一丶 安装

通过 npm 安装 dva-cli 并确保版本是0.8.1或以上。

  1. $ npm install dva-cli -g
  2. $ dva -v
  3. 0.8.1

二丶创建新应用

安装完dva-cli之后,就可以在命令行里访问到dva命令(不能访问?)。现在,你可以通过dva new创建新应用。

  1. $ dva new dva-quickstart
  2. $ npm start

之后浏览器就会打开 http://localhost:8000,你会看到dva的欢迎界面。

三丶使用antd组件库

通过 npm 安装 antd 和 babel-plugin-import。babel-plugin-import 是用来按需加载 antd 的脚本和样式的

  1. $ npm install antd babel-plugin-import --save

编辑.roadhogrc,使 babel-plugin-import 插件生效。

  1. "extraBabelPlugins": [
  2. - "transform-runtime"
  3. + "transform-runtime",
  4. + ["import", { "libraryName": "antd", "style": "css" }]
  5. ],

注:dva-cli 基于 roadhog 实现 build 和 server,更多.roadhogrc的配置详见 roadhog#配置

四丶准备工作以及文件之间的对应关系

首先在创建文件之前(一般安装的时候系统会自动生成一个默认的services文件下 Example.js 和 model文件下 example.js,两者都是一一对应)

react项目的推荐目录结构(如果使用dva脚手架创建,则自动生成如下)

  1. |── /mock/ # 数据mock的接口文件
  2. |── /src/ # 项目源码目录(我们开发的主要工作区域)
  3. | |── /components/ # 项目组件(用于路由组件内引用的可复用组件)
  4. | |── /routes/ # 路由组件(页面维度)
  5. | | |── route1.js
  6. | | |── route2.js # 根据router.js中的映射,在不同的url下,挂载不同的路由组件
  7. | | └── route3.js
  8. | |── /models/ # 数据模型(可以理解为store,用于存储数据与方法)
  9. | | |── model1.js
  10. | | |── model2.js # 选择分离为多个model模型,是根据业务实体进行划分
  11. | | └── model3.js
  12. | |── /services/ # 数据接口(处理前台页面的ajax请求,转发到后台)
  13. | |── /utils/ # 工具函数(工具库,存储通用函数与配置参数)
  14. | |── router.js # 路由配置(定义路由与对应的路由组件)
  15. | |── index.js # 入口文件
  16. | |── index.less
  17. | └── index.html
  18. |── package.json # 项目信息
  19. └── proxy.config.js # 数据mock配置

五丶创建接口文件products.js

  1. 在services文件下创建products.js, .yield call方法里面的usersService.fetch方法如下(PAGESIZE目前是常量) products.js代码如下:
  1. import request from 'requesturl';
  2. // 新闻轮播图显示
  3. export function NewsCarousel(start, limit ){
  4. const body = JSON.stringify({ start: 0, limit: 1000 });
  5. return request("menu/query", {
  6. method: "POST", body,
  7. headers: {'Content-Type': 'application/json'}
  8. });
  9. }
  10. //新闻列表
  11. export function NewsList(start, limit, type){
  12. const body = JSON.stringify({ start, limit, type});
  13. return request("new/query", {
  14. method: "POST", body,
  15. headers: {'Content-Type': 'application/json'}
  16. });
  17. }
  1. 然后在models中创建对应的products.js, 因为services下的products.js 和models下的products.js 两者是react 调入接口和接收接口参数 密不可分的文件。
  1. import * as services from '../services/products';
  2. export default {
  3. namespace: 'products',
  4. state: {
  5. newinfo: [],
  6. newdetail: []
  7. },
  8. reducers: {
  9. update(state, action) {
  10. return { ...state, ...action.payload };
  11. },
  12. },
  13. effects: {
  14. * NewsInfo({ payload},{ call, put }){
  15. const list = yield call(services.NewsCarousel);
  16. let menu= [], arr = list.data.data;
  17. arr.forEach(items => {menu.push({ title: items.Text, id: items.Id }) });
  18. yield put({ type: "update", payload: { newinfo: menu }});
  19. },
  20. * NewsDetail({ payload:{start, limit, type}}, { call, put }){
  21. const detail = yield call(services.NewsList, start, limit, type);
  22. yield put({ type: "update", payload: { newdetail: detail.data.data}});
  23. }
  24. },
  25. subscriptions: {
  26. setup({ dispatch, history }) {
  27. return history.listen(({ pathname, query }) => {
  28. if(pathname === "/"){
  29. dispatch({ type: 'NewsInfo'});
  30. dispatch({ type: 'NewsDetail', payload:{
  31. start: 0,
  32. limit: 1000,
  33. type: "7ad2c8db-ff04-4736-81c9-1b7c6fb276b3"
  34. }});
  35. }
  36. })
  37. },
  38. },
  39. };

六丶在components文件下ListPage文件夹下

NewsCarousel.js

  1. import React from 'react';
  2. import { connect } from 'dva';
  3. import styles from './styles.less';
  4. import { Carousel } from 'antd-mobile';
  5. const NewsCarousel = ({ dispatch, newdetail, ...rest }) =>{
  6. return(
  7. <Carousel
  8. autoplay={false}
  9. infinite
  10. selectedIndex={0}
  11. swipeSpeed={35}>
  12. {newdetail && newdetail.length!== 0?
  13. newdetail.map(val =>(
  14. <a
  15. key={val.Id}
  16. href={val.Link}
  17. className={styles.banner}>
  18. <img
  19. style={{
  20. width: '100%',
  21. height: '180px'
  22. }}
  23. src={val.Img}
  24. alt=""/>
  25. <p className={styles.title}>
  26. {val.Title}
  27. </p>
  28. </a>
  29. )): ""}
  30. </Carousel>
  31. )
  32. }
  33. export default connect(({ products }) => ({ ...products }))(NewsCarousel);

NewsCrad.js

  1. import React from 'react';
  2. import { connect } from 'dva';
  3. import styles from './styles.less';
  4. import { Tabs, WhiteSpace, Card, WingBlank } from 'antd-mobile';
  5. const DTabBar = Tabs.DefaultTabBar;
  6. const NewsCrad = ({ dispatch, newinfo, newdetail, ...rest }) =>{
  7. const changeKey = (key) =>{
  8. dispatch({
  9. type: 'products/NewsDetail',
  10. payload:{ type: key.id, start: 0, limit: 1000 }
  11. })
  12. }
  13. const renderContent = (tab, i) => {
  14. return(
  15. <div>
  16. {newdetail && newdetail.length!== 0?
  17. newdetail.map((val, i) =>
  18. <WingBlank size="sm" key={i}>
  19. <WhiteSpace/>
  20. <a href={val.Link}>
  21. <Card>
  22. <Card.Body>
  23. <img src={val.Img} className={styles.cover} alt=""/>
  24. <div className={styles.adde}>{val.Title}</div>
  25. <p className={styles.pade}>{val.Memo}</p>
  26. </Card.Body>
  27. </Card>
  28. </a>
  29. </WingBlank>
  30. ): ""}
  31. </div>
  32. )
  33. }
  34. return(
  35. <Tabs
  36. tabs={newinfo}
  37. onChange={changeKey}
  38. renderTabBar={props => <DTabBar { ...props } />}>
  39. {renderContent}
  40. </Tabs>
  41. )
  42. }
  43. export default connect(({ products }) => ({ ...products }))(NewsCrad);

七丶在 routes文件下 ListView.js进行数据渲染

  1. import React from 'react';
  2. import { NewsCarousel, NewsCrad } from 'components';
  3. export default function ListView(){
  4. return (
  5. <div>
  6. <NewsCarousel/>
  7. <NewsCrad/>
  8. </div>
  9. );
  10. }

码云地址: https://gitee.com/github-29425276/NewsPush.git
简书原文: https://www.jianshu.com/p/55702d52593b
更新日期: 2017.10.23 16:56