1.模板管理
1.1 yeoman-environment插件
基于yeoman-generator 、yeoman-environment插件,将各类基础模板(vant、antdV、element、eapp)等做成基础模版,并可将该模版上传至npm进行管理。
参考链接:https://www.npmjs.com/package/generator-yo-template
2.模板生成
2.1 平台创建项目(前置条件--未完成)
通过平台,录入项目信息,通过接口在git创建对应的git项目,并初始化生成init.js文件
2.2创建模版
执行指令
node init.js
2.3自动生成模板
3.模板介绍(antdV 版本)
3.1目录结构
├─assets # 静态资源
│ └─img
├─components # 组件库
│ └─global # 全局组件 <放入后不需要注册也不需要引入>
├─decorator # 装饰器
├─filter # 过滤器
├─http # 网络请求
├─layouts # layout文件
├─plugins # 插件库 如需要引入第三方组件等 <推荐使用cdn>
├─router # 路由
├─store # vuex
│ └─modules # vuex 模块
├─style # 样式
│ ├─css # css 文件
│ └─auto.css # css 生成器自动生成(css-generator-plugin)
├─utils # 工具库目录
└─views # 页面文件
└─login # 登陆逻辑处理
3.2 components组件库
存放组件库的目录。
components/global目录,主要存放全局通用组件,如loading,button,modal等
PS:其中globalcomponent.js会将该目录下所有.vue文件自动注册挂载到Vue上
3.3 decorator装饰器
3.3.1什么是装饰器
Decorator 是 ES7 的一个新语法,正如其“装饰器”的叫法所表达的,他可以对一些对象进行装饰包装然后返回一个 被包装过的对象,可以装饰的对象包括:类,属性,方法等
3.3.2为什么使用装饰器
适合用来做基础库的语法糖,用来简化上层代码 - 对重复工作量大的业务进行修饰,方便维护且代码简洁
3.3.2装饰器的原理是什么
Object.defineProperty()
3.3.4 如何使用装饰器
<div @click="deleteConfirm">删除</div>
//未使用装饰器的做法
methods: {
deleteConfirm () {
this.$confirm({
title: '确认删除该条信息吗',
okText: '确认',
cancelText: '取消',
onOk () {
this.deleteApi()
}
})
},
async deleteApi () {
await this.$apis.deleteConfirm()
}
}
//使用装饰器的做法
methods: {
@confirm('确认删除该条信息吗')
async deleteApi () {
await this.$apis.deleteConfirm()
}
}
3.3.5 如何实现装饰器
decorator/index.js
/**
* 提示装饰器
* @param {String | Object} message 需要提示用户的信息 或者 confirm 的配置
* @param {Function} errorFn 请求异常的回调 返回this 使用function 则为你绑定
*/
export function confirm (message, errorFn) {
const defaultConf = {
// primary ghost dashed danger link
okType: 'danger',
maskClosable: false
}
return function (target, name, descriptor) {
const oldFn = descriptor.value
descriptor.value = function (...args) {
Modal.confirm(Object.assign(
defaultConf,
isString(message) ? { title: message } : message, // if use string then create Object else use Object to assign
{
onOk: () => oldFn.apply(this, args),
onCancel: () => {
// 无论如何都提示
globalWarn(`用户点击了取消:${name}`)
if (errorFn) {
errorFn.call(this, this)
}
}
}
))
}
}
}
3.3.6 装饰器适合哪些需求
目前团队内已使用的场景主要为:confirm,loading,log,debounceFn,throttleFn
3.4 dicts字典
// 默认提供的方法
/**
* 字典
* @example
// 根据字典名,获取list(多用于下拉框),如[{key:1,name:'类型1'},{key:2,name:'类型2'}]
* dict.getDictList('user')
// 根据字典名,获取对象,如{ 1: '内置类型1', 2: '内置类型2' }
* dict.getDictObj('user')
// 根据字典名和key,获取value
* dict.getDictItem('user',2))
*/
// 字典对象
const dicts = {
taskType: { 1: '内置类型1', 2: '内置类型2' }
}
3.5 filter过滤器
不改变原始数据的前提下,修改数据的展现形式
import Vue from 'vue'
/* 格式化金额 */
export const moneyFormat = (money) => {
return money ? `${(money / 100).toFixed(2)}` : ''
}
Vue.filter('moneyFormat', moneyFormat)
// html
<span>{{data.money | moneyFormat}}</span>
3.6 http
3.6.1 拦截器封装
// 请求头处理
// 1.一般为token、header等请求头统一处理
http.interceptors.request.use(
config => {
const token = session.getSession('token')
if (token) config.headers.token = token.replace(/"/g, '')
return config
},
error => {
throw new Error(JSON.stringify(error))
}
)
// 响应头处理
// 1.正常接口等统一处理
// 2.登陆权限拦截统一处理
// 3.指定错误逻辑统一处理
// 4.其他错误的统一处理
http.interceptors.response.use(
response => {
const res = response.data
if (!res.success) { // 逻辑错误 自定义错误码
if (res.errorMsg) {
ErrorMessage(res.errorMsg)
}
globalError('接口调用失败')
switch (res.errorCode) {
case 401:
case 403:
case 405:
case '-3':
session.destroy('token')
router.push({ name: 'login', query: { from: window.this.$route.name, params: window.this.$route.query } })
break
default:
break
}
throw new Error(JSON.stringify(res))
}
return res.result
},
error => {
// http error
globalError(new Date(), 'err' + error) // for debug reject
ErrorMessage(ERROR_MSG[error?.response?.status] || `连接出错(${error.response.status})!`) // 消抖
throw new Error(JSON.stringify(error))
}
)
3.6.2 get、post等方式封装
ps:通过高阶函数封装,api.js内不需要维护入参
// get 方法 也调用一次 toJSON
export const get = url => {
return (params = {}) => {
return new Promise((resolve, reject) => {
http.get(url, { params: JSONClone(params), paramsSerializer: x => Qs.stringify(x, { arrayFormat: 'repeat' }) })
.then(resolve)
.catch(reject)
})
}
}
// post JSON 默认调用 toJSON
export const post = url => {
return (data = {}) => {
return new Promise((resolve, reject) => {
http.post(url, data)
.then(resolve)
.catch(reject)
})
}
}
// post 表单 手动 toJSON
export const form = url => {
return (data = {}) => {
return new Promise((resolve, reject) => {
// 达到和直接post json 一样的效果 先调用 toJSON
http.post(url, Qs.stringify(JSONClone(data), { arrayFormat: 'repeat' }))
.then(resolve)
.catch(reject)
})
}
}
// temp post 但是拼接URL 临时使用
export const temp = url => {
return (params = {}) => {
return new Promise((resolve, reject) => {
http.post(url, {}, { params })
.then(resolve)
.catch(reject)
})
}
}
3.6.3 apis.js统一管理
// apis.js
import {
get,
post,
binary, // post 上传文件 (二进制文件)
form, // post 表单
temp, // 临时post 拼接URL
put, // 上传文件
download // 下载文件
} from '@/http/request'
export default {
/* demo -- start */
// 调用方式1(推荐使用) this.$apis.demoGet({id: 1, sex: 2})
demoGet: get('/isDemo/getApi'),
demoPost: post('isDemo/postApi'),
demoBinary: binary('isDemo/binaryApi'),
demoForm: form('isDemo/formApi'),
demoTemp: temp('isDemo/tempApi'),
demoPut: put('isDemo/tempApi'),
demoDownload: download('isDemo/tempApi')
/* demo -- end */
}
// main.js
Vue.prototype.$apis = apis
3.7 layouts布局管理和router路由管理
设立思路:将布局和页面逻辑进行解耦。由page控制页面逻辑,layout控制布局类型
3.7.1 managerLayout
管理平台布局,可用于嵌套各类管理平台页面
3.7.2 baseLayout
基础布局,可用于登陆、无权限、临时性的移动端页面等
PS:如管理平台某个详情页 通过OA推送后,希望用户可以在钉钉侧边栏打开看到详情页面
3.7.3 router.js
// router.js
{ // base 下没有任何 外部layout
path: '/base',
name: 'base',
redirect: { name: 'base_home' },
component: baseLayout,
children: [
{
path: 'depDetailCharts',
name: 'base_depDetailCharts',
component: () => import('@/pages/depDetailCharts'),
meta: { title: '三级部门日志图表', breadcrumb: [{ name: 'base_home', title: '日志统计' }, { name: 'base_depLogCharts', title: '部门日志图表' }] }
}
]
},
{ // manager 下 有默认layout
path: '/manager',
name: 'manager',
redirect: { name: 'manager_home' },
component: managerLayout,
children: [
{
path: 'depDetailCharts',
name: 'manager_depDetailCharts',
component: () => import('@/pages/depDetailCharts'),
meta: { title: '三级部门日志图表', breadcrumb: [{ name: 'manager_home', title: '日志统计' }, { name: 'manager_depLogCharts', title: '部门日志图表' }] }
}
]
}
// 不同layout的页面间交互跳转
// 通过this.$route.matched[0].name 获取当前layout类型
this.$router.push({ name: `${this.$route.matched[0].name}_depDetailCharts`, query: { }})
3.8 pages
尽量login.vue来管理登陆,并推荐做一个模拟登陆
3.9 store
vuex管理
3.10 style
3.10.1 css-generator-plugin
通过正则匹配所有.vue文件,根据固有规则的class,自动生成样式代码
参考链接:https://www.npmjs.com/package/css-generator-plugin
4. webpack配置(模板优化)
4.1 将静态资源通过CDN引入的形式(css固定CDN引入,js仅打包时通过CDN引入(本地照常))
参考链接:https://www.npmjs.com/package/import-assets-from-cdn
4.1.1使用方式
4.1.2 实际效果
4.2 配置打包版本/环境/时间(控制台打印)
4.2.1 使用方式
参考链接:https://www.npmjs.com/package/log-info-webpack-plugin
4.2.2 实际效果:显示当前环境,打包时间等信息,便于排查快速定位问题
4.3 开启分析打包日志
PS:打包后展示各个包的依赖关系及大小,可用来分析优化
建议调试时,选择性开启,请勿提交,请勿常开
// 安装依赖
npm install webpack-bundle-analyzer -D
// 以下是打包依赖分析 push 请关闭 请只在本地使用
config
.plugin('webpack-bundle-analyzer')
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
.end()
4.3.1 CDN优化前效果图
4.3.2 CDN优化后效果图
4.4 去除console.log
config.optimization.minimizer('terser').tap((args) => {
args[0].terserOptions.compress.drop_console = true // 移除 console.log
return args
})
4.5 本地代理
devServer: {
// host: "localhost",
port: 8080, // 端口号
https: false, // https:{type:Boolean}
open: false, // 配置自动启动浏览器
disableHostCheck: true, // 解决127.0.0.1指向其他域名时出现"Invalid Host header"问题
proxy: {
'/bscnym': {
target: 'http://xxx:8000',
changOrigin: true,
pathRewrite: { '^/': '/' }
}
}
},
4.6 配置别名
config.resolve.alias.set('@', resolve('src'))
5. 小程序模板简介
5.1目录介绍
├── assets # 静态资源 │ └── icon # iconfont │ └── iconfont.acss # 字体文件样式库 │ └── image # 图片 │ └── style # 部分全局公用的样式库 │ └── public.acss # 基础公用样式库 ├── commons # 通用UI组件(建议在js或者md文件内,标明入参及其含义) │ └── ... # 自定义通用UI组件 ├── components # 业务组件 │ └── ... # 其他自定义业务组件 ├── pages # 页面 │ └── ... # 具体页面 ├── service # 服务 │ └── api # 具体请求 │ └── request # 接口请求的统一封装 │ └── host # 域名 ├── utils # 帮助类 │ └── config.js # 配置 │ └── dict.js # 字典 │ └── mockData.js # 模拟数据 │ └── index.js # 所有utils的统一输出 │ └── ddApi.js # dd相关的api封装 │ └── utils.js # 非dd相关的api封装 ├── app.acss # 全局样式 ├── auto.acss # css生成器自动生成的样式文件 ├── css.generator.config.js # css生成器插件版配置 ├── app.js # 小程序启动入口 ├── app.json # 小程序全局配置,如底部,顶部 ├── package.json # 依赖配置 ├── README.md # README
5.2 commons 通用组件 和 components 组件
同H5版本
PS:由于小程序,组件需要在使用文件的json文件中配置注入,故通用组件库没有做自动注入的操作
5.3 pages 页面
5.4 service 服务
5.4.1 api.js 请求列表
同H5
5.4.2 request.js 接口请求的统一封装
基本思路同H5,接口调用方式由axios改为dd.httpRequest,具体逻辑可根据服务端情况微调
5.4.3 host.js 域名
不同环境的地址配置,等同于H5的 .env文件
5.5 utils 帮助类
5.5.1 config.js 配置项
各类配置项,等同于H5的 .env文件
5.5.2 dict.js 字典
同H5
5.5.3 mockData.js 模拟数据
此处设定为obj[key]直接获取json,json直接由后端提供demo,由config.js控制mock开关。也可采用mock.js
5.5.4 ddApi.js
dd相关的api封装,便于维护
5.5.5 utils.js
非dd相关的api封装,便于维护
5.5.6 index.js
所有utils的统一输出,便于使用
5.6 auto.css 和 css.generator.config.js 生成器自动生成文件与插件的配置
css生成器插件版,通过package.json配置脚本 yarn dev启动。
自动生成auto.css文件,且该文件建议不提交git(避免每次生成不一致,导致较大冲突)
PS:方案需统一,auto.css不提交git,本地运行必须通过yarn dev生成auto.css,否则本地样式会出现异常
5.7 其他想法
login建议单独页面,可将登录逻辑与拦截器等统一逻辑尽可能解耦,逻辑拓展性较强,且尽可能与h5逻辑保持一致