PC管理端架构
技术构成:
1)基础框架React ----性能优越、稳定可靠
虚拟DOM技术,网页在内存拼接,一次批量快速渲染
2)UI组件库Ant Design ----成熟、丰富、稳定的React UI组件库
文档说明清晰,使用人数多,常用UI组件多,界面美观,可定制性高
3)数据状态管理Dva
跨组件数据状态共享,避免复杂的数据传递,任一组件可以随意获取另一组件数据
4)打包工具WebPack
可以使用现金的ES6/ES7/ReactJSX语法
可以使用样式缩略语法less
代码分割、合并、压缩
工程脚手架——根目录
.gitignore --git忽略文件夹
.happypack --WebPack多进程打包插件
dist --最终打包生成的html+css+js
node_modules --node.js依赖包目录
src --开源目录
package-lock.json --node.js锁定包版本文件
package.json --node.js包管理记录文件
README.md --工程说明文档
webpack.config.js --webpack配置文件
webpack.dll.config.js --Webpack Dll配置文件
工程脚手架——src目录
assets --静态资源目录(样式、图片、字体、json)
config --站点配置文件
css --站点全局样式
pages --业务页面目录
pubBiz --业务组件(构件)目录
utils --公共工具类
widget --基础组件目录
favicon.ico --站点地址栏图标
index.html --单页面模板
index.js --入口程序
router.js --路由配置
theme.js --主题设置
工程脚手架 - 业务页面
xxxServ.js 接口服务层 对应RESTFull接口的访问路径
xxxMod.js 业务处理层 接口请求、数据状态处理
xxxView.jsx 视图展示层 描述UI长什么样子、按钮点击响应处理
xxxStyle.less 页面的样式 UI元素的样子
安装yx-npm命令行(CLI)工具
外网安装
1. 需要先登录私有npm仓库
npm login --registry https://npm.dtyunxi.cn
提示:安装过程提示输入的用户名、密码、邮箱由云徙提供
2. 继续安装yx-npm
npm install yx-npm -g --registry https://npm.dtyunxi.cn
2. 执行初始化命令(会提示输入项目名name、端口号port)
yx-npm make mgmt
3. 安装包依赖(进入项目根目录)
npm install
4. 启动项目
npm run dev
5. 浏览器访问(port为步骤2的端口号,登录用户名、密码、图形验证码随便填点击登录进去)
http://localhost:port
编写雇员CRUD
编写雇员列表
yx-npm list -e employee -z 雇员
提示:
-e 为所要生成模块的英文名
-z 为所要生成模块的中文名
编写雇员编辑页
yx-npm edit -e employee -z 雇员
编写雇员详情页
yx-npm detail -e employee -z 雇员
提示:以上命令会在当前目录生成一个dest目录,子文件夹为一个完整的模块
cfgMenu.js为生成的菜单配置内容,可拷贝对应内容到config/menu.js中,注意修改value的值cfgRouter.js为生成的路由配置内容,可拷贝对应内容到src/router.js中其余的文件拷贝到biz目录下对应的文件夹,然后根据需要修改文件依赖路径
框架数据流驱动走向
重点介绍3层,
1)xxxServ.js 接口服务层
export function doit (body) {
return request({
method: "post",
url: `${wechatApi}/doit`,
data: JSON.stringify(body),
})
}
这里是请求后台接口的方法,其中这里的request是封装了axios的函数,所以他返回的是一个promise对象,URL就是要请求的地址,body就是请求参数了
request剖析如下:
import axios from "axios"
export default async function request(options) {
let response
try {
response = await axios(options);
return response
} catch(err) {
return response
}
}
2)xxxMod.js 业务处理层
export default {
namespace: "test", //命名空间名字,必填
state:{num: 0}, //state就是用来放初始值的
//能改变界面的action,这里不能做数据处理,只能用来return state从而改变界面
reducers: {
addNum( //addNum可以理解为一个方法名
//此处的state就是上面出事的state,这里理解是旧state
state, { payload: { num }} //num是传过来的,名字可任意起,不是state中的num,这接受一个action
){
//return新的state,这样页面就会更新,吧num:num重新赋值,这样后面赋值的num就会覆盖前面的。
return {...state, num}
},
},
//ES6新语法,与后台交互,处理数据逻辑的地方,实现异步处理
effects: {
*fetchNum({ payload2 }, {call, put, select }) {
//fetchNum方法名,payload2是传来的参数,是个对象,如果没参数可以写成{_,{call,put,select}}
const { data } = yield call(myService.diot, {anum:payload2.numCount})
//myService是引入service层的文件名,diot是对应的接口函数名,anum是后台要求传的参数, data就是后台返回来的数据
const m = yield select((state) => state.test.num) //select就是用来选择上面state里的,这里没用上
yield put({
//这就是reducer中addNum方法,put用来出发reducer中的方法,payload就是传过去的参数。同时也能触发等级effects里的其他方法
type: "addNum",
payload: {
num: data, //把后台返回的数据赋值给num, 如果方法是来自reducer则必须同名
},
})
},
*fetchUser(_,{call, put}) {
//....
},
subscriptions: {
//订阅监听,如若监听路由,则是页面的入口点
setup ({ dispatch, history, query }) {
return history.listen(async ({ pathname, search, query}) => {
if(pathname === '/testdemo') {
//进入testdemo时,就会触发fetchUser方法
dispatch({ type: "fetchUser" })
}
})
}
}
}
},
xxxView.jsx 视图展示层
clickHandler = () => {
dispatch({
type: "test/fetchNum",
//这里就会触发mod层effect里的方法(也可以直接触发reducer中方法)
//test就是mod命名空间名字
payload:{
numCount: ++1,
},
})
}
总结数据趋向走向流程:
点击页面按钮 -> 触发clickHandler -> 触发mod层effect的fetchNum -> 触发serv层doit,获取后台返回数据
-> 触发mod层的addNum,返回数据更新mod层的state -> components应用mod层中的state的num
-> 触发页面render方法重新渲染 -> 界面更新
render方法什么时候会触发
当state或props变化时就会触发render,我们一般在render里只获取 props 和 state,尽量不做逻辑处理 (数据逻辑处理基本在render上面的函数或者models中处理)。当父组件给子组件传递props时,子组件那个props最好不要在render里面做逻辑计算赋值,不然传递过去,子组件有可能拿不到最新的值。比如传了个数组arr,arr在render里做了数据处理,赋值,render会运行多次(这里举例3次)所以结果可能是 [1,2,3] [1,2,3] [1,2],子组件拿到的值是[1,2,3]而不是最终的[1,2],所以当你出现子组件无法获取父组件传递过来最后正确的值,看看是不是值在render做了运算赋值,解决方法就是把数据逻辑放在models层处理,然后再返回,这样就没问题了。
页面要应用mod层的数据要用connect
import { Compoent } from 'react'
import { connect } from 'dva'
class TheDemo extends Compoent {
clickHandler = () => {xxxx}
render() {
const {num} = this.props //获取下面的num
return (
<div>
<button onClick = {this.clickHandler}</button>
<p>{num}</p>
</div>
)
}
}
//字面意思就是把mud的state变成组件的props
function mapStateToProps(state) {
const { num } = state.test //test就是mod命名空间名字
return {
num, //在这return,上面才能获取到
}
}
export default connect(mapStateToProps) (TheDemo)