# README.md

- 开发

  基础: pug + stylus / sass / less + vuex + axios + quasar + element-ui + vant + bus + ...
  高级: 自定义指令, 页面混入, 全局过滤器, 重置样式和主题, 条件编译`compression-webpack-plugin`, 动态作用域插槽和具名插槽, 基础库和依赖 (crypto-js, px2rem, fecha ...)
  集成: 配置 mob 和 admin 两套代码登录页, mob 的 TabBar, admin sideBar, token 和路由钩子验证
  平台: 条件编译下配置不同环境下加载不同组件库, 真正的按需引入. _兼容两端, `process.env.VUE_APP_PLATFORM` 值为集合, 多平台编译_
  扩展: 配置了对应的主题和样式重置(条件编译), 分环境: 加载路由 `redirectIndex`, `progress`, 骨架屏, 404 页面(_设备判断优先于且兼容平台_), ...

- 取消

  图片压缩(图片压缩不如图片懒加载和 base64)
  node_modules 抽离公共部分单独部署（多项目）

- 扩展

  ssr: 更高的服务器成本(https://ssr.vuejs.org/zh/) Nuxt.js. 更好的 SEO，避开 ajax 获取内容不能被抓取，若 SEO 至关重要; 更快的内容到达时间，若内容到达时间(time-to-content) 与转化率直接相关.
  可用：`prerender-spa-plugin` 预渲染，相对于 ssr 改动小，且只有极少页面需要 seo. 但存在动态数据, 经常发生变化, 实时性, 路由过多情况下不建议使用, 维护成本过高
  推荐: 骨架屏实现方案: 全局骨架屏使用的 base64 GIF 图片, 极大减少白屏时间. 页面骨架屏将 SEO 配置骨架屏标签上, 不但实现了 seo 抓取页面内容, 还提升了数据请求 loading 单一, 加载导致页面抖动问题
  依赖: 使用 `vue-content-loader` 依赖, 构建页面级骨架屏. 若使用了 quasar / vant-ui. 可使用其内置的骨架屏组件

--~---~---~---~---~---~---~-----~---~---~---~---~---~---~---~--~-----~---~-----~---~---~---~---~---~---~---~--~-----~---~-----~---~---~--

# 前言

- 验证

  开发环境下开启了 `eslint`, 并配置 `pre-commit`

- 原则

  1. 尽可能按需加载
  2. 尽量做到复用性
  3. 尽可能减少体积
  4. 尽可能使用异步
  5. 尽可能不要添加无效 npm

- 规范

  1. 使用 px 而不是 rem, 已添加了高清和 rem 适配, 详见 REMARK.md
  2. 尽可能符合语法规范: CSS BEM, 驼峰, lint, ...
  3. 使用 bus/storage 将 key 声明为常量，便于追踪和管理
  4. 数据源返回尽可能使用 map, 提取需要字段. 避免注入过多无效字典影响性能
  5. vue 不允许直接在组件第一层使用 v-for，因此为每个组件都添加有容器，页面类名为 main，组件类名为 comp
  6. 重复代码、公共样式、固定方法，统一进行封装；尽可能将公共变量、配置环境变量常量化到配置文件
  7. 数组处理尽量少使用 for/forEach。多使用 find、filter、some、every、reduce 等
  8. 尽量使用结构和扩展语法，取值，合并对象
  9. 变量和文件命名尽可能不要使用拼音，使用驼峰命名方式（每个单词首字母大写，第一个单词首字母可小写）
  10. 组件引用使用动态引入，懒加载：compName: () => import("@/comp path"),
  11. 路由按需加载： component: () => import("@/comp path"),
  12. 组件尽可能声明 name 值，组件内使用 comp + 组件名称，页面使用路由名称: `keep-alive`, `dom 递归`, `vue-tools` :: _通过 `plop` 生成自带_
  13. 引用文件, 路径使用绝对路径(若需要可为目录配置别名)
  14. 尽可能去掉无用生产依赖, 尽可能安装在 `devDependencies` 下 (_安装依赖 -D 等同于 --save-dev, -S 即 --save 进入 `dependencies` 内_)

- 文件

  1. 文件夹：中横线
  2. js 文件名称：中横线
  3. css 文件名称：点
  4. vue 文件名称：大驼峰

- 使用

  1. 数据量大, 冻结, 降低开销: `this.item = Object.freeze(Object.assign({}, this.item))` _滤掉无用字段可用封装 `optimize` 库_
  2. 一次性响应事件使用 v-once
  3. 优先 v-show, 尽量不使用 v-if
  4. 使用 keep-alive: 需要组件有 name, `plop` 方式下自动生成
  5. v-if 不要和 v-for 同级: 若真是存在这个情况, 改用计算属性

--~---~---~---~---~---~---~-----~---~---~---~---~---~---~---~--~-----~---~-----~---~---~---~---~---~---~---~--~-----~---~-----~---~---~--

# 使用

- 环境

  1. npm install / npm i: 下载项目依赖
  2. npm run serve / npm run dev: 运行测试环境
  3. npm run build: 运行生产环境: `dist` -- 可在 `.env` 配置打包平台

- 细节

  1. 路由懒加载：component: () => import("path”)
  2. 组件懒加载: compName: () => import("path”)
  3. 所有文件按需加载
     1. styles 继承和混合(主题自动加载); 详见 REMARK.md 样式篇
     2. axios 不使用 `vue-router` 插件, _不在原型链添加 axios 对象, 按需引入_
     3. 组件库 `element-ui / vant-ui` 按需加载, 详见 READEME.MD
  4. 配置 `babel/syntax-dynamic-import` 异步加载插件 -- 详见 `.babel.config.js`
  5. 在普通 js 文件中获取到 vue 实例
     1. 粗暴直接: 在 main.js 将创建的 vue 对象挂在在 window 上: `window.$vue = new Vue({})`, _若只是获取 vue 属性,如 router 可直接导入其文件即可_
     2. 相对优雅: 在 main.js 进行 vue 实例进行导出,在需要的文件被内导入, _尽可能使用传参的方式带入`this`以避免性能问题, 示例: `@/utils/message.js`全局提示_ (import 不会重复导入)
     3. 解决方案: _按需引入, `this.$xxx` 访问 `Vue.prototype.$xxx` 原型链对象, 无需通过 `main.js`作为中转, 直接按照声明方式使用即可. 其中若使用 `router / store` 同理_
     4. 案例展示: `@/service/progress` 分平台全局提示 UI: 设备判断优先于且兼容平台, 如 loading, message, notice, dialog, .... (_服务于通用而不是组件内部_)
  6. `optimize` 防抖和节流, 序列化 table 组件表头数据, 组件 table 映射必须属性
  7. 性能优化: 如 bus, vue 细节点, 详见 REMAEK.md

--~---~---~---~---~---~---~-----~---~---~---~---~---~---~---~--~-----~---~-----~---~---~---~---~---~---~---~--~-----~---~-----~---~---~--

# 项目

- 项目配置

  1. 浏览器样式重置
  2. 开发环境下 vconsole
  3. 主题自动加载
  4. 条件编译
  5. 自动异步加载
  6. px 自动转为 rem
  7. 文件别名管理
  8. 打包体积分析
  9. 本地代理
  10. 自动识别文件后缀
  11. 代码压缩混淆, 去除注释和打印
  12. 配置 gzip 压缩 (需要服端也开启)
  13. 取消编译 map
  14. 分包处理和懒加载, chunk 配置, 将各个文件 css 和 js 单独拆分, 减少体积提升加载速度
  15. 输出重构: 打包编译后的文件名称【模块名称.chunkhash.版本号】, 避免缓存
  16. 骨架屏: 全局 loading GIF
  17. vuex: mudules 管理 (命名空间)
  18. axios aop 统一管控，导入导出通用接口

- 项目工程结构

  1. 依赖 `npm i -D mddir`, 目录结构图 (开发依赖)
  2. 执行 `npm run topology` 运行 `node node_modules/mddir/src/mddir src` 为 `src` 目录生成目录解构图

```
|-- vue-mcli
    |-- .DS_Store
    |-- App.vue
    |-- main.js
    |-- package-lock.json
    |-- package.json
    |-- assets
    |   |-- .DS_Store
    |   |-- icon
    |   |   |-- no-data-icon.png
    |   |-- images
    |   |   |-- .DS_Store
    |   |   |-- 404.jpg
    |   |   |-- bg-login-admin.jpg
    |   |   |-- bg-login-mob.jpeg
    |   |   |-- sample-media.jpg
    |   |   |-- sample.jpg
    |   |   |-- solution-media.jpg
    |   |   |-- solution.jpg
    |   |-- logo
    |   |   |-- .DS_Store
    |   |   |-- ico.png
    |   |   |-- logo-calendar.png
    |   |   |-- logo-t.png
    |   |   |-- logo.png
    |   |-- tmp
    |       |-- .DS_Store
    |       |-- banner
    |       |   |-- banner1-mob.png
    |       |   |-- banner1.png
    |       |   |-- banner2-mob.jpg
    |       |   |-- banner2.jpg
    |       |-- skeleton
    |           |-- .DS_Store
    |           |-- seketon-admin.jpeg
    |           |-- seketon-mob.jpeg
    |-- components
    |   |-- admin
    |   |   |-- table.mixin.js
    |   |   |-- table.vue
    |   |   |-- topBack.vue
    |   |-- dialog
    |   |   |-- role.vue
    |   |-- mob
    |       |-- navBar.vue
    |-- config
    |   |-- bus.js
    |   |-- setting.js
    |   |-- expert
    |   |   |-- filters.js
    |   |   |-- mixins.js
    |   |-- loader
    |   |   |-- element.ui.js
    |   |   |-- flexRem.js
    |   |   |-- quasar.ui.js
    |   |   |-- vant.ui.js
    |   |   |-- vconsole.js
    |   |-- skeleton
    |       |-- admin.vue
    |       |-- conf.js
    |       |-- mob.vue
    |-- directive
    |   |-- loader.js
    |   |-- waves
    |       |-- index.js
    |       |-- waves.css
    |       |-- waves.js
    |-- mock
    |-- router
    |   |-- index.js
    |   |-- modules
    |       |-- admin.js
    |       |-- mob.js
    |       |-- sideBar.js
    |       |-- tabBar.js
    |       |-- universal.js
    |-- service
    |   |-- api.js
    |   |-- network.js
    |   |-- progress.js
    |   |-- request.js
    |   |-- vendor.js
    |-- store
    |   |-- getters.js
    |   |-- index.js
    |   |-- modules
    |       |-- config.js
    |       |-- user.js
    |-- styles
    |   |-- .DS_Store
    |   |-- animate.styl
    |   |-- extend.styl
    |   |-- mixin.styl
    |   |-- quasar.variables.styl
    |   |-- transition.styl
    |   |-- loader
    |       |-- browser.reset.styl
    |       |-- common.styl
    |       |-- element.variables.scss
    |       |-- navBar.reset.styl
    |       |-- vant.variables.less
    |       |-- variables.styl
    |-- utils
    |   |-- array.js
    |   |-- calc.js
    |   |-- crypto.js
    |   |-- device.js
    |   |-- fecha.js
    |   |-- optimize.js
    |   |-- storage.js
    |   |-- util.js
    |   |-- validate.js
    |-- views
        |-- .DS_Store
        |-- index.vue
        |-- element
        |   |-- pages
        |   |   |-- hsJianGao.vue
        |   |   |-- loginIn.vue
        |   |-- sideBar
        |       |-- sideBar.1.1.vue
        |       |-- sideBar.1.2.vue
        |       |-- sideBar.2.1.vue
        |       |-- sideBar.2.2.vue
        |       |-- sideBar.layout.vue
        |-- quasar
        |   |-- calendar
        |   |   |-- approval.vue
        |   |   |-- checkIn.vue
        |   |   |-- layout.vue
        |   |-- cms
        |       |-- .DS_Store
        |       |-- layout
        |       |   |-- index.vue
        |       |-- pages
        |           |-- .DS_Store
        |           |-- index.vue
        |-- universal
        |   |-- 404.vue
        |-- vant
            |-- pages
            |   |-- login.vue
            |   |-- setting.vue
            |-- tabBar
                |-- tabBar.four.vue
                |-- tabBar.layout.vue
                |-- tabBar.one.vue
                |-- tabBar.three.vue
                |-- tabBar.two.vue
```
