.
├── README.md # 文档
├── dist # 生产部署文件
├── docs # 示例部署文件
├── public
│ ├── index.html # 入口页的HTML模板文件
│ └── favicon.ico
├── server # local-web-server配置文件
│ ├── build.example.js # 编译示例文件
│ ├── config.mock.js # mock接口
│ ├── config.prod.example.js # 示例
│ ├── config.prod.js # 生产
│ └── mocks # mock数据
├── src
│ ├── api # 接口
│ ├── assets
│ │ ├── css
│ │ └── img
│ ├── components # 组件
│ │ ├── common # 公共组件
│ │ ├── layouts # 布局组件
│ │ └── pages # 页面组件
│ ├── config # 项目配置数据,常量
│ ├── i18n # 国际化
│ │ ├── en
│ │ ├── index.js
│ │ └── zh-CN
│ ├── App.vue # 根组件
│ ├── main.js # 入口js
│ ├── mixins # 混入
│ ├── router # 路由
│ ├── store
│ │ ├── index.js # vuex主文件
│ │ └── modules # vuex模块
│ └── utils # 工具方法文件
│ ├── init # 初始化组件和插件
│ ├── load-component # 加载组件方法
│ └── index.js
├── tool # 软件工具相关安装文件
├── vue.config.js # vue cli项目配置文件
├── jsconfig.json # 用于VSCodeIDE智能提示的配置文件
├── apiary.apib # 接口文档
├── package.json
└── README.md
-
本项目是基于Element UI开发的 CMS 原型,依赖 vue,vue-router,vuex @panhezeng/*等类库,详见 package.json
-
本项目的理念是简单好改,专注解决开发 CMS 最基本和核心的需求,用户访问页面权限,数据列表的展示,列表查询筛选排序,列表项的增删查改等
-
本项目主要是对本人以前开发的 CMS 的抽象封装和重构优化,参考了 Ant Design Pro 和 Vue Element Admin,和它们的最重要区别在于,当用户通过点击菜单浏览列表页面,然后进行翻页,筛选等操作后,再刷新页面,依然可以恢复刷新前的列表查询条件
-
最佳实践,最大限度使用 Vue 的组合,插槽(slot),混入 (mixins),抽象封装可复用代码
-
本项目 Element UI 使用按需加载方式,可以修改 src/utils/init-components/element-ui.js 文件增减组件,自定义主题则参考 Element 文档的搭配插件按需引入组件主题部分
-
为减少编译时间,项目初始化依赖的 vue 等类库,除了 element-ui 外,都使用 externals 方法加载,具体见 vue.config.js 的 externals 和 HtmlWebpackTagsPlugin
-
浏览器兼容见 .browserslistrc 和 vue.config.js 的 cdnAssets polyfill.min.js (实测兼容 IE11)
-
不需要的功能可以删除相关代码,比如如果不需要国际化,可以说删除所有 VueI18n 相关代码;不需要切换菜单布局,则可以删除多余的菜单布局代码
-
本页面国际化切换后,使用 reload 方式生效,虽然有点不太友好,但是考虑很多地方国际化不是依赖 vue i18n 模块,而是通过其他方式,还有如果服务端数据也有多语言版本,还需要重新通过接口请求数据等
-
根据项目需求不同,团队人员技术选型不同,在权限设计上会有所不同,本 cms 原型的菜单通过后端获得,权限细化到按钮级别,API 按照后端语言 Python 的 Django 框架要求设计。如果希望菜单放到前端等,后端使用后端 PHP 框架,则需要修改相关代码,在相关功能处已经通过注释说明
-
src/config/pages/index.js 文件包含了所有页面路由权限相关配置,具体页面访问,按钮显示的逻辑,全项目搜索 actionCodes,查看相关代码
-
在 src/components/pages/ 目录内建立以模块名命名 PascalCase(Pascal Case 命名规范)的目录,index.vue 是该模块默认页。 比如公告 News 模块 src/components/pages/News/ ,index.vue 是公告列表页, Item.vue 是公告详情页,components/Form.vue 是添加和编辑公告的表单组件。
-
在 src/config/pages/ 目录内建立以模块名命名 kebab-case(kebab Case 命名规范)的 js 文件,配置该模块的页面路由相关配置。具体页面配置规则请阅读 src/config/pages/index.js 内 pages 对象的注释,参考 news.js 。
-
如果模块需要出现在导航菜单中,以下方式二选一
-
后端实现,在账户信息接口 /api/cms/account/ 返回对象的 menu_actions 属性上设置菜单数据,菜单对象 的 path 属性值必须和页面配置对象的 path 属性值一致。
-
前端实现,在 src/store/modules/pages/menu/ 目录内,在 index.js 或者 development.js 文件内设置菜单数据,development.js 文件内的数据在生产模式会被丢弃。
-
-
注意,如果前后端都设置了同样的菜单数据,则会出现两份同样的菜单
-
如果需要配置导航菜单的 icon,以下方式二选一
-
前端实现, 在 src/config/pages 目录内的页面配置 js 对象中,设置 icon 属性,值为 src/assets/img/icons/svg 中的 svg 文件名。非叶子节点的菜单是没有对应页面配置的,可以通过设置叶子节点菜单的页面配置对象的 parentIcon 属性实现 icon 显示,值和 icon 属性一样,注意如果多个子菜单设置了不同 parentIcon,按菜单顺序取第一个 parentIcon,后面的无效。
-
后端实现,设置账户信息接口返回的菜单对象的 icon 属性,要求同上。
-
-
在 src/api/ 目录内建立以模块名命名 kebab-case(kebab Case 命名规范)的 js 文件,配置该模块的接口。接口 url 请到 mock 文档查看,如果是列表类的增删查改模块,api 方法可继承 common-crud.js,参考 news.js 。
-
如果想把关联度高的模块放在一起,也可以采用父模块名目录嵌套子模块名目录或文件的形式。
-
拿到开发需求后,拷贝粘贴 News 模块相关目录文件,改成新需求的模块名,即可快速开始。具体细节请阅读注释。请修改 index.vue 和 Form.vue 内的 import api from '@/api/news' 的 news 为 新需求模块的 api 文件名
-
vue.config.js devServer 配置 api 接口 代理
-
如需单文件上传,src 目录搜索 single-upload ,查看 SingleUpload 组件用法示例
-
如需多文件上传,src 目录搜索 multiple-upload ,查看 MultipleUpload 组件用法示例
-
如需文本框输入联想搜索 远程搜索单选,src 目录搜索 fetchSuggestions ,查看 el-autocomplete 组件用法示例
-
如需远程搜索多选 tag 和创建 tag 类数据,src 目录搜索 select-remote-multiple ,查看 SelectRemoteMultiple 组件用法示例
-
如需列表项筛选, src 目录搜索 :filters ,查看 el-table-column 组件用法示例,需要 el-table 组件 设置 @filter-change="listScope.filterChange"
-
如需列表后端排序,src 目录搜索 sortable="custom" ,查看 el-table-column 组件用法示例,需要 el-table 组件 设置 @sort-change="listScope.sortChange"
-
如需拖拽排序 在需要实现拖拽排序的组件内混入 src/mixins/sortable.js,src 目录搜索 sortable ,查看 sortable 用法示例
-
如需富文本编辑器, src 目录搜索 Editor ,查看 Editor 组件用法示例
-
基于 src/components/common/Page/List/index.vue 组件的列表页,如需给初始获取列表数据的接口请求设置 query 数据,可以使用 beforeRouteEnter 的 next 方法实现,src 目录搜索 path: to.path , 查看用法示例
-
src/config/form-rules.js src/mixins/form.js 提供常用的表单验证规则
-
element 的表单验证支持的类型和扩展使用方法见async-validator
-
如果 element ui 的 icon 不够用,可以使用 svg-icon 组件,src 目录搜索 svg-icon ,查看用法示例。 在iconfont制作下载 icon 的 svg 文件放到 src/assets/img/icons/svg 目录,在 svg-icon 标签的 icon 属性上添上 svg 的名字即可
-
外部组件的所有属性方法事件用法,请查看组件文档,或者直接查看 node_modules 内组件源码
-
两个以上页面级组件会用到的组件放在 src/components/common 内
-
公共组件和 mixins 的修改要谨慎,确认是普遍性需求,并且兼容之前代码
-
所有混入类,比如常用的 src/mixins/list.js 和 src/mixins/form-add-edit.js 所有的属性对象函数等,都可以在使用混入类的地方进行覆写或追加数据,建议开发前先仔细阅读 src/mixins 类的代码
-
样式相关
-
如需定制样式, 在 root 元素写上 class="目录名-模块名", 示例
-
所有模块样式都嵌套在 root class 内, 示例 .directory-file { .content-main {} }
-
不要使用 scoped-css,原因很多,比如父组件无法覆写子组件的 scoped-css,通过类似 v-html 方式添加的 dom,scoped-css 不起作用等
-
element ui 的部分组件在渲染后是会提取放到 body 元素下,比如 el-dialog,所以这些组件的 class name 和样式,需要特别处理,必须保证 class name 的唯一性,使用目录名-模块名-组件名的方式实现,并且不能嵌套在 root class 内
-
-
如需组件名, 组件名由目录名和文件名构成, 帕斯卡命名法, 示例 name: 'DirectoryFile'
-
列表页组件相关
-
组件 created 方法 默认初始化列表数据,列表查询表单的重置查询,列表项筛选都通过 apiListParamsUpdate 重新请求列表数据,其他情况自行调用 fetchData 方法
-
如需查询表单, page-list 标签写上 :api-list-params="apiListParams" 属性,并且在 page-list 元素内使用 slot,示例 表单项
-
如需带展开功能的查询表单, page-list 标签写上 collapse-form 属性,并且在 query form slot 元素内写上子元素 展开后显示的表单项
-
通过定义页面组件的 data,computed 可以覆写 MixinList 的 data,computed 定义, 比如 apiList 等
-
通过页面组件的 data 定义 apiListParams 对象定义列表接口参数数据,包括列表页查询表单数据,el-table 的 filters 数据,列表页初始化时请求列表接口参数数据初始值
-
用 apiListParamsResetExcludeKeys 排除不点击查询重置按钮重置的字段
-
如果基于 page-list 组件的页面要实现刷新页面回写查询表单数据,则必须在 data 里面定义 apiListParams 数据,注意 apiListParams 对象只支持数字和字符串类型数据,如果查询表单有组件绑定值为 object 或 array,则必须特殊处理,具体使用示例搜索 CascaderValueLast
-
通过页面组件的 data 定义 apiListParamExcludeKeys 数组,剔除列表请求接口的参数
-
如果需要接管列表页点击添加或编辑按钮的行为,page-list 标签写上 header-btn-add-callback 属性 和 header-btn-edit-callback 属性,page-list-action-cell-btn 标签写上 btn-edit-callback 属性
-
如需批量操作按钮, page-list 标签写上 header-btn-batch 属性
-
如需增加 header 区域按钮,在 page-list 元素内使用 slot,slot 名字查看 page-list 组件内 <slot name="header 打头的代码
-
列表元素是在 page-list 元素内写上 slot 命名为 list 的子元素
-
-
在 page-list 组件内查看所有 slot 的可使用 slot 数据
-
-
添加编辑页组件相关
-
通过定义页面组件的 data,computed 可以覆写 MixinFormAddEdit 的 data,computed 定义, 比如 id, apiCreate 等
-
MixinFormAddEdit 提供了提交前拦截,不返回等机制,具体看 src/mixins/form-add-edit.js
-
-
如果是在 jsx 中使用组件,需要通过 Vue.component 方式注册组件
-
注意,用 element 组件的 Table 表格组件,用属性修改宽度样式等,需要刷新页面才能看到正式效果,热更新的方式会异常
-
有些热更新情况下会出现的警告之类的可以忽略,正常刷新无问题
-
富文本编辑器、单文件上传组件等自定义组件的表单项验证需要设置 :show-message="!formData.bar" 才能实现预期效果
Languages and Frameworks | JavaScript | Webpack,点击文件夹图标选择项目的 node_modules/@vue/cli-service/webpack.config.js 文件,实现智能跳转和提示
搜索 eslint,打钩激活
安装 prettier 插件,搜索 File Watchers,点击+,选择 prettier,添加 js 和 vue 的 watcher,可能需要翻墙下载插件,可以使用 tool 目录内的本地文件安装,和导入 watcher 官方文档
Languages and Frameworks | JavaScript ,选择 JSX
每次安装了新版本 node,需要搜索 Node.js , Node interpreter 选择最新版本 node , 勾选 Coding assistance for Node.js , Package manager 选择 npm
配置 jsconfig.json 文件,实现智能跳转和提示
安装 prettier 插件,官方文档
配置
"prettier.eslintIntegration": true, // 开启 eslint 支持
"eslint.autoFixOnSave": true, // 每次保存时自动修复
"eslint.validate": [ // 开启对.vue文件中错误的检查
"javascript",
"javascriptreact",
{
"language": "html",
"autoFix": true
},
{
"language": "vue",
"autoFix": true
}
]
安装插件:SublimeLinter-eslint
修改 SublimeLinter 配置,SublimeLinter settings syntax_map
"syntax_map": {
//・・・
"vue": "javascript",
"vue component": "javascript",
"html": "javascript",
},
-
Ubuntu 系统第一次需要执行
sudo apt-get install -y build-essential
-
重置前端依赖环境,cd 到项目目录,删除前端依赖相关文件
rm -rf node_modules package-lock.json yarn.lock && npm cache clean --force
-
安装项目依赖包 ** 如果需要把老版本的全局模块安装到新版本 node,请把 nvm install node 替换为 nvm install node --reinstall-packages-from=node, 有些系统 nvm 命令需要手动添加到 bash,所以下面命令会找不到 nvm 报错中断,请查看 nvm 安装文档 **
curl -o- https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash && export NVM_NODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/node && nvm install node && nvm use node && curl -o- https://gist.githubusercontent.com/52cik/c1de8926e20971f415dd/raw/e98cbe963748046f371a5c95161449b8b5bd321a/npm.taobao.sh | bash && npm install -g npm && npm install -g nrm && npm i
-
本地测试 http://0.0.0.0:8001/
npm run serve
-
正式发版
npm run build
-
如果 npm run build 失败报错,可以尝试删除 node_modules 文件夹,package-lock.json yarn.lock 文件(如果有的话),再重新执行上面的命令
npm WARN deprecated nomnom babel-preset-es 可以无视,是因为项目依赖的底层包没有更新造成的,不影响项目功能
- cd 到项目目录,执行以下命令
curl -o- https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash && export NVM_NODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/node && nvm install node && nvm use node && curl -o- https://gist.githubusercontent.com/52cik/c1de8926e20971f415dd/raw/e98cbe963748046f371a5c95161449b8b5bd321a/npm.taobao.sh | bash && npm install -g npm && npm i && npm run build
- 拷贝 dist 目录下所有文件到服务器的 cms 域名映射的目录下,所有相关域名地址都指向目录下的 index.html.
nginx
location / {
try_files $uri $uri/ /index.html;
}