一、数据不响应,可能是用法有问题

比如下面这段代码:

<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方法来实现的,但通过这种方法只能监听到已有属性,新增的属性是无法监听到的,但我就是想监听,小编你说咋办吧。下面小编提供了四种方式:

1. 将本来要新增的属性提前在data中定义好

比如上面的公众号,我可以提前在userInfo里面定义好,这样就不是新增属性了,就像下面这样

data() {return {userInfo: {name: '子君',sex: '男',// 我先提前定义好officialAccount: ''}}}

2. 直接替换掉userInfo

虽然无法给userInfo里面添加新的属性,但是因为userInfo已经定义好了,所以我直接修改userInfo的值不就可以了么,所以也可以像下面这样写

this.userInfo = {// 将原来的userInfo 通过扩展运算法复制到新的对象里面...this.userInfo,// 添加新属性officialAccount: '前端有的玩'
}

3. 使用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,其他时候一般不会需要使用。

4. 使用$forceUpdate

我觉得$forceUpdate的存在,让许多前端开发者不会再去注意数据双向绑定的原理,因为不论什么时候,反正我修改了data之后,调用一下$forceUpdate就会让Vue组件重新渲染,bug是不会存在的。但是实际上这个方法并不建议使用,因为它会引起许多不必要的性能消耗。

5、针对数组的特定方式

其实不仅仅是对象,数组也存在数据修改之后不响应的情况,比如下面这段代码

<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不能检测到以下变动的数组:

  1. 当你利用索引直接设置一个项时,例如: this.list[index] = newValue

  2. 修改数组的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还针对数组提供了变异方法

在操作数组的时候,我们一般会用到数据提供的许多方法,比如push,pop,splice等等,在Vue中调用数组上面提供的这些方法修改数组的值是可以触发数据响应的,比如上面的代码改为以下代码即可触发数据响应

this.list.splice(0,1,'王五')

实际上,如果Vue仅仅依赖gettersetter,是无法做到在数组调用push,pop等方法时候触发数据响应的,因此Vue实际上是通过劫持这些方法,对这些方法进行包装变异来实现的。

Vue对数组的以下方法进行的包装变异:

  • push

  • pop

  • shift

  • unshift

  • splice

  • sort

  • reverse

所以在操作数组的时候,调用上面这些方法是可以保证数据可以正常响应,下面是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),就是为了取得depvar ob = this.__ob__;var inserted;switch (method) {case 'push':case 'unshift':inserted = args;breakcase 'splice':inserted = args.slice(2);break}// 如果有新的数据插入,则插入的数据也要进行一个响应式if (inserted) { ob.observeArray(inserted); }// 通知依赖进行更新ob.dep.notify();return result});

二、文本格式化,filter更简单

1、使用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>

通过上面的修改是不是就简单多了

2、注册全局filter

有些过滤器使用的很频繁,比如上面提到的日期过滤器,在很多地方都要使用,这时候如果在每一个要用到的组件里面都去定义一遍,就显得有些多余了,这时候就可以考虑Vue.filter注册全局过滤器

对于全局过滤器,一般建议在项目里面添加filters目录,然后在filters目录里面添加

// filters\index.jsimport 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>

三、了解Vue.use的用法

Vue.use是一个全局的方法,它需要在你调用 new Vue() 启动应用之前完成,Vue.use的参数如下

/**
* plugin: 要安装的插件 如 ElementUI
* options: 插件的配置信息 如 {size: 'small'}
*/
Vue.use(plugin, options)
复制代码

四、提高Vue渲染性能,了解一下Object.freeze

当一个 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.freezetableData: 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项目更丝滑的几个小技巧相关推荐

  1. Vue项目更丝滑的几个小技巧

    数据不响应,可能是用法有问题: 比如下面这段代码: <template><div><div><span>用户名: {{ userInfo.name }} ...

  2. 让你的网页更丝滑(全)

    这篇文章是2019年5月11号,我在上海FDConf2019上的分享整理. 演讲主题:[让你的网页更丝滑] 时间:2019年5月11日(下午) 地点:上海 - FDCon2019 - B会场(全栈&a ...

  3. java安装好了打不开机_劝告大家!早餐打豆浆,黄豆泡好直接打不对,教你1招,豆浆香浓更丝滑...

    " 导语:打豆浆泡好直接打?难怪豆浆没有早餐店的好喝,教你正确做法 适当吃豆制品对于大人小孩都有好处,豆浆作为其中的一种,更是我家早餐常会喝的,香浓顺滑的豆浆,搭配油条或者是饼,美好的早餐便 ...

  4. Mac 让程序坞更丝滑

    Mac在设置自动隐藏和显示程序坞后,鼠标滑到程序坞位置,默认有1秒的延迟才会出现. 为了让这一操作更丝滑,可以在终端中使用如下命令: defaults write com.apple.Dock aut ...

  5. 让你的网页更丝滑(一)

    前段时间,我将精力专注在Web性能领域:在这个领域下有个重要的课题是如何让网页更丝滑(流畅). 想让网页变得丝滑,首先,我们需要一个标准来判断什么样的网页是丝滑的:其次,我们要准确的测量出网页的性能数 ...

  6. 让你的app体验更丝滑的11种方法!冲击手机应用榜单Top3指日可待

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由WeTest质量开放平台团队 发表于云+社区专栏 一款app除了要有令人惊叹的功能和令人发指交互之外,在性能上也应该追求丝滑的要求,这 ...

  7. 这样设置过渡动画,让你的Android手机变得更丝滑

    前言 通过合理的设置安卓中过渡动画的缩放速度,可以让安卓手机中窗口的切换更自然.更流畅,操作上感觉更加的丝滑.安卓手机上一般有窗口动画缩放(window_animation_scale).过渡动画缩放 ...

  8. Unity简单几行代码让玩家水平移动更丝滑真实

    可以先来看看基础的移动代码,接收玩家的输入,然后赋予刚体速度. 但是这种写法存在几个问题,下面一一纠正. 首先,如果直接改变刚体的速度,那么可能会出现穿墙的问题. 而且没有一种从速度0到缓慢加速的过程 ...

  9. Eclipse 项目导航字体设置 左侧树字体 小技巧

    在解压的文件下 E:\eclipse\plugins\org.eclipse.ui.themes_1.2.0.v20170517-0622\css\dark 找到  e4-dark_basestyle ...

最新文章

  1. nagios插件之登陆防火墙实现session监控
  2. 【codeforces】【比赛题解】#940 CF Round #466 (Div. 2)
  3. ZooKeeper编程
  4. [NPUCTF2020]Mersenne twister
  5. centos7 dns配置_Centos7.7 安装FreeIPA (三)
  6. ASP.NET之SOAP的发送、接收与处理类 [转载]
  7. HDU - 6183 Color it(动态开点线段树/树状数组套动态开点线段树)
  8. 【转】 NSArray copy 问题
  9. flutter闪屏过渡动画,闪光占位动画
  10. java转换字符集_Java字符集转换解释
  11. SQL实战之获取所有部门当前manager当前的薪水
  12. 数据库的时间格式(毫秒表示)
  13. winpe 卡巴斯基本升级内部错误
  14. PHP读取Excel数据
  15. qt 中获取摄像头视屏并传输
  16. ADB 学习(4):adb shell (上)
  17. “云桥”通往存储中心极速世界的通道
  18. 一天天学WG--第一天
  19. STM32按键总结(低电平有效及上升沿有效)
  20. 计算机实训安全教育,暑期实践 | 计算机学院举行暑期社会实践动员暨安全教育大会...

热门文章

  1. Python015面向对象之类和对象
  2. 上私户“低首付”蛋蛋订车超赞!!
  3. Stream.iterate
  4. 内存条的主要技术指标
  5. 推荐一款非Win7下专用的“任务栏图标收纳”工具——TrayApp(转自:http://www.ibobosky.com/my-quick-start-tool-trayapp.htm)...
  6. 蓝桥杯2019年真题演练——4、 迷宫(JavaA组)
  7. 云里黑白21——Ti的软件不是你想用就能用的—ccs6.0(code composer studio)中文帐户名改英文
  8. HDRsoft Photomatix Pro图形工具
  9. iOS AVPlayer使用总结
  10. 关于VSFTPD匿名用户文件上传权限的问题