# 前端培训资料 - 公众号 ## 前期准备 1.node 环境配置在 12 及以上,可以使用 nvm 进行 node 环境管理 2.下载微信开发者工具 3.同步项目仓库 ## 启动 1.命令行运行 `npm install` 或 `yarn` 安装依赖 2.运行 `npm run start` 或 `yarn start` 启动项目 3.微信开发者工具打开启动项目后的链接,即可预览项目 ## 上传 开发完成之后,同步代码到远程仓库,Jenkins 上面手动点击构建,即可发布新版本 太和公众号: - QA 环境 [Jenkins](https://jenkins.ywtinfo.com/view/qa/job/qa-fe-nfthwe/) - 生产环境 [Jenkins](https://jenkins.ywtinfo.com/view/product/job/product-fe-nfthwe-%E5%A4%AA%E5%92%8C%E5%85%AC%E4%BC%97%E5%8F%B7/) 南方医务通公众号: - QA 环境 [Jenkins](https://jenkins.ywtinfo.com/view/qa/job/qa-fe-nfywtwe/) - 生产环境 [Jenkins](https://jenkins.ywtinfo.com/view/product/job/product-fe-nfywtwe%E5%8D%97%E6%96%B9%E5%8C%BB%E5%8A%A1%E9%80%9A/) ### 项目结构 ```javascript . ├── .babelrc // babel配置 ├── .editorconfig // 编辑器配置 ├── .eslintignore ├── .eslintrc.js // eslint配置 ├── .gitignore ├── .gitmodules // git submodule配置 ├── .postcssrc.js ├── .prettierrc ├── README.md ├── build // 构建配置目录 │ ├── build-qa.js // qa环境变量配置 │ ├── build.js // prod环境变量配置 │ ├── check-versions.js │ ├── dev-client.js │ ├── dev-server.js // dev环境express启动 │ ├── mock.js // mock数据 │ ├── utils.js // 样式相关构建工具库 │ ├── webpack.base.conf.js // webpack基本构建配置 │ ├── webpack.dev.conf.js // webpack dev环境构建配置 │ ├── webpack.prod.conf.js // webpack prod环境构建配置 │ └── webpack.qa.conf.js // webpack qa环境构建配置 ├── config │ ├── dev.env.js // mobile端项目配置 │ ├── index.js // 项目配置汇总 │ ├── prod.env.js // mobile端prod项目配置 │ ├── qa.env.js // mobile端qa项目配置 │ └── test.env.js // 测试项目配置 ├── dist ├── index.ejs // html模板 ├── node_modules ├── package-lock.json ├── package.json ├── src │ ├── assets // 项目资源 │ ├── components // 公共封装组件 | │ ├── Agreement // 文本公告弹窗 | │ ├── AlertTitle // 提示标语 | │ ├── App // APP总容器 | │ ├── ChatItem // 咨询聊天组件 | │ ├── DoctorInfoItem // 医生信息 | │ ├── FilterModal // 信息过滤组件 | │ ├── GHNotice // 富文本公告弹窗 | │ ├── HomePages // 首页公告 | │ ├── HospitalInfoItem // 医院信息 | │ ├── MySegmentedControl // 列表展示 | │ ├── MySwitch // switch组件 │ | └── SexSelect // 性别选择组件 │ ├── const // 常量配置 │ ├── containers // 不同业务页面 | │ ├── App // 项目入口/首页 | │ ├── CheckResult // 检验检查模块 | │ ├── Consult // 咨询模块 | │ ├── DoctorTeam // 医生团队模块 | │ ├── DrugNews // 快讯模块 | │ ├── Fl_up // 随访模块 | │ ├── Global // 医生信息 | │ ├── Guide // 引导模块 | │ ├── Home | │ ├── Me // 个人中心 | │ ├── MedicalRecord // 诊疗卡中心 | │ ├── NoMatch // 404页面 | │ ├── OnlineOrder // 线上订单 | │ ├── OrderCenter // 订单中心 | │ ├── Pay // 支付页面 | │ ├── PrivateDoctor // 专职医生介绍页面 | │ ├── Report // 远程会诊专家报告 | │ ├── Tools // 签名模块 | │ ├── YuYueGuaHao // 预约挂号-南方医科大学南方医院 │ | └── YuYueGuaHao-TaiHe // 预约挂号-太和 │ ├── entry.js // 项目入口 │ ├── hoc // 高阶函数 │ ├── reducers // redux-reducer │ ├── routers // 路由配置 │ ├── saga // redux-saga │ ├── server // 接口相关api │ ├── ui_module_components // git submodule │ └── utils // 工具类 └── static // 静态文件夹 ├── .gitkeep ├── images └── pdfjs-dist ``` ### 生命周期 react 所有生命周期都适用,项目中最常用的有以下两种: ```js class App extends Component { state = { name: "", }; // 可以使用所有的 React 生命周期方法,一般在此阶段请求接口获取数据 componentDidMount() { this.setState({ name: "xxx", }); } // 页面状态或者变量更新时的生命周期 componentDidUpdate() {} render() { return
; } } ``` --- ### 全局状态管理 公众号使用 redux 相关套件进行全局状态管理 以获取/修改用户信息为例: #### 设置 reduce 和 state 在 `src/reduce/user.js` 中,创建 reduce,用于同步更改 state ```js import { combineReducers } from "redux"; const initState = { name: "", }; function userInfo(state = initState, action) { switch (action.type) { case "SAVE": return Object.assign({}, state, action.info.user); default: return state; } } export default combineReducers({ userInfo, }); ``` #### 设置 action 在 `src/saga/user.js` 文件中,我们将创建一个 Saga 来监听所有的 INIT action,并触发一个 API 调用获取用户数据: ```js import { call, put, takeEvery, takeLatest } from "redux-saga/effects"; import Api from "..."; // worker Saga : 将在 INIT action 被 dispatch 时调用 function* fetchUser(action) { const user = yield call(Api.fetchUser); yield put({ type: "SAVE", info: { user } }); } /* 在每个 `INIT` action 被 dispatch 时调用 fetchUser 允许并发(译注:即同时处理多个相同的 action) */ function* mySaga() { yield takeEvery("INIT", fetchUser); } /* 也可以使用 takeLatest 不允许并发,dispatch 一个 `INIT` action 时, 如果在这之前已经有一个 `INIT` action 在处理中, 那么处理中的 action 会被取消,只会执行当前的 */ function* mySaga() { yield takeLatest("INIT", fetchUser); } export default mySaga; ``` #### 连接 Redux Store 为了能跑起 Saga,我们需要使用 redux-saga 中间件将 Saga 与 Redux Store 建立连接。 在项目的入口文件 `src/entry.js` 中建立连接: ```js import { createStore, applyMiddleware } from "redux"; import createSagaMiddleware from "redux-saga"; import mySaga from "./sagas/user.js"; import reducer from "./reduce/user.js"; // create the saga middleware const sagaMiddleware = createSagaMiddleware(); // mount it on the Store const store = createStore(reducer, applyMiddleware(sagaMiddleware)); // then run the saga sagaMiddleware.run(mySaga); ``` #### 页面或者组件接入 ```js import React, { Component } from "react"; import { withRouter } from "react-router-dom"; import { connect } from "react-redux"; class App extends Component { state = { nickName: "", }; componentDidMount() { this.props.onInitUserInfo(); // 调用 props 中的方法获取全局数据 this.getNickName(); // 直接调用接口获取数据 } async getNickName() { const result = await getNickNameApi(); this.setState({ nickName: result.nickName, }); } render() { const { userInfo } = this.props; // 从 props 中获取数据 return (
this.props.onChangeUserInfo({ name: "xxx" })}> {userInfo.name}
); } } const mapStateToProps = (state) => { // 设置所要监听/获取的数据 return { userInfo: state.userInfo, }; }; const mapDispatchToProps = (dispatch) => { // 设置函数,触发 dispatch,获取/修改用户数据 return { onInitUserInfo() { // 初始化数据 dispatch({ type: "INIT" }); }, onChangeUserInfo(user) { // 修改数据 dispatch({ type: "SAVE", info: user, }); }, }; }; // 通过 redux 提供的 connect 方法,给 APP 组件的 props 中连接所需要的属性和方法 export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App)); ```