|
@@ -0,0 +1,292 @@
|
|
|
+# 前端培训资料 - 公众号
|
|
|
+
|
|
|
+## 前期准备
|
|
|
+
|
|
|
+1.node 环境配置在 14 及以上,可以使用 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 {
|
|
|
+ // 可以使用所有的 React 生命周期方法,一般在此阶段请求接口获取数据
|
|
|
+ componentDidMount() {}
|
|
|
+
|
|
|
+ // 页面状态或者变量更新时的生命周期
|
|
|
+ componentDidUpdate() {}
|
|
|
+
|
|
|
+ render() {
|
|
|
+ return <div></div>;
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 全局状态管理
|
|
|
+
|
|
|
+公众号使用 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 (
|
|
|
+ <div onClick={() => this.props.onChangeUserInfo({ name: "xxx" })}>
|
|
|
+ {userInfo.name}
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+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));
|
|
|
+```
|