重读 vue2.0 风格指南,我整理了这些关键规则
又是一个阳光明媚,风和日丽的周末,有人陪女神去逛街,有人陪女神去看电影,小编却默默的拿出电脑。哈哈哈,不是小编屌丝,女神正坐在旁边玩手机(感觉不是屌丝才怪)。
这两天小编重读了一遍vue2.0官网的风格指南,整理了这九条关键规则。
v-for设置键值
提到v-for
需要设置键值,许多人第一反应会从diff
算法的角度去讲原因,我更喜欢举一个例子来演示一下原因
假设有这样的一个页面,页面的列表是通过遍历数组得来的,如下图所示
示例代码如下
现在需要删除第二个元素。下面我们分别在渲染列表是 不使用key,使用索引作为key, 使用唯一值id作为key,看三种场景删除第二个元素之后的效果
v-for
不使用key
点击查看代码演示
可以看到,不使用key,删除第二个元素之后,输入框前面的数字显示正确的,但是数字3后面的输入框的内容显示错了,应该显示 我是第三个
v-for
使用索引作为key
点击查看代码演示
可以看到,使用索引作为key
之后,与不使用key的效果一样,删除第二个元素之后,输入框前面的数字显示正确的,但是数字3后面的输入框的内容显示错了,应该显示 我是第三个
v-for
使用唯一值id作为key
点击查看代码演示
使用id作为key
,显示正确
为什么v-for
需要设置key,原因很简单。
对比数组 [1,2,3]和[1,3],我们很容易发现删掉了2,但是计算机不是这样的逻辑
计算机对比新旧数组,发现1===1,保持不变
然后再对比2,发现2变成了3,那么就把2修改为3,原来第二行的元素都可以复用,只把数字改一下就可以了
然后在对比3与undefined,发现3被删了,索引把第三行的元素删掉
那么为什么不能用索引作为key呢?
当删掉[1,2,3]中的2之后,数组的长度由3变成了2,那么原来数字3的索引就变成了数字2的索引了。
计算机对比key为0的值,发现都是1,保持不变
计算机对比key为1的值,发现从2变成了3,元素复用, 修改元素上面的文字
计算机对比key为2的值,发现被删掉了,所以删掉第三行元素
而对于使用id作为key,那么每条数据都有了唯一的标识,当删掉[{id:'1',value: 1},{id: '2',value: 2}, {id: '3', value:3}]
中的第二个,整个过程如下
计算机取出新数据第一项的id,然后在原来数据里面寻找,发现存在相同id的数据,而且数据没有变化,所以保持不变
计算机继续取第二项的id,发现是3,然后从原来数据里面也找到了3,所以3保留
这时候旧数据里面剩了id为2的数据,而新的里面没有了,所以删掉。
没得问题嘛!!!!
模板中的复杂逻辑使用计算属性代替
vue在模板可以使用表达式是非常方便的,但表达式在设计之初是为了进行简单逻辑处理的,如果在模板中使用太多或太复杂的逻辑,会让模板的可读性和可维护性变得很差,整个模板显得很臃肿。
Bad
Good
避免v-for与v-if混用
永远不要将v-for和v-if同时用在同一个元素上。
在开发vue项目中,大家可能会遇到这样的代码
如果在项目中启用了eslint
,则可能会看到下面这样的异常提示(需要启用eslint vue/no-use-v-if-with-v-for
规则)
在vue处理指令的时候,v-for
比v-if
会有更高的优先级,那么上述的代码用js可以模拟为
通过上述代码可以看到,即使大部分数据的visible都是false,也会将整个list全部遍历一次。如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候。
对于上述的问题,可以使用计算属性来处理
通过上述的代码,我们可以获得以下好处
过滤后的列表只会在 list 数组发生相关变化时才被重新运算,过滤更高效。
使用 v-for="item in list" 之后,我们在渲染的时候只遍历需要显示的数据,渲染更高效。
解耦渲染层的逻辑,可维护性比较高。
尽量使用私有属性/方法
在开发vue组件的时候,我们可以通过组件的ref
来调用组件对外提供的方法,但是一个组件内部有些方法是内部私有的,不应该被外部调用,但实际上js中并没有像其他语言一样有私有方法(比如java
的private
),所以在js中一般约定使用_
开头的属性或者方法表示私有的。
在vue中定义私有属性/方法又与js常规约定有所不同。在Vue内部,已经使用了_
开头去定义Vue原型上面的私有属性/方法,如果在组件内上面继续使用_
开头去定义私有属性/方法可能会出现覆盖实例上面属性/方法的情况,比如下面这种情况:
上面的代码看似没有问题,实际上运行的时候会报错,因为_init
方法会覆盖Vue.prototype
上面的同名方法,如下图为Vue原型链的方法,第一个便是_init
在Vue2.0风格指南中,建议使用$_
来定义私有方法,可以确保不会和Vue自身发生冲突。修改上例为
组件数据必须是一个函数,并返回一个对象
在说为什么组件的数据必须返回一个函数之前,我们先来了解一下js中的基本类型与引用类型。
基本类型
在es2020发布了bigint类型之后,js中的基本类型一种包含七种,分别是
string 字符类型
number 数值类型
boolean 布尔类型
undefined
null
Symbol
Bigint
基本类型的特点包括
基本类型的值是存放到栈内存里面的
基本类型的比较是它们的值的比较
基本类型的值是不可变的,对值的修改会在栈内存中开辟新的空间
基本类型上面不能挂载新的属性
引用类型
在js中,除了八种基本类型,其他都属于引用类型,像Object
,Array
,Function
,RegExp
,Date
等等
引用类型的特点包括
引用类型的值保存在堆内存中,而引用保存到栈内存中
引用类型的值是按引用访问的
引用类型的值是可变的(在堆内存中直接修改)
引用类型上面可以挂载新的属性
通过上面的对比,我想大家其实也清楚了为什么vue的数据必须返回一个函数了。
假设我们现在开发了一个组件,组件上面的data是一个普通的对象,那么当我们实例化多个组件的时候,所有的实例将共享引用同一个数据对象,任何一个实例对数据的修改都会影响到其他实例。而将组件上面的数据定义为一个函数之后,当实例化多个组件的时候,每个实例通过调用 data 函数,从而返回初始数据的一个全新副本数据对象,这时候就避免了对象引用。
为组件样式设置作用域
在前端发展日新月异的今天,所有的一切都在飞速的发展,前端项目规模越来越大,而css作为一个只有全局作用域的语言,样式冲突会带来很多麻烦。JS语言模块已经标准化,CSS还是在不断探索,同时这也是一个急需解决的问题。现在人们提出了许多为css添加作用域的解决方法,比如BEM样式规范,比如css module。
在Vue中,使用了通过给元素添加scoped attribute
的方式为css添加作用域,具体代码如下
编译之后的结果如下
虽然我们建议为组件样式添加作用域,但是不一定必须使用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应该尽量详细
对比下面的两段代码
对比上面两段代码,通过第二段代码我们可以很清楚的知道组件需要什么属性,属性的类型是什么,默认值是什么,是否是必须的,这样做的好处包括:
详细的定义了属性的各方面信息,所以很容易看懂组件的用法;
在开发环境下,如果向一个组件提供格式不正确的 prop,Vue将会得到警告,可以更快的发现潜在的问题。
组件名应该由多个单词组成
对于组件名应该由多个单词组成的必要性,我想到了自己曾经见过的一段代码
看到这段代码,然后感觉很正常,没啥毛病,然后我看了一眼界面,诶,为什么header左侧有一个logo呢?我笑着说,这一定是样式里面加的咯,然后看了一眼样式,wtf,什么鬼,样式里面也没有加啊,这是怎么做到的,好神奇。后来就看到了这样的一段代码
我的四十米长大砍刀呢!!!!!!
为什么组件名应该又多个单词组成,因为这样做可以避免跟现有的以及未来的 HTML 元素相冲突。更关键的是,这样做不会被打,当然你也可以不这么做,祝你好运,(手动调皮)。
版权声明: 本文为 InfoQ 作者【前端有的玩】的原创文章。
原文链接:【http://xie.infoq.cn/article/4a16d0ebf477724138f0e8b7f】。文章转载请联系作者。
评论