项目开发指引
这个文档主要提供项目开发指引
模块搭建规范
模块分类
项目上需要按业务进行模块分类, 在project
下建立项目的分类目录。
比如框架这里, 将所有功能分为两类:
- 组织管理相关(orgModules);
- 系统管理相关(systemModules);
如下所示结构:
├─src #项目资源主目录
│ │
│ └─scopes #功能模块顶层目录
│ │
│ ├─core #框架模块的顶层目录
│ │ │
│ │ ├─ orgModules #模块分类: 组织管理相关
│ │ │
│ │ └─ systemModules #模块分类: 系统管理相关
│ │
│ └─project #预留的项目开发的顶层目录
添加模块
在分类目录下就可以添加相应的模块了,模块按复杂程度可分为单功能模块和多功能模块,不同类型模块目录结构有所不同。
单功能模块
单功能模块的完整目录结构很简单, 如下所示:
├─simpleDemoModule #模块: 简单模块实例
│ │
│ ├─part #页内组件目录(非必须,视情况存在)
│ │
│ ├─route.js #入口路由(非必须,视情况存在)
│ │
│ ├─simpleDemoModule.html #入口html
│ │
│ ├─simpleDemoModule.js #入口js
│ │
│ └─simpleDemoModule.vue #入口vue
其中 part
目录,route.js
都不是必须的。
多功能模块
通常情况下,模块都不是单独的功能,比如框架的资源权限管理模块(authority),模块下有四个相关功能:
- 角色权限管理(roleAuthorityManagement)
- 管理员权限(adminAuthority)
- 权限代理(authorityAgent)
- 相识权限管理(similarAuthority)
多功能模块的完整目录结构, 如下所示:
├─orgModules #模块分类: 组织管理相关
│ │
│ └─authority #模块: 资源权限管理
│ │
│ ├─modulePart #模块的功能目录,四个功能的实现都在这个目录下
│ │ │
│ │ ├─ roleAuthorityManagement #功能: 角色权限管理
│ │ │
│ │ ├─ adminAuthority #功能: 管理员权限
│ │ │
│ │ ├─ authorityAgent #功能: 权限代理
│ │ │
│ │ └─ similarAuthority #功能: 相识权限管理
│ │
│ ├─router #模块的路由配置目录,新增功能后都需要到该目录注册功能路由,这点后面还会提到
│ │ │
│ │ ├─ index.js #路由入口文件
│ │ │
│ │ └─ routes.js #模块下功能的路由加载
│ │
│ ├─authority.html #入口html, 要求跟模块同名
│ │
│ └─authority.js #入口js, 要求跟模块同名 (模块内插件声明也在该入口js中)
在模块的功能目录下, 要求创建一个跟功能同名的vue文件, 作为功能入口, 创建 routes.js
作为功能的路由声明, 简单功能只需要一个功能路由指向入口vue文件即可。
功能的完整目录结构,如下所示:
├─adminAuthority #功能: 管理员权限
│ │
│ ├─api #后台请求代码目录
│ │
│ ├─part #页内组件目录(非必须,视情况存在)
│ │
│ ├─adminAuthority.vue #功能入口vue
│ │
│ └─routes.js #功能路由声明
模块路由
单功能模块路由
没有多余的规范要求,按vue官网实现即可。
多功能模块路由
功能路由声明
模块中每个功能都需要声明自己的路由, 最简单的路由声明就是一个路由直接指向功能的入口vue。典型的路由声明参考,如下所示:
//导出该功能路由 export default [ { title:"管理员权限", name: "adminAuthority", path: 'adminAuthority', component: ()=>import("./adminAuthority.vue"), children: [ { name:'xxxxx', path:'xxxxx', component:()=>import("./part/xxxxx.vue") }, ... ] }, ... ];
模块路由导入
添加一个功能后,需要在模块路由中注册该功能路由, 在 routes.js
中添加引入代码, 如下所示:
import roleAuthorityManagement from '../modulePart/roleAuthorityManagement/routes' import authorityAgent from '../modulePart/authorityAgent/routes' import adminAuthority from '../modulePart/adminAuthority/routes' import similarAuthority from '../modulePart/similarAuthority/routes' const innerRoutes = [ ...roleAuthorityManagement, ...authorityAgent, ...similarAuthority, ...adminAuthority ]
模块注入
添加一个模块后, 需要到 faceConfig 配置中新增模块寻址入口,
// 项目文件打包寻址地址 'docModule': ['corePage/*', 'demoPage/*'], 'coreModules': [ 'orgModules/authority', 'orgModules/orguser', 'systemModules/sysmg', 'systemModules/logmg' ], 'projectModules': [ 'demoModules/projectModuleOne', 'demoModules/projectModuleTwo' ]
在创建对应的功能菜单时, 功能路径配置格式为 [模块入口].html#/[功能名]
组件命名规范
- 文件名、组件名、引入名保持一致 (强制)
- 名称不能重复 (强制)
- 使用驼峰命名,名称开头小写 (强制)
- 名称要有意义,做到见名知意 (强制)
- 不能使用拼音命名 (建议)
data命名规范
data 属性名应该尽量能够做到见名知意,一般来说需要突出两到三个重点:
- 这个变量是关于什么业务行为的?
- 这个变量是关于什么组件的?
- 这个变量是关于组件什么特性的?
比如关于资源管理的model的显示隐藏控制属性,错误示例visable ,正确示例resourceMgModelVisible。
方法命名规范
事件方法命名格式 handleXxxxx, 其他方法命名格式 fnXxx
样式规范
组件样式强烈建议指明作用域与模块内有效,否则可能出现样式混乱
且,样式选择器应避免使用元素选择器, 推荐类选择器
<style scoped lang="less" type="text/less"> #app { padding: 20px } </style>
环境准备
安装环境之前需要安装 nodejs
项目初始化
- 获取项目。
//git 地址 git clone git@114.116.133.51:8package-web-framework/hsa-web-cli.git
- 安装项目依赖。
cmd进入项目文件夹,我这里项目文件夹为demo,然后运行npm install
安装项目依赖的包
F:\gitPro>cd demo F:\gitPro\demo>npm install
- 启动项目。
# 启动 > npm run dev
开发/发布环境配置
开发环境配置
- 配置文档后端地址:
faceConfig.js
//配置测试后端地址 "basePath":"http://localhost:8081", 2. 启动开发环境 # 启动 > npm run dev
打包发布配置
- 我们在发布打包的时候,需要把我们请求的服务器端的地址设置为发布的后端服务地址,在
faceConfig.js
中配置基本路径
//其中http://192.168.28.114:8080就是你发布的后端服务地址 "basePath":"http://192.168.28.114:8080"
- 打包发布命令
npm run build
按需加载
说明
@hsa/hsa-ui
的所有组件从v1.2.0-beta2
开始支持按需加载。
使用方法
- 在入口文件中,引入
@/src/common/js/public-ant-modules
- 如果已经引入
public-ant.js
,则将其删除或注释 - 注释入口文件中之前所有组件引入代码或按照按需加载的方式将其重新引入
public-ant-modules
文件中已经默认引入了一些常用的组件及工具- 完整组件列表请参考
@src/common/js/modules/demoModules.js
- 启动
dev-server
,然后进入相应功能,查看浏览器console(F12)的error(红色)信息,即可看见缺少的组件及工具)在入口文件中引入需要加载的组件及工具等。(从src/common/js/demoModule.js文件中复制即可
- 引入一个组件的代码如下
import { affix } from '@hsa/hsa-ui Vue.use(affix)
import {button} from '@hsa/hsa-ui
,这种引入方式会自动引入组件及样式。无需自己写引入样式的代码(echarts除自动引入的样式文件外,在一个需求下需要引入额外的css文件,具体请查看echarts的文档。#文档跳转)
传统加载方式
传统加载方式:将所有(必需)组件及其样式打包到一个完整的js/css文件中,然后通过引入这个js/css文件实现组件的加载及引入。
说明
@hsa/hsa-ui
所有版本均支持传统加载方式@hsa/hsa-ui
提供的组件,大部分可通过此方式加载;还有一部分组件由于使用频率较低等原因,没有添加到这个js中,对于这一部分组件(以下称可选组件),可以采取按需加载来引入。
可选组件
careful-delete driver, echarts, rich-editor, simple-uploader, w2ui-datagrid, search-panel, sensitive-input, user-input, user-select, tag-select, page-tool
引入方式
- 在入口文件中引入
@src/common/js/public-ant
- 框架版本
1.1.1
之后,均默认使用按需加载的方式进行组件加载。
- 可选组件通过下面的方式加载
import { pageTool } from '@hsa/hsa-ui Vue.use(pageTool)
两种加载方式的比较
加载方式
- 传统方式加载组件只需要引入js/css,然后注册即可。
- 按需加载只需要引入组件,然后注册。
相比之下,传统方式加载所有组件最多只需要3行代码;
传统方式
import HsaUI from '@hsa/hsa-ui/dist/hsa-ui.js import '@hsa/hsa-ui/dist/hsa-ui.css Vue.use(HsaUI)
按需加载
import { affix, anchor, autoComplete, ... } from '@hsa/hsa-ui Vue.use(affix) Vue.use(anchor) Vue.use(autoComplete) ...
页面性能
- 按需加载可以在一定程度上提升页面的加载性能
- 按需加载可以在一定程度上减少页面的大小
调试能力
- 按需加载由于引入的是可读性较高的编译代码,所以在调试组件内部代码时,具有更高的可调式性
- 传统方式编译出的代码是经过混淆、压缩的,在调试组件内部代码时,很难发现组件代码中的问题
推荐
- 推荐使用按需加载方式加载组件,这样可以有效提高编译后的页面加载性能
内存溢出报错
//全局安装 increase-memory-limit npm install -g increase-memory-limit //项目目录下运行 increase-memory-limit
执行npm install
时,权限不足
installation failed { Error: EACCES: permission denied, mkdir '**' }
就是说 npm 出于安全考虑不支持以 root 用户运行,即使你用 root 用户身份运行了,npm 会自动转成一个叫 nobody 的用户来运行,而这个用户几乎没有任何权限。这样的话如果你脚本里有一些需要权限的操作,比如写文件(尤其是写 /root/.node-gyp),就会崩掉了。
为了避免这种情况,要么按照 npm 的规矩来,专门建一个用于运行 npm 的高权限用户;要么加 --unsafe-perm 参数,这样就不会切换到 nobody 上,运行时是哪个用户就是哪个用户,即使是 root。
解决方案1:添加参数--unsafe-perm
npm install --unsafe-perm
解决方案2:建立用户:npm,且权限设置应当较高。
参考文档:unsafe-perm
在Idea/WebStorm中,在Vue文件写代码时会自动引入错误的组件
- 打开设置。
- Editor->General->Auto Import ,取消勾选JavaScript相关的复选框。
前端项目开发规约细则
规约细则是开发过程中的总结与代码优化, 该文档会不断完善与补充。
- API 代码提取到单独JS模块, 请求回调使用
=>
函数, 去调多余的 self 声明 - 在判断、插槽等vue语法时 , 尽量使用 template 代替 div, 减少页面层级
vue 属性赋值建议都用双引号, 建议四个属性以上换行书写
<ta-form-item label='自定义编码' :labelCol="formItemLayout.labelColTwo" :wrapperCol="formItemLayout.wrapperColTwo" fieldDecoratorId="code"> <ta-input/> </ta-form-item>
- 不推荐使用 v-html 语法
- 使用 v-for 语法时, 必须指定 key 值
<ta-select-option v-for="item in CollectionData('SEX')" :key="item.value" :value="item.value"> {{item.label}} </ta-select-option>
- v-for 与 v-if 不要同时用在一个元素上,如果是为了过滤列表, 请使用计算属性替代v-if ;如果是为了隐藏列表, 请在外层加 template 标签处理;
- 表格的列定义放在 export default 语法前 , import 语法后, 用 const 声明
- 组件的data 应该是一个函数, 而不是一个对象
export default { name: "componentName", data(){ return { } } }
- Form 布局相关、列布局相关 配置 应该放置data顶部
export default { name: "componentName", data(){ return { //表单布局 formLayout: 'horizontal', formItemLayout: { labelCol: {span: 6}, wrapperCol: {span: 18} }, //栅栏布局 row: { col: { selectCol: { span: {sm: 7} }, searchCol: { span: {xs: 12, sm: 10, md: 8, lg: 6} } } }, } } }
- Form表单赋值, setFieldsValue 可配合框架提供的 Base.objectAssign 方法使用, 方便有效
this.form.resetFields(); let updateFormItemValue = Base.objectAssign(this.form.getFieldsValue(),result) this.form.setFieldsValue(updateFormItemValue)
- 组件的 prop 定义, 应该更加具体, 至少要指明属性类型
props:{ search:{ type: Function, required: true }, advancedSearch:{ type: Function, required: true } },
- 使用计算属性时, 可进行拆分,多个计算属性更有利于代码阅读和重构
- 应该优先通过 prop 和事件进行父子组件之间的通信,而不是 this.$parent 或改变 prop。
- 应用优先使用框架提供的 vuex 管理全局状态, 而不是使用全局变量
- lodash 工具类提供了 isString、isArray、isPlainObject 等工具方法(完整用例请查看官网https://www.lodashjs.com), 框架已经引入, 开发人员引入:
import isString from 'lodash/isString' import isPlainObject from 'lodash/isPlainObject' import toString from 'lodash/toString'
- 实现确认框,不建议添加model 通过data 属性控制, 使用 this.$confirm API 即可, 减少不必要的data 属性
this.$confirm({ title: '是否删除已选中的代理角色?', okText: '删除', okType: 'danger', onOk:() => { api.batchDeleteAgentRole(this,roleIdArray,(data) => { this.fnGetAllAgentRole(); }) } });
- 关于更多 this.$confirm 属性支持可查阅 API 网站
在线主题换肤功能使用方法
引入
- 在需要换肤的页面入口文件添加下面的代码
import { changeThemeHandler } from '@/common/js/util/themeConfig.js' changeThemeHandler()
- 分别将文件
webpack.dev.conf.js
及webpack.prod.conf.js
文件中75-82行及63-70行的注释打开。这可以让webpack在编译的时候将必须的依赖复制到static目录下 - 将
userMenu.vue
文件28行的false
改为true
或将v-if
删除。 - 按需加载下的主题换肤与传统方式一致
开发及发布流程变更
- 在执行
dev-server
或build
之前,需要首先执行dev:color-less
将主题文件正确的生成
需要替换的颜色变量及使用方法
- 目前框架支持基于less的主题颜色替换。
- 方法:
- 在config/themeVariables.js中添加需要进行主题替换的变量。
- 如果需要在vue中使用变量,则需要在
src/style/var.less
文件中参照:root的配置,将变量配置为css的原生变量(此方法不支持IE,若要支持IE,请引用相应polyfill)。
示例:
:root { --primary-color: @primary-color; }
- 如果需要添加新的主题,则需要在src/style/theme目录下新建相应的主题js文件,并参照其他js的写法将相应的变量进行赋值。同时,需要在
src/style/theme/theme.js
文件中将这个新的主题的primary-color
进行导出。
- 注意事项:
src/style/theme
目录下的文件名应该与src/style/theme/theme.js
中的键对应,否则可能出现未知的错误。
- 引用:
- 在vue文件中使用:
- 在src/style/index.less中定义css原生变量后,可以直接通过
var(--primary-color)
来使用。示例如下:
body{ background-color: var(--primary-color); }
- 在less文件中使用:
在less文件中,可以直接使用@primary-color来引用变量。
示例
body{ background-color: @primary-color; }