作者简介:
李中凯老师,8年前端开发,前端负责人,擅长JavaScript/Vue。
公众号:1024译站
掘金文章专栏:https://juejin.im/user/57c7cb8a0a2b58006b1b8666/posts
主要分享:Vue.js, JavaScript,CSS
通过查看 Vue.js 文档 和网上的资料,我列了一个最佳实践和风格指南的清单,这些是被普遍认为更加正确的 Vue.js 用法。
下面列出的这些点,有些是功能和优化相关的,其他的是 Vue.js 命名约定和元素顺序相关。
组件销毁的时候用 $off 清除事件监听器
当使用$on
监听事件时,我们应该记得在destroyed()
中用$off
移除该事件。这样可以防止内存泄漏。
事件名总是使用 kebab-case 大小写
触发和监听自定义事件时,应该总是使用 kebab-case 大小写形式。为什么呢?因为无论怎样事件名总会自动转成小写,根本没有机会监听到驼峰式和首字母大写格式的事件名,因此,跟监听用的格式保持一致更加合理,也就是 kebab-case 形式。
// 触发事件
this.$emit('my-event') // 不推荐写法:myEvent
// 绑定事件
v-on:my-event
避免在 created 和 watch 里调用同一个方法
如果需要在组件初始化和属性变化时触发方法调用,通常的做法是这样的:
watch: {
myProperty() {
this.doSomething();
}
},
created() {
this.doSomething();
},
methods: {
doSomething() {
console.log('doing something...');
}
}
尽管看起来没错,但是这里使用created()
是多余的。我们可以把所有功能都放进watch
,这样就避免在created()
中写重复的代码了,同时还能在组件初始化时触发。例如:
watch: {
myProperty: {
immediate: true, // 初始化时立即执行
handler() {
this.doSomething();
}
}
},
methods: {
doSomething() {
console.log('doing something...');
}
},
// 这样甚至更好
watch: {
myProperty: {
immediate: true, //初始化时立即执行
handler() {
// 只用一次的代码都不需要定义方法了。
console.log('doing something...');
}
}
},
v-for 循环总是使用 :key
在模板循环里总是加上:key
是一种常见的最佳实践。不带:key
的v-for
会导致很难发现错误,尤其是在动画中。
mixins 中的属性名使用$_前缀
mixins 是一种绝佳的方式,它把重复代码放在一起,然后在需要的时候引入。但是,一个大大的但是,这会导致一些问题。在这里我们说下属性冲突的问题。
但我们在组件中引入一个mixin时,其实是将mixin里的代码和组件代码合并了。那么,碰到同名的属性会怎样?答案是,组件的优先级更高。
如果我想要 mixin 的优先级更高怎么办 ?你无法改变优先级,但是可以避免属性合并,甚至选择正确的命名约定来避免属性覆盖。
为了区分 mixin 属性和组件属性,我们可以使用$_
前缀。为什么是这两个字符?有几个原因:
-
来自VueJs 风格指南的约定
-
_
是给Vue 私有属性用的 -
$
是给 Vue 开源生态用的
VueJs 风格指南 建议加上mixin的名称,例如:$_myMixin_updateUser
。
我发现,加上 mixin 的名称带来的迷惑性多于可读性。不过这也取决于 mixin 的开发者和使用场景。
通过添加$_
,例如$_updateUser
,代码的可读性好多了,也可以轻松区分组件和 mixin 了。
mixin用到的属性应该在mixin中定义
在上一点的基础上,mixin还有另一个问题:有时候会忘了定义相关属性。
如果我们创建了一个 mixin,并使用了this.language
,而它没有在mixin内部定义,那么引入这个 mixin 的组件必须要包含language
属性。
想必你也能看出来,这很容易出错。为了避免这些错误,我们应该在 mixin 内部定义用到的东西。不要担心会定义两次,Vue.js 足够智能,如果检测到已经从Store 获取(大部分情况下都是从 store 获取数据),就不会做重复工作。
单文件组件命名使用 PascalCase 或者 kebab-case 大小写风格
PascalCase 风格能更好地与编辑器集成,在常用的IDE中也有更好的自动完成和导入功能。
如果我们想避免大小写敏感的文件系统的问题,kebab-case 风格比较合适。
基类组件命名使用前缀
展示型、静态的和“纯”组件应该用一个前缀来与其他非“纯”组件区分开来。这样可以提高项目的可读性,以及改善团队和开发者之间的知识传递。
组件名称使用 PascalCase 风格
在 JavaScript 中,PascalCase 风格是类和原型构造器的传统约定,Vue 组件使用这种风格也比较合理。
如果你只使用通过Vue.component
定义的全局组件,建议使用 kebab-case 风格。
Prop 声明时应该总是使用 camelCase,但在模板里是 kebab-case 的。
根据语言各自的约定:JavaScript 使用(camelCase) , HTML 使用 (kebab-case), prop
在JS中定义时用camelCase,而在HTML中使用kebab-case是合理的。
使用风格指南中的组件配置项顺序
听起来可能有点呆板,但是在整个项目中让组件的所有配置项保持一样的顺序,有助于内容查找,也方便创建新的组件。
Vue.js 代码约定见风格指南 (https://vuejs.org/v2/style-guide/#Component-instance-options-order-recommended)。
使用 v-for 的元素不要同时使用 v-if
这是性能杀手,对于这种错误做法,列表越大,性能损失越大。
我们通过代码来解释下。假设有这么一个场景:
<ul>
<li
v-for="game in games"
v-if="game.isActive"
:key="game.slug"
>
{{ game.title }}
<li>
</ul>
这会被解析成类似这样的代码:
this.games.map(function (game) {
if (game.isActive) {
return game.title
}
})
可以看到,我们必须遍历整个games
列表,无论符合条件的games
列表是否有变化。
其他框架,比如 Angular,这种写法根本无法通过编译。(使用**ngFor*
的元素不能有**ngIf*
)
Actions 必须有返回
这是长期折腾 async
/await
和 Vuex actions 得出的经验。
举例如下:
// Store
[SOME_ACTION] () {
// 耗时的某个操作
console.log('Action done');
}
// 使用 action
async doSomething() {
await dispatch(SOME_ACTION);
console.log('Do stuff now');
}
这会输出:
// Do stuff now
// Action done
这是因为await
不知道要等待什么,相反,如果我们实际上返回了一个Promise.resolve()
,await
就会等待解决,然后继续执行。
// Store
[SOME_ACTION] () {
// 耗时的操作
console.log('Action done');
Promise.resolve();
}// 使用action
async doSomething() {
await dispatch(SOME_ACTION);
console.log('Do stuff now');
}
这会输出:
// Action done
// Do stuff now
在 actions 和 getters 内部使用选择器函数
我们创建选择器函数是有原因的,不但可以在整个应用中使用,还可以在Vuex Store 内部使用。
看看代码就明白了:
// 先定义选择器函数
export const language = (state) => state.userConfig.language;// 某个Action需要 language 属性
// 不推荐
[GET_GAMES]({ commit, rootState }) {
const lang = rootState.userConfig.language;
// Do stuff...
}
// 推荐
[GET_GAMES]({ commit, rootState }) {
const lang = language(rootState);
// Do stuff...
}
本文已经获得李中凯老师授权转发,其他人若有兴趣转载,请直接联系作者授权。
作者简介:
李中凯老师,8年前端开发,前端负责人,擅长JavaScript/Vue。
公众号:1024译站
掘金文章专栏:https://juejin.im/user/57c7cb8a0a2b58006b1b8666/posts
主要分享:Vue.js, JavaScript,CSS