又是一个阳光明媚,风和日丽的周末,有人陪女神去逛街,有人陪女神去看电影,小编却默默的拿出电脑。哈哈哈,不是小编屌丝,女神正坐在旁边玩手机(感受不是屌丝才怪)。javascript
这两天小编重读了一遍vue2.0官网的风格指南,整理了这九条关键规则。css
v-for设置键值
提到v-for
须要设置键值,许多人第一反应会从diff
算法的角度去讲缘由,我更喜欢举一个例子来演示一下缘由html
假设有这样的一个页面,页面的列表是经过遍历数组得来的,以下图所示前端
示例代码以下vue
<!--模板部分--> <div id="app"> <div v-for="item in arr"> {{item}} <input/> </div> <button @click="deleteData">删除第二个元素</button> </div> 复制代码
// js 部分 new Vue({ el: '#app', data() { return { arr: [1,2,3] } }, methods:{ deleteData() { this.arr.splice(1,1) } } }) 复制代码
如今须要删除第二个元素。下面咱们分别在渲染列表是 不使用key,使用索引做为key, 使用惟一值id做为key,看三种场景删除第二个元素以后的效果java
v-for
不使用key
点击查看代码演示v-for
使用索引做为key
点击查看代码演示
key
以后,与不使用key的效果同样,删除第二个元素以后,输入框前面的数字显示正确的,可是数字3后面的输入框的内容显示错了,应该显示 我是第三个v-for
使用惟一值id做为key
点击查看代码演示使用id做为key
,显示正确算法
为何v-for
须要设置key,缘由很简单。 对比数组 [1,2,3]和[1,3],咱们很容易发现删掉了2,可是计算机不是这样的逻辑数组
那么为何不能用索引做为key呢? 当删掉[1,2,3]中的2以后,数组的长度由3变成了2,那么原来数字3的索引就变成了数字2的索引了。bash
而对于使用id做为key,那么每条数据都有了惟一的标识,当删掉[{id:'1',value: 1},{id: '2',value: 2}, {id: '3', value:3}]
中的第二个,整个过程以下markdown
没得问题嘛!!!!
模板中的复杂逻辑使用计算属性代替
vue在模板可使用表达式是很是方便的,但表达式在设计之初是为了进行简单逻辑处理的,若是在模板中使用太多或太复杂的逻辑,会让模板的可读性和可维护性变得不好,整个模板显得很臃肿。
<!--v-if使用了一连串的条件判断,可读性比较差--> <button v-if=" user.roles && user.roles.includes('Workflowbeheer') && data.userId === user.id && data.status === 1 " > 删除 </button> 复制代码
<template> <button v-if="deletable"> 删除 </button> </template> <script> export default { computed: { // 判断是否能够删除 deletable() { const { data, user } = this // 若是当前用户不是流程管理员,则不能编辑 if (user.roles && user.roles.includes('Workflowbeheer')) { // 若是当前用户为流程发起者且状态为未启动,则能够删除 return data.userId === user.id && data.status === 1 } return false } } } </script> 复制代码
避免v-for与v-if混用
在开发vue项目中,你们可能会遇到这样的代码
<ul> <li v-for="item in list" v-if="item.visible" :key="item.id"> {{ item.name }} </li> </ul> 复制代码
若是在项目中启用了eslint
,则可能会看到下面这样的异常提示(须要启用eslint vue/no-use-v-if-with-v-for
规则)
The 'list' variable inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if'. 复制代码
在vue处理指令的时候,v-for
比v-if
会有更高的优先级,那么上述的代码用js能够模拟为
list.map(item => { if(item.visible) { return item.name } }) 复制代码
经过上述代码能够看到,即便大部分数据的visible都是false,也会将整个list所有遍历一次。若是每一次都须要遍历整个数组,将会影响速度,尤为是当之须要渲染很小一部分的时候。
对于上述的问题,可使用计算属性来处理
<ul> <li v-for="item in getList" :key="item.id"> {{ item.name }} </li> </ul> computed: { getList() { return this.list.filter(item => { return item.visible }) } } 复制代码
经过上述的代码,咱们能够得到如下好处
尽可能使用私有属性/方法
在开发vue组件的时候,咱们能够经过组件的ref
来调用组件对外提供的方法,可是一个组件内部有些方法是内部私有的,不该该被外部调用,但实际上js中并无像其余语言同样有私有方法(好比java
的private
),因此在js中通常约定使用_
开头的属性或者方法表示私有的。
{
// 公共的
selectRows(rows) {},
// 私有的 外部虽然能够调用到,可是由于是`_`开头,因此按照约定不该该去调用
_select(rows){}
}
复制代码
在vue中定义私有属性/方法又与js常规约定有所不一样。在Vue内部,已经使用了_
开头去定义Vue原型上面的私有属性/方法,若是在组件内上面继续使用_
开头去定义私有属性/方法可能会出现覆盖实例上面属性/方法的状况,好比下面这种状况:
methods: { // 初始化组件的数据方法 _init() { fetch().then(data => { }) } } 复制代码
上面的代码看似没有问题,实际上运行的时候会报错,由于_init
方法会覆盖Vue.prototype
上面的同名方法,以下图为Vue原型链的方法,第一个即是_init
在Vue2.0风格指南中,建议使用$_
来定义私有方法,能够确保不会和Vue自身发生冲突。修改上例为
methods: { // 初始化组件的数据方法 $_init() { fetch().then(data => { }) } } 复制代码
组件数据必须是一个函数,并返回一个对象
在说为何组件的数据必须返回一个函数以前,咱们先来了解一下js中的基本类型与引用类型。
在es2020发布了bigint类型以后,js中的基本类型一种包含七种,分别是
基本类型的特色包括
let a = 2 let b = a // 对a的值的修改,会在栈内存开辟新的空间,因此不会影响到b的值 a = 3 // 输出 3 2 console.log(a,b) // 不能给基本类型上面挂载新的属性 a.testProp = '挂载的属性' // 输出undefined console.log(a.testProp) 复制代码
Object
,Array
,Function
,RegExp
,Date
等等引用类型的特色包括
let obj1 = {a: 1, b: 2} let obj2 = obj1 // 由于引用类型的值是保存到堆内存的,obj1与obj2引用的是同一块堆内存空间,因此对obj1的值进行 // 修改,会直接影响到obj2的值 obj1.a = 3 // 输出 3 console.log(obj2.a) // 挂载新的属性 obj1.testProp = '挂载的新属性值' // 输出 "挂载的新属性值" console.log(obj1.testProp) 复制代码
经过上面的对比,我想你们其实也清楚了为何vue的数据必须返回一个函数了。
假设咱们如今开发了一个组件,组件上面的data是一个普通的对象,那么当咱们实例化多个组件的时候,全部的实例将共享引用同一个数据对象,任何一个实例对数据的修改都会影响到其余实例。而将组件上面的数据定义为一个函数以后,当实例化多个组件的时候,每一个实例经过调用 data 函数,从而返回初始数据的一个全新副本数据对象,这时候就避免了对象引用。
为组件样式设置做用域
在前端发展突飞猛进的今天,全部的一切都在飞速的发展,前端项目规模愈来愈大,而css做为一个只有全局做用域的语言,样式冲突会带来不少麻烦。JS语言模块已经标准化,CSS仍是在不断探索,同时这也是一个急需解决的问题。如今人们提出了许多为css添加做用域的解决方法,好比BEM样式规范,好比css module。
在Vue中,使用了经过给元素添加scoped attribute
的方式为css添加做用域,具体代码以下
<template> <button class="button">按钮</button> </template> <!--给style标签添加scoped属性--> <style scoped> .button { width: 50px; height: 40px; } </style> 复制代码
编译以后的结果以下
<!--html 添加了一个新属性 data-v-039c5b43,对于组件内的全部元素,都会添加同一个属性data-v-039c5b43,这样保证了同一个组件内全部元素都在同一个做用域内--> <button data-v-039c5b43="" class="button">按钮</button> 复制代码
/*经过为样式添加属性选择器,去限制样式的做用域*/ .button[data-v-039c5b43] { width: 50px; height: 40px; } 复制代码
虽然咱们建议为组件样式添加做用域,可是不必定必须使用vue提供的attribute scoped
,对于组件库之类可能须要在外部覆盖样式,若是使用attribute scoped
,由于属性名不肯定,且样式权重较高,致使样式覆盖很困难.
这时候更建议使用相似BEM之类的命名规范来约束,这让覆写内部样式更容易,使用了常人可理解的 class 名称且没有过高的选择器优先级,并且不太会致使冲突。好比element ui 和 vant 均使用了BEM
将复杂页面拆分红多个多个组件文件
你有没有见过一个Vue文件里面有一大坨密密麻麻的模板代码,模板代码里面还加载了大量的v-if
,v-for
,v-show
之类的指令,我不知道你看到以后感受怎么样,对于小编来讲,这无疑是地狱,各类逻辑耦合到一块儿,改bug比蜀道还要难 对于一个复杂的页面,咱们建议将页面按照模块/功能进行拆分,而后写成多个小的,单一的组件,而后在主入口文件中引用。好比,对于一个复杂的页面,咱们能够拆分红
header.vue
main.vue
footer.vue
三个文件,而后在三个文件内完成各自的逻辑,最后经过将三个组件都引入主入口文件,来实现页面的拼装。 这样作的好处包括
prop应该尽可能详细
对比下面的两段代码
// 第一段 export default { props:['status','data'] } // 第二段 export default { props:{ status: { type: Boolean, default: true }, data:{ type: Array, required: true } } } 复制代码
对比上面两段代码,经过第二段代码咱们能够很清楚的知道组件须要什么属性,属性的类型是什么,默认值是什么,是不是必须的,这样作的好处包括:
组件名应该由多个单词组成
对于组件名应该由多个单词组成的必要性,我想到了本身曾经见过的一段代码
<header class="header"> <!--栏目--> <ul> <li>首页</li> <li>关于</li> </ul> </header> 复制代码
看到这段代码,而后感受很正常,没啥毛病,而后我看了一眼界面,诶,为何header左侧有一个logo呢?我笑着说,这必定是样式里面加的咯,而后看了一眼样式,wtf,什么鬼,样式里面也没有加啊,这是怎么作到的,好神奇。后来就看到了这样的一段代码
import Header from '@/components/header' export default { components: { Header } } 复制代码
个人四十米长大砍刀呢!!!!!!
为何组件名应该又多个单词组成,由于这样作能够避免跟现有的以及将来的 HTML 元素相冲突。更关键的是,这样作不会被打,固然你也能够作,祝你好运,(手动调皮)。
本文主要参考了:
感谢做者,如侵权当即删除。若是您以为本文对您有帮助,但愿您能够给小编一个赞,不胜感激。小手一赞,艳遇不断,哈哈哈哈哈