分支规则
主分支: master
开发分支: develop
功能开发以 `feature/功能名` 命名
组件开发以 `components/组件名` 命名
修复 bug 以 `bugfix/bug(bugId或简短名)` 命名
紧急修复以 `hotfix/bug` 命名
文档开发以 `docs/功能名` 命名
命名规则
统一命名规则
动态组件 统一使用 `tag` 属性来指定生成的标签类型
状态对应属性应该为直接的状态名
如: `loading` 状态对应属性名应该为 `loading`、`disabled` 状态对应属性名应该为 `disabled`
分子以上组件,内部出现多个组件有相同状态则以 [组件名][状态名] 小驼峰形式对外暴露
内部组件对外暴露 `class` 属性以 `[组件名][Class]` 小驼峰形式命名
`script`、`js` 中驼峰命名,文档、文件夹、模板中以 - 连接
数组类型以复数形式命名
例如: `options` 对应为 `array` 类型, `option` 对应为 `object` 类型
内部组件命名也应该符合命名规范
内部组件属性透传命名建议以 `[组件名]Props` 名称命名
例如: 导航组件使用 `logoProps` 属性对 `logo` 标签进行属性传递
内部响应事件函数应该以 `handle[EventName]` 命名, `update` 事件以 `update[PropName]` 命名,如果内部有多个相同的事件名,则以 `handle[Element/ComponentName][EventnName]` 命名
子组件有更改属性需求时,对外发送 `update:PropName` 事件,并且将新值当做第一个参数
代码块Vue.js Component<template><div></div></template><script>export default {props: {visible: Boolean,},methods: {toggle () {this.$emit('update:visible', !this.visible);}}}</script>slot 命名应该明确表明该 slot 对应元素的意义
例如: <slot name='loading' /> 表明此插槽用来显示自定义的 loading 元素
// only an demo <script>export default { name: 'MtdButton', props: { // logo 地址 logo: String, // [组件/模块名]Props logoProps: Object, // [组件/模块名]Class logoClass: String, // 数组类型命名复数 options: Array, option: Object, }, methods: { // handle[ComponentName][EventName] handleInputClick () { } }}</script>Props
样式相关枚举类型属性不做强校验、功能相关强校验
用户可能自己定义了其他样式并将改属性传入,所以对样式方面的枚举类型不做强校验,但是功能方面需要内部的支持,传入一个不支持的对于用户来说没有任何意义。
代码块Vue.js Component// tooltip component<script>export default {name: 'MtdTooltip',props: {// 此属性用于生成对应的 class,内部样式只支持 dark、 light,但是不能排除用户提供了其他样式的可能,所以此处不校验theme: String,// 此属性用于 tooltip 的显示触发方式,由于内部只实现了 hover,click 所以对于用户来说传递一个其他方式并没有意义trigger: {type: String,validator: function (v) {return ['hover', 'click'].includes(v);}}// ...other}// ...}</script>表单需要支持 `v-model`, 使用 .sync 修饰符表达更新 props 意图
代码块Vue.js Component// switch component<script>export default {name: 'MtdSwitch',model: {prop: 'actived',},props: {actived: Boolean,},methods: {handleClick () {this.$emit('input', this.actived);}}}</script>上层组件需要支持内部组件属性透传,特别是要提供内部组件 `class` 传递
有些时候需要对内部进行样式的覆盖,如果不提供 `class` 支持,外部只能通过选择器的优先级完成.
代码块Vue.js Component// 分页组件分为 Pagination, Pager// Pagination component<template><ss-pager v-bind="$attrs" :class="pagerClass"></ss-pager>// or<ss-pager v-bind="pagerProps"></ss-pager>// ...</template><script>export default {name: 'MtdPagination',props: {pagerClass: string,}}</script>组件作用对应某一个原生标签时,需要使用 `v-bind="$attrs"` ,对应的也可以使用 `v-on="$lisenters"`
这样做可以不用显示的定义全原生标签属性,而且当原生属性扩展时不需要更变
代码块Vue.js Component// input component<template>// ...<input v-bind="$attrs" /></template>组件避免出现不同属性控制相同功能、样式
代码块Vue.js Component// pager component// 不推荐<script>export default {props: {total: Number,pageCount: Number,pageSize: Number,}}</script>// 推荐<script>export default {props: {total: Number,pageSize: Number,}computed: {pageCount () {return Math.ceil(total/pageSize) || 0;}}}</script>
Data / State
组件无状态,控制权交与使用者
代码块Vue.js Component// switch component<script>export default {props: {actived: Boolean,},methods: {handleClick () {this.$emit('input', !this.actived); // 此时如果外部没有改变 actived 属性的值,显示依然会是原来的状态}}}</script>优先使用计算方式得出当前所需内部属性 (vue 中的 computed)
例如: tabs 组件中,tab 组件会有 active 的状态,active 的状态应该由计算属性得出来,而不是通过 watch 来改变内部变量
代码块JavaScript// betterget active () {return tabsValue === this.value}// notwatch {tabsValue (n) {this.active = n === this.value}}避免出现内部属性的使用 (vue 的 data 函数, react 的 state)
Event
在父子组件通信、属性方法定义时,当不需要方法的返回值时,原则上都应该使用事件的方式 ( Vue )
代码块JavaScript// 不推荐export default {name: 'MtdInput',props: {onChange: Function,},methods: {handleInput (v) {this.onChange(v);}}}// 推荐export default {name: 'MtdInput',methods: {handleInput (v) {this.$emit('input', v);}}}组件应该支持常用的原生事件,原生事件第一个参数应该是 event 对象
代码块Vue.js Component<template><div><input v-bind="$attrs" v-on="$lisenters" :value="value" @input="handleInput" /></div></template><script>export default {name: 'MtdInput',props: {value: [String, Number]},// ...other}</script>原生类型事件,其行为应该同原生事件 例如: compositionstart、compositionend 事件,应该表现同原生,不应该对外发送 change 类型事件
change、update 类型事件第一个参数是 新值,第二个参数是 旧值
代码块Vue.js Component<template><div></div></template><script>export default {props: {visible: Boolean,},methods: {handleClose () {this.$emit('update:visible', false, this.visible);}}}</script>事件、方法参数应该避免超过3个,且越常用的参数应该越靠前
方法中最后一个参数不应该是 bool 类型,应该将所有 bool 类型参数改为 object
代码块JavaScript// 不推荐:function doSomthing (param, replace /* bool */)// 推荐:function doSomthing (param, { replace /* bool */ })
组件通信
统一使用 事件 方式向父级通信,父级通过更改 prop 做出回应
避免使用 refs
避免使用 $parent
Vue.js 支持组件嵌套,并且子组件可访问父组件的上下文。访问组件之外的上下文违反了基于模块开发的第一原则。因此你应该尽量避免使用 this.$parent
其他
组件内部不要出现魔数,如果确实有需求需要使用,必须添加注释,描述清楚数值的作用及来源,如果可能更改(该值可能出现自定义的需求),则将其作为属性,默认值为当前值
样式相关需求优先考虑 `css` 或 `scss` 变量方式,如果 `css`、`scss` 实现不了,则需要在 `js` 实现时添加注释说明原因
将样式与 `js` 分离,方便用户做样式覆盖,如果写在了 `js` 中则很大概率会使用 `style` 方式来生成样式,对于用于自定义样式来说非常困难,而且,各个页面、组件之间样式很可能有一定的关联性,一部分在 `css` 中,一部分在 `js` 中不利于管理