规范与每一个团队和我的都是息息相关的,由于其影响的不仅是只是代码的维护和理解成本,严重的时候是会影响成员开发的心情css
一个团队的编码规范、git规范等,并无绝对的最优解,内心要清楚明白没有银弹
,规范是为了让团队统一,提升代码阅读性、下降代码维护成本等,本文是记录一些在项目code review
中常见的规范,仅供参考html
vue
中data
的数据默认便会进行双向数据绑定,如果将大量的和渲染无关的数据直接放置在data
中,将会浪费双向数据绑定时所消耗的性能,将这些和渲染无关的数据进行抽离并配合Object.freeze
进行处理前端
table
中columns
数据能够单独提取一个外部js
文件做为配置文件,也能够在当前.vue
文件中定义一个常量定义columns
数据,由于不管如何都是固定且不会修改的数据,应该使用Object.freeze
进行包裹,既能够提升性能还能够将固定的数据抽离,一些下拉框前端固定的数据也建议此操做vue
const columnList = Object.freeze([
{ title: '姓名', key: 'name', align: 'center' },
{ title: '性别', key: 'gender', align: 'center' }
])
复制代码
须要注意的是 Object.freeze() 冻结的是值,这时仍然能够将变量的引用替换掉,还有确保数据不会变才可使用这个语法,若是要对数据进行修改和交互,就不适合使用冻结了。git
Modal
框的控制一个页面种一般会存在不少个不一样功能的弹框,如果每个弹框都设置一个对应的变量来控制其显示,则会致使变量数量比较冗余和命名困难,可使用一个变量来控制同一页面中的全部Modal
弹框的展现web
好比某个页面中存在三个Modal
弹框ajax
// bad
// 每个数据控制对应的Modal展现与隐藏
new Vue({
data() {
return {
modal1: false,
modal2: false,
modal3: false,
}
}
})
// good
// 当modalType为对应的值时 展现其对应的弹框
new Vue({
data() {
return {
modalType: '' // modalType值为 modal1,modal2,modal3
}
}
})
复制代码
debounce
使用例如远程搜索时须要经过接口动态的获取数据,如果每次用户输入都接口请求,是浪费带宽和性能的json
当一个按钮屡次点击时会致使屡次触发事件,能够结合场景是否当即执行immediate
浏览器
<Select :remote-method="remoteMethod">
<Option v-for="item in temoteList" :value="item.value" :key="item.id">{{item.label}}</Option>
</Select>
复制代码
import {debounce} from 'lodash'
methods:{
remoteMethod: debounce(function (query) {
// to do ...
// this 的指向没有问题
}, 200),
}
复制代码
功能的开发过程当中,图片的处理每每是比较容易被忽略的环节,也会在必定程度影响开发的效率和页面的性能bash
图片压缩问题,除非特别要求图片必须高质量的显示,不然都应该进行对应的压缩处理
不一样业务场景进行图片格式的选型
6KB
的图片进行base64
处理webp
进行图片的处理在组件中使用
$route
会使之与其对应路由造成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了其灵活性。
使用 props
将组件和路由解耦:
取代与 $route
的耦合
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User }
]
})
复制代码
经过 props
解耦
这样你即可以在任何地方使用该组件,使得该组件更易于重用和测试。
const User = {
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, props: true },
// 对于包含命名视图的路由,你必须分别为每一个命名视图添加 `props` 选项:
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
})
复制代码
参考:路由组件传参
在父子组件中,掌握父子组件对应的生命周期钩子加载顺序可让开发者在更合适的时候作适合的事情 父组件
<template>
<div>
<h3>home</h3>
<list @hook:mounted="listMounted" />
</div>
</template>
<script>
import List from './list'
export default {
name: "home",
components: {
List
},
methods: {
listMounted(){
console.log('------------ listMounted');
}
},
beforeCreate() {
console.log("home beforeCreate");
},
created() {
console.log("home created");
},
beforeMount() {
console.log("home beforeMount");
},
mounted() {
console.log("home mounted");
},
beforeDestroy() {
console.log("home beforeDestroy");
},
destroyed() {
console.log("home destroyed");
}
}
</script>
复制代码
子组件
<template>
<div>
list
</div>
</template>
<script>
export default {
naem: "list",
beforeCreate() {
console.log("list beforeCreate");
},
created() {
console.log("list created");
},
beforeMount() {
console.log("list beforeMount");
},
mounted() {
console.log("list mounted");
},
beforeDestroy() {
console.log("list beforeDestroy");
},
destroyed() {
console.log("list destroyed");
}
}
</script>
复制代码
加载时父子组件的加载顺序
home beforeCreate --> home created --> home beforeMount --> list created --> list beforeMount --> list mounted
复制代码
销毁时父子组件的销毁顺序
home beforeDestroy --> list beforeDestroy --> list destroyed --> home destroyed
复制代码
实际开发过程当中会遇到当子组件某个生命周期完成以后通知父组件,而后在父组件作对应的处理
emit up
// 子组件在对应的钩子中发布事件
created(){
this.$emit('done')
}
// 父组件订阅其方发
<list @done="childDone">
复制代码
hook
经过@hook
监听子组件的生命周期
<list @hook:mounted="listMounted" />
复制代码
Select
优化下拉框遍历时,须要注意options
标签保持同一行,如果存在换行,会致使选中时的值存在多余的空白
<!-- bad -->
<Select :remote-method="remoteMethod">
<Option v-for="item in temoteList" :value="item.value" :key="item.id">
{{item.label}}
</Option>
</Select>
复制代码
须要将Options
和下拉框的值保持在同一行
<!-- good -->
<Select :remote-method="remoteMethod">
<Option v-for="item in temoteList" :value="item.value" :key="item.id">{{item.label}}</Option>
</Select>
复制代码
data
数据层级data
数据具备数据层级结构,切勿过分扁平化或者嵌套层级过深,如果过分扁平化会致使数据命名空间冲突,参数传递和处理,如果层级嵌套过深也会致使vue
数据劫持的时候递归层级过深,如果嵌套层级丧心病狂那种的,当心递归爆栈的问题。并且层级过深会致使数据操做和处理不便,获取数据作容错处理也比较繁琐。通常层级保持2-3层最好。
如果只有一层数据,过于扁平
{
name: '',
age: '',
gender: ''
}
复制代码
致使处理不方便
// 做为接口参数传递
ajax({
this.name, this.age, this.gender
})
// 接口获取数据,批量处理
ajax().then(res => {
const {name, age, gender} = res.data
this.name = name
this.age = age
this.gender = gender
})
复制代码
适当的层级结构不只增长代码的维护和阅读性,还能够增长操做和处理的便捷性
{
person: { // 我的信息
name: '',
age: '',
gender: ''
}
}
复制代码
能够针对person
进行操做
// 做为接口参数传递
ajax(this.person)
// 接口获取数据,批量处理
ajax().then(res => {
const {name, age, gender} = res.data
this.$set(this, 'person', {name, age, gender})
})
复制代码
策略模式的使用,避免过多的if else
判断,也能够替代简单逻辑的switch
const formatDemandItemType = (value) => {
switch (value) {
case 1:
return '基础'
case 2:
return '高级'
case 3:
return 'VIP'
}
}
// 策略模式
const formatDemandItemType2 = (value) => {
const obj = {
1: '基础',
2: '高级',
3: 'VIP',
}
return obj[value]
}
复制代码
解构赋值以及默认值,当解构的数量小于多少时适合直接解构并赋值默认值,数据是否进行相关的聚合处理
const {
naem = '',
age = 10,
gender = 'man'
} = res.data
// bad
this.name = name
this.age = age
this.gender = gender
// good
this.person = {
naem,
age,
gender
}
复制代码
任什么时候候尽可能是的一个函数就作一件事情,而不是将各类逻辑所有耦合在一块儿,提升单个函数的复用性和可读性
每一个页面都会在加载完成时进行数据的请求并展现到页面
created() {
this.init();
},
methods: {
// 将所有的请求行为聚合在init函数中
// 将每一个请求单独拆分
init() {
this.getList1()
this.getList2()
},
getList1() {
// to do ...
},
getList2() {
// to do ...
}
}
复制代码
html
书写编写template
模板时,属性过多时,是否换行
<template>
<!-- 不换行 -->
<VueButton class="icon-button go-up" icon-left="keyboard_arrow_up" v-tooltip="$t('org.vue.components.folder-explorer.toolbar.tooltips.parent-folder')" @click="openParentFolder" />
<!-- 换行 -->
<VueButton
class="icon-button go-up"
icon-left="keyboard_arrow_up"
v-tooltip="$t('org.vue.components.folder-explorer.toolbar.tooltips.parent-folder')"
@click="openParentFolder"
/>
</template>
复制代码
html
中展现一些如<
,>
,&
等字符时,使用字符实体代替
<!-- bad -->
<div>
> 1 & < 12
</div>
<!-- bad -->
<div>
> 1 & < 12
</div>
复制代码
在开发中修改第三方组件样式是很常见,但因为 scoped
属性的样式隔离,可能须要去除 scoped
或是另起一个 style
。这些作法都会带来反作用(组件样式污染、不够优雅),样式穿透在css预处理器中使用才生效。
<style scoped lang="less">
.content /deep/ .el-button {
height: 60px;
}
</style>
复制代码
<style scoped lang="scss">
.content ::v-deep .el-button {
height: 60px;
}
</style>
复制代码
<style scoped ang="stylus">
外层 >>> .custon-components{
height: 60px;
}
</style>
复制代码
适当的空格能够提高代码的阅读体验,显得更为优雅和美观
选择器后、属性值
.custom-style { // 选择器和{ 之间空格
margin: 0; // 属性值前
transform: scale(1.5, 2.2); // 逗号以后增长空格
}
复制代码
和html
类型,当某行的属性不少,适当的换行能够提升阅读和美观
.custom-style{
// 能够在一次声明中定义一个或多个属性
background: background-clip
background-color
background-image
background-origin
background-position
background-repeat
background-size;
}
复制代码
当一个规则包含多个选择器时,每一个选择器声明必须独占一行,过长致使须要横向滚动阅读剩余的内容,应该尽可能使得阅读顺序纵向化
.custom .header .title,
.other .header .title {
color: #f0f;
}
复制代码
浏览器在解析css
时,是按照从右到左递归匹配的,过深的层级嵌套不只影响性能,并且还会致使样式阅读性和代码维护性下降,通常层架控制在5层以内
属性选择器中的值必须用双引号包围,不容许使用单引号,也不容许不使用引号,html
的属性值也是推荐使用双引号,js
中使用单引号
.custom-style{
font-family: "PingFang SC", "STHeitiSC-Light";
}
复制代码
同一 规则下的属性在书写时,应按功能进行分组。 并以 Formatting Model(布局方式、位置) > Box Model(尺寸) > Typographic(文本相关) > Visual(视觉效果) 的顺序书写,以提升代码的可读性。
解释:
另外,为增长可读性,若是包含 content 属性,应放在属性的最前面。
参考