阵阵键盘声,隐隐测试言。 产品不稳定,今夜无人还。javascript
在开发Vue
的过程当中,咱们常常会遇到一些这样那样的问题,而后要卡好半天,等问题解决了才发现原来一些细节知识点仍是没有掌握好。今天小编就整理了几个在项目中会用到的一些实战技巧点,但愿能够帮助到正在努力赚钱的你。江湖规矩,先赞后看,艳遇不断。css
阅读小编近期的热门
Vue
相关文章,我是子君,每周一,不见不散前端
实战技巧,Vue原来还能够这样写 获赞 2600+vue
绝对干货~!学会这些Vue小技巧,能够早点下班和女神约会了 获赞 1200+java
我在项目中是这样配置Vue的 获赞 1000+git
前方高能,这是最新的一波Vue实战技巧,不用则已,一用惊人 获赞 1000+github
学会使用Vue JSX,一车老干妈都是你的 获赞700+web
看到赚到!重读vue2.0风格指南,我整理了这些关键规则 获赞 150+算法
前几天有朋友给我发了一段代码,而后说Vue
有bug
,他明明写的没问题,为啥数据就不响应呢,必定是Vue
的bug
?我感受他比尤雨溪要牛逼,高攀不起,就没有理他了。可是确实有时候咱们在开发时候会遇到数据不响应的状况,那怎么办呢?好比下面这段代码:element-ui
<template>
<div> <div> <span>用户名: {{ userInfo.name }}</span> <span>用户性别: {{ userInfo.sex }}</span> <span v-if="userInfo.officialAccount"> 公众号: {{ userInfo.officialAccount }} </span> </div> <button @click="handleAddOfficialAccount">添加公众号</button> </div> </template> <script> export default { data() { return { userInfo: { name: '子君', sex: '男' } } }, methods: { // 在这里添加用户的公众号 handleAddOfficialAccount() { this.userInfo.officialAccount = '前端有的玩' } } } </script> 复制代码
在上面的代码中,咱们但愿给用户信息里面添加公众号属性,可是经过this.userInfo.officialAccount = '前端有的玩'
添加以后,并无生效,这是为何呢?
这是由于在Vue
内部,数据响应是经过使用Object.definePrototype
监听对象的每个键的getter
,setter
方法来实现的,但经过这种方法只能监听到已有属性,新增的属性是没法监听到的,但我就是想监听,小编你说咋办吧。下面小编提供了四种方式,若是有更多方式,欢迎下方评论区告诉我。
data
中定义好好比上面的公众号,我能够提早在userInfo
里面定义好,这样就不是新增属性了,就像下面这样
data() {
return { userInfo: { name: '子君', sex: '男', // 我先提早定义好 officialAccount: '' } } } 复制代码
userInfo
虽然没法给userInfo
里面添加新的属性,可是由于userInfo
已经定义好了,因此我直接修改userInfo
的值不就能够了么,因此也能够像下面这样写
this.userInfo = {
// 将原来的userInfo 经过扩展运算法复制到新的对象里面 ...this.userInfo, // 添加新属性 officialAccount: '前端有的玩' } 复制代码
Vue.set
其实上面两种方法都有点取巧的嫌疑,其实对于新增属性,Vue
官方专门提供了一个新的方法Vue.set
用来解决新增属性没法触发数据响应。
Vue.set 方法定义
/** * target 要修改的对象 * prpertyName 要添加的属性名称 * value 要添加的属性值 */ Vue.set( target, propertyName, value ) 复制代码
上面的代码使用Vue.set
能够修改成
import Vue from 'vue'
// 在这里添加用户的公众号 handleAddOfficialAccount() { Vue.set(this.userInfo,'officialAccount', '前端有的玩') } 复制代码
可是每次要用到set
方法的时候,还要把Vue
引入进来,好麻烦,因此为了简便起见,Vue
又将set
方法挂载到了Vue
的原型链上了,即Vue.prototype.$set = Vue.set
,因此在Vue
组件内部能够直接使用this.$set
代替Vue.set
this.$set(this.userInfo,'officialAccount', '前端有的玩')
复制代码
小编发现有许多同窗不知道何时应该用Vue.set
,其实只有当你要赋值的属性尚未定义的时候须要使用Vue,set
,其余时候通常不会须要使用。
$forceUpdate
我以为$forceUpdate
的存在,让许多前端开发者不会再去注意数据双向绑定的原理,由于不论何时,反正我修改了data
以后,调用一下$forceUpdate
就会让Vue
组件从新渲染,bug
是不会存在的。可是实际上这个方法并不建议使用,由于它会引发许多没必要要的性能消耗。
其实不只仅是对象,数组也存在数据修改以后不响应的状况,好比下面这段代码
<template> <div> <ul> <li v-for="item in list" :key="item"> {{ item }} </li> </ul> <button @click="handleChangeName">修更名称</button> </div> </template> <script> export default { data() { return { list: ['张三', '李四'] } }, methods: { // 修改用户名称 handleChangeName() { this.list[0] = '王五' } } } </script> 复制代码复制代码
上面的代码但愿将张三的名字修改成王五,实际上这个修改并不能生效,这是由于Vue
不能检测到如下变更的数组:
this.list[index] = newValue
length
属性,例如:
this.list.length = 0
因此在上例中经过this.list[0] = '王五'
是没法触发数据响应的,那应该怎么办呢?像上面提到的Vue.set
和$forceUpdate
均可以解决这个问题,好比Vue.set
能够这样写
Vue.set(this.list,0,'王五')
复制代码
除了那些方法以外,Vue
还针对数组提供了变异方法
在操做数组的时候,咱们通常会用到数据提供的许多方法,好比push
,pop
,splice
等等,在Vue
中调用数组上面提供的这些方法修改数组的值是能够触发数据响应的,好比上面的代码改成如下代码便可触发数据响应
this.list.splice(0,1,'王五')
复制代码
实际上,若是Vue
仅仅依赖getter
与setter
,是没法作到在数组调用push
,pop
等方法时候触发数据响应的,所以Vue
其实是经过劫持这些方法,对这些方法进行包装变异来实现的。
Vue
对数组的如下方法进行的包装变异:
因此在操做数组的时候,调用上面这些方法是能够保证数据能够正常响应,下面是Vue
源码中包装数组方法的代码:
var original = arrayProto[method];
def(arrayMethods, method, function mutator () { // 将 arguments 转换为数组 var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; var result = original.apply(this, args); // 这儿的用法同dependArray(value),就是为了取得dep var ob = this.__ob__; var inserted; switch (method) { case 'push': case 'unshift': inserted = args; break case 'splice': inserted = args.slice(2); break } // 若是有新的数据插入,则插入的数据也要进行一个响应式 if (inserted) { ob.observeArray(inserted); } // 通知依赖进行更新 ob.dep.notify(); return result }); 复制代码
filter
更简单filter
简化逻辑我想把时间戳显示成yyyy-MM-DD HH:mm:ss
的格式怎么办?是须要在代码中先将日期格式化以后,再渲染到模板吗?就像下面这样
<template> <div> {{ dateStr }} <ul> <li v-for="(item, index) in getList" :key="index"> {{ item.date }} </li> </ul> </div> </template> <script> import { format } from '@/utils/date' export default { data() { return { date: Date.now(), list: [ { date: Date.now() } ] } }, computed: { dateStr() { return format(this.date, 'yyyy-MM-DD HH:mm:ss') }, getList() { return this.list.map(item => { return { ...item, date: format(item.date, 'yyyy-MM-DD HH:mm:ss') } }) } } } </script> 复制代码复制代码
像上面的写法,针对每个日期字段都须要调用format
,而后经过计算属性进行转换?这时候能够考虑使用Vue
提供的filter
去简化
<template>
<div>
<!--使用过滤器-->
{{ dateStr | formatDate }}
<ul>
<li v-for="(item, index) in list" :key="index">
<!--在v-for中使用过滤器-->
{{ item.date | formatDate }}
</li>
</ul>
</div>
</template>
<script>
import { format } from '@/utils/date'
export default {
filters: {
formatDate(value) {
return format(value, 'yyyy-MM-DD HH:mm:ss')
}
},
data() {
return {
date: Date.now(),
list: [
{
date: Date.now()
}
]
}
}
}
</script>
复制代码
经过上面的修改是否是就简单多了
filter
有些过滤器使用的很频繁,好比上面提到的日期过滤器,在不少地方都要使用,这时候若是在每个要用到的组件里面都去定义一遍,就显得有些多余了,这时候就能够考虑Vue.filter
注册全局过滤器
对于全局过滤器,通常建议在项目里面添加filters
目录,而后在filters目录里面添加
// filters\index.js
import Vue from 'vue' import { format } from '@/utils/date' Vue.filter('formatDate', value => { return format(value, 'yyyy-MM-DD HH:mm:ss') }) 复制代码
而后将filters
里面的文件引入到main.js
里面,这时候就能够在组件里面直接用了,好比将前面的代码能够修改成
<template>
<div>
<!--使用过滤器-->
{{ dateStr | formatDate }}
<ul>
<li v-for="(item, index) in list" :key="index">
<!--在v-for中使用过滤器-->
{{ item.date | formatDate }}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
date: Date.now(),
list: [
{
date: Date.now()
}
]
}
}
}
</script>
复制代码
是否是更简单了
在使用一些UI
框架的时候,常常须要使用Vue.use
来安装, 好比使用element-ui
时候,常常会这样写:
import Vue from 'vue';
import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI,{size: 'small'}); 复制代码
使用了Vue.use
以后,element-ui
就能够直接在组件里面使用了,好神奇哦(呸,娘炮)。接下来咱们实现一个简化版的element
来看如何去安装。
Vue.use
的用法Vue.use
是一个全局的方法,它须要在你调用 new Vue()
启动应用以前完成,Vue.use
的参数以下
/** * plugin: 要安装的插件 如 ElementUI * options: 插件的配置信息 如 {size: 'small'} */ Vue.use(plugin, options) 复制代码
element-ui
的安装逻辑想一下,使用Vue.use(ElementUI,{size: 'small'})
以后咱们能够用到哪些element-ui
提供的东西
element-ui
的组件,不须要再
import
v-loading
指令
this.$loading
在组件里面显示
loading
// 这个是一个按钮组件
import Button from '@/components/button' // loading 指令 import loadingDirective from '@/components/loading/directive' // loading 方法 import loadingMethod from '@/components/loading' export default { /** * Vue.use 须要插件提供一个install方法 * @param {*} Vue Vue * @param {*} options 插件配置信息 */ install(Vue, options) { console.log(options) // 将组件经过Vue.components 进行注册 Vue.components(Button.name, Button) // 注册全局指令 Vue.directive('loading', loadingDirective) // 将loadingMethod 挂载到 Vue原型链上面,方便调用 Vue.prototype.$loading = loadingMethod } } 复制代码
经过上面的代码,已经实现了一个丐版的element-ui
插件,这时候就能够在main.js
里面经过Vue.use
进行插件安装了。你们可能会有疑问,为何我要用这种写法,不用这种写法我照样能够实现功能啊。小编认为这种写法有两个优点
Vue.use
在安装插件的时候,会对插件进行缓存,即一个插件若是安装屡次,实际上只会在第一次安装时生效。
Vue.prototype
上实现。
element-ui
当一个 Vue 实例被建立时,它将 data
对象中的全部的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。可是这个过程其实是比较消耗性能的,因此对于一些有大量数据但只是展现的界面来讲,并不须要将property
加入到响应式系统中,这样能够提升渲染性能,怎么作呢,你须要了解一下Object.freeze
。
在Vue
官网中,有这样一段话:这里惟一的例外是使用 Object.freeze()
,这会阻止修改现有的 property,也意味着响应系统没法再追踪变化。这段话的意思是,若是咱们的数据使用了Object.freeze
,就可让数据脱离响应式系统,那么该如何作呢?
好比下面这个表格,由于只是渲染数据,这时候咱们就能够经过Object.freeze
来优化性能
<template>
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="date" label="日期" width="180" />
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="address" label="地址" />
</el-table>
</template>
<script>
export default {
data() {
const data = Array(1000)
.fill(1)
.map((item, index) => {
return {
date: '2020-07-11',
name: `子君${index}`,
address: '大西安'
}
})
return {
// 在这里咱们用了Object.freeze
tableData: Object.freeze(data)
}
}
}
</script>
复制代码
有的同窗可能会有疑问,若是我这个表格的数据是滚动加载的,你这样写我不就无法再给tableData
添加数据了吗?是,确实没办法去添加数据了,但仍是有办法解决的,好比像下面这样
export default {
data() { return { tableData: [] } }, created() { setInterval(() => { const data = Array(1000) .fill(1) .map((item, index) => { // 虽然不能冻结整个数组,可是能够冻结每一项数据 return Object.freeze({ date: '2020-07-11', name: `子君${index}`, address: '大西安' }) }) this.tableData = this.tableData.concat(data) }, 2000) } } 复制代码
合理的使用Object.freeze
,是能够节省很多渲染性能,特别对于IE浏览器,效果仍是很明显的,赶快去试试吧。
最后若是你如今须要开发移动端项目,能够了解一下小编整理的一个开箱即用框架 vue-vant-base,也许能够帮到你哦
不要吹灭你的灵感和你的想象力; 不要成为你的模型的奴隶。 ——文森特・梵高
本文使用 mdnice 排版