一丶 安装
通过 npm 安装 dva-cli 并确保版本是0.8.1或以上。
$ npm install dva-cli -g
$ dva -v
0.8.1
二丶创建新应用
安装完dva-cli之后,就可以在命令行里访问到dva命令(不能访问?)。现在,你可以通过dva new创建新应用。
$ dva new dva-quickstart
$ npm start
之后浏览器就会打开 http://localhost:8000,你会看到dva的欢迎界面。
三丶使用antd组件库
通过 npm 安装 antd 和 babel-plugin-import。babel-plugin-import 是用来按需加载 antd 的脚本和样式的
$ npm install antd babel-plugin-import --save
编辑.roadhogrc,使 babel-plugin-import 插件生效。
"extraBabelPlugins": [
- "transform-runtime"
+ "transform-runtime",
+ ["import", { "libraryName": "antd", "style": "css" }]
],
注:dva-cli 基于 roadhog 实现 build 和 server,更多.roadhogrc的配置详见 roadhog#配置
四丶准备工作以及文件之间的对应关系
首先在创建文件之前(一般安装的时候系统会自动生成一个默认的services文件下 Example.js 和 model文件下 example.js,两者都是一一对应)
react项目的推荐目录结构(如果使用dva脚手架创建,则自动生成如下)
|── /mock/ # 数据mock的接口文件
|── /src/ # 项目源码目录(我们开发的主要工作区域)
| |── /components/ # 项目组件(用于路由组件内引用的可复用组件)
| |── /routes/ # 路由组件(页面维度)
| | |── route1.js
| | |── route2.js # 根据router.js中的映射,在不同的url下,挂载不同的路由组件
| | └── route3.js
| |── /models/ # 数据模型(可以理解为store,用于存储数据与方法)
| | |── model1.js
| | |── model2.js # 选择分离为多个model模型,是根据业务实体进行划分
| | └── model3.js
| |── /services/ # 数据接口(处理前台页面的ajax请求,转发到后台)
| |── /utils/ # 工具函数(工具库,存储通用函数与配置参数)
| |── router.js # 路由配置(定义路由与对应的路由组件)
| |── index.js # 入口文件
| |── index.less
| └── index.html
|── package.json # 项目信息
└── proxy.config.js # 数据mock配置
五丶创建接口文件products.js
- 在services文件下创建products.js, .yield call方法里面的usersService.fetch方法如下(PAGESIZE目前是常量) products.js代码如下:
import request from 'requesturl';
// 新闻轮播图显示
export function NewsCarousel(start, limit ){
const body = JSON.stringify({ start: 0, limit: 1000 });
return request("menu/query", {
method: "POST", body,
headers: {'Content-Type': 'application/json'}
});
}
//新闻列表
export function NewsList(start, limit, type){
const body = JSON.stringify({ start, limit, type});
return request("new/query", {
method: "POST", body,
headers: {'Content-Type': 'application/json'}
});
}
- 然后在models中创建对应的products.js, 因为services下的products.js 和models下的products.js 两者是react 调入接口和接收接口参数 密不可分的文件。
import * as services from '../services/products';
export default {
namespace: 'products',
state: {
newinfo: [],
newdetail: []
},
reducers: {
update(state, action) {
return { ...state, ...action.payload };
},
},
effects: {
* NewsInfo({ payload},{ call, put }){
const list = yield call(services.NewsCarousel);
let menu= [], arr = list.data.data;
arr.forEach(items => {menu.push({ title: items.Text, id: items.Id }) });
yield put({ type: "update", payload: { newinfo: menu }});
},
* NewsDetail({ payload:{start, limit, type}}, { call, put }){
const detail = yield call(services.NewsList, start, limit, type);
yield put({ type: "update", payload: { newdetail: detail.data.data}});
}
},
subscriptions: {
setup({ dispatch, history }) {
return history.listen(({ pathname, query }) => {
if(pathname === "/"){
dispatch({ type: 'NewsInfo'});
dispatch({ type: 'NewsDetail', payload:{
start: 0,
limit: 1000,
type: "7ad2c8db-ff04-4736-81c9-1b7c6fb276b3"
}});
}
})
},
},
};
六丶在components文件下ListPage文件夹下
NewsCarousel.js
import React from 'react';
import { connect } from 'dva';
import styles from './styles.less';
import { Carousel } from 'antd-mobile';
const NewsCarousel = ({ dispatch, newdetail, ...rest }) =>{
return(
<Carousel
autoplay={false}
infinite
selectedIndex={0}
swipeSpeed={35}>
{newdetail && newdetail.length!== 0?
newdetail.map(val =>(
<a
key={val.Id}
href={val.Link}
className={styles.banner}>
<img
style={{
width: '100%',
height: '180px'
}}
src={val.Img}
alt=""/>
<p className={styles.title}>
{val.Title}
</p>
</a>
)): ""}
</Carousel>
)
}
export default connect(({ products }) => ({ ...products }))(NewsCarousel);
NewsCrad.js
import React from 'react';
import { connect } from 'dva';
import styles from './styles.less';
import { Tabs, WhiteSpace, Card, WingBlank } from 'antd-mobile';
const DTabBar = Tabs.DefaultTabBar;
const NewsCrad = ({ dispatch, newinfo, newdetail, ...rest }) =>{
const changeKey = (key) =>{
dispatch({
type: 'products/NewsDetail',
payload:{ type: key.id, start: 0, limit: 1000 }
})
}
const renderContent = (tab, i) => {
return(
<div>
{newdetail && newdetail.length!== 0?
newdetail.map((val, i) =>
<WingBlank size="sm" key={i}>
<WhiteSpace/>
<a href={val.Link}>
<Card>
<Card.Body>
<img src={val.Img} className={styles.cover} alt=""/>
<div className={styles.adde}>{val.Title}</div>
<p className={styles.pade}>{val.Memo}</p>
</Card.Body>
</Card>
</a>
</WingBlank>
): ""}
</div>
)
}
return(
<Tabs
tabs={newinfo}
onChange={changeKey}
renderTabBar={props => <DTabBar { ...props } />}>
{renderContent}
</Tabs>
)
}
export default connect(({ products }) => ({ ...products }))(NewsCrad);
七丶在 routes文件下 ListView.js进行数据渲染
import React from 'react';
import { NewsCarousel, NewsCrad } from 'components';
export default function ListView(){
return (
<div>
<NewsCarousel/>
<NewsCrad/>
</div>
);
}
码云地址: newspush