nextTick()

在jQuery中,如果我们要生成一个ul-li的列表元素,我们也不会在循环体中每生成一个li就将它插入到ul中,而是在循环体内拼接每个li,待循环体结束后,再一并添加到ul元素上进行视图渲染。这样是为了避免页面不断的进行重排和重绘,优化页面性能。

var list = [1,2,3,4,5,6]

// bad
for (var i = 0; i < list.length; i++) {
$("<li></li>").text(list[i]).appendTo("#one")
} // good
var temp = ""
for (var i = 0; i < list.length; i++) {
temp += `<li>${list[i]}</li>`
}
$("#two").append(temp)

同样,在Vue中,不可能监控到一个数据更新就马上去刷新视图,而是异步执行 DOM 更新。

当观察到数据变化,Vue 会开启一个队列,用来缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。然后,在下一个的事件循环前的“tick”中,Vue 再使用刷新后队列中的数据去执行渲染工作。这种使用队列并在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的,很大的提升了页面性能。

所以当我们在this.someData = newValue时,并没有马上在页面中渲染newValue。所以如果此时我们从DOM元素中获取相应的值是没有改变的。

<div id="tick">
<p ref="msg">{{ msg }}</p>
<button @click="updateMsg">更新msg</button>
</div>
var vm = new Vue({
el: "#tick",
data: {
msg: 123
},
methods: {
updateMsg() {
this.msg = 456;
console.log("this.msg",this.msg) // 456 数值是已更新
console.log("msg.textContent", this.$refs.msg.textContent) // 123 视图未更新
}
}
})

如果实际需求确实需要操作数据变化后相关的DOM,VUE提供了nextTick( callback )方法来执行DOM渲染完成后的回调。可以使用全局的Vue.nextTick( callback ),也可以使用实例对象的提供的this.$nextTick( callback )

上面的例子改写下:

var vm = new Vue({
el: "#tick",
data: {
msg: 123
},
methods: {
updateMsg() {
this.msg = 456;
console.log("this.msg",this.msg) // 456 数值是已更新
console.log("msg.textContent", this.$refs.msg.textContent) // 123 视图未更新
this.$nextTick(() => {
console.log("nextTick", this.$refs.msg.textContent) // 456 此时视图已更新
})
}
}
})

现在,回头再仔细回味下解释vue文档中的异步更新队列中这段解释:

只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。

同一个数值在同一事件中被多次改变,队列中只会保留最后值用来执行视图更新,并且执行页面渲染时机是当前事件执行结束后。

我们验证下:


var vm = new Vue({
el: "#tick",
data: {
msg: 123
},
methods: {
updateMsg() {
this.msg = 456;
console.log("first_this.msg",this.msg)
console.log("first_this.$refs.msg.textContent", this.$refs.msg.textContent)
this.$nextTick(() => {
console.log("first_nextTick", this.$refs.msg.textContent)
}) for (let i=0; i < 5000; i++) {
console.log('i')
} this.msg = 789;
console.log("second_this.msg",this.msg)
console.log("second_this.$refs.msg.textContent", this.$refs.msg.textContent)
this.$nextTick(() => {
console.log("second_nextTick", this.$refs.msg.textContent)
})
}
}
})
first_this.msg 456
first_this.$refs.msg.textContent 123
5000 i
second_this.msg 789
second_this.$refs.msg.textContent 123
first_nextTick 789
second_nextTick 789

观察页面,并没有出现456后再变成789,而是直接变成789,两次的赋值只取了最后一次数值用来渲染,并且两次nextTick回调打印的都是同一个值。所以页面的渲染是在整个updateMsg事件执行后进行的。

vue-learning:11 -js-nextTick()的更多相关文章

  1. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十五 ║Vue基础:JS面向对象&字面量& this字

    缘起 书接上文<从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十四 ║ VUE 计划书 & 我的前后端开发简史>,昨天咱们说到了以我的经历说明的web开发经历的 ...

  2. vue初学:基础概念

    一.vue使用步骤: 1.引包vue.js 2.html中写要操作的DOM节点 3.创建vue对象:new Vue({options}); 4.配置options:el:(要操作的对象,用选择器,同j ...

  3. Vue源码解析之nextTick

    Vue源码解析之nextTick 前言 nextTick是Vue的一个核心功能,在Vue内部实现中也经常用到nextTick.但是,很多新手不理解nextTick的原理,甚至不清楚nextTick的作 ...

  4. vue中config/index.js:配置的详细理解

    当我们需要和后台分离部署的时候,必须配置config/index.js: 用vue-cli 自动构建的目录里面  (环境变量及其基本变量的配置) var path = require('path') ...

  5. vue-learning:22 - js - directives

    directives 在讲解视图层指令时,我们讲到ref特性,使用它我们可以获取当前DOM元素对象,以便执行相关操作. <div id="app"> <input ...

  6. vue开发:前端项目模板

    简介 vue-cli创建vue项目,整合vuex.vue-router.axios.element-ui 项目模板下载地址 创建项目 使用vue-cli创建项目,功能选择:Babel.Router.v ...

  7. iosselect:一个js picker项目,在H5中实现IOS的select下拉框效果

    具体文档和demo可以访问github:https://github.com/zhoushengmufc/iosselect 移动端浏览器对于select的展示样式是不一致的,ios下是类似原生的pi ...

  8. iosselect:一个js picker项目,在H5中实现IOS的下拉效果

    iosselect是在webapp下的一个picker组件,可以轻松实现各类选择器效果.比如地区选择 时间选择 日期选择等. 下面是一个地址选择器demo截图,可以访问:http://zhoushen ...

  9. Javascript模块化编程(三):require.js的用法

    Javascript模块化编程(三):require.js的用法 原文地址:http://www.ruanyifeng.com/blog/2012/11/require_js.html 作者: 阮一峰 ...

  10. JS组件系列——开源免费图表组件:Chart.js

    前言:最近被开源免费得有点上火了,各种组件首先想到的就是是开源否.是否免费.是否和bootstrap风格一致.想着以后做报表肯定要用到图表组件的,于是在Bootstrap中文网上面找到了Chart.j ...

随机推荐

  1. docker出现如下错误:Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

    在docker中配置deepo时出现了错误: 在出现这个错误之前,我是先用如下命令查看NVIDIA-docker是否安装成功. docker run --runtime=nvidia --rm nvi ...

  2. Git同步Python代码

    之前我们都是将代码保存到本地目录, 然后再上传到Git中,但如果针对在pycharm中的代码,就要换另一种方式了,下面简单介绍一下. 1.打开pycharm主界面,选择菜单栏VCS---checkou ...

  3. nginx 做反向代理

    1.Nginx的常用配置大家可以去搜一下,有很多优秀的博客,我这篇文章要实现的需求是: a.根据访问的域名不同,跳转到不同的项目(html首页,80端口) b.拦截访问中所有带有api的请求,转发到后 ...

  4. 微信小程序中支持es7的async语法

    最近在原生的微信小程序项目中需要把原来es6的promise方法改成es7的async await,这样代码看起来更直观,也方便以后的兄弟维护,但是改了代码之后项目就报错了. 提示的错误是:regen ...

  5. iOS Animation 主流炫酷动画框架(特效)收集整理 #91

    https://github.com/sxyx2008/DevArticles/issues/91

  6. 自定义View系列教程08--滑动冲突的产生及其处理

    深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...

  7. 4.2.1 Data Flow-File Write-基本过程

  8. 项目中容易出现的BUG预警

    之前没有记录BUG的习惯导致在同一个坑里边栽了好几次,于是将最近几个项目中遇到的问题整理一下,在进行新项目时预警一遍: 使用携带有搜索功能的分页查询时,注意当用户更改了查询条件但没有点击查询按钮直接点 ...

  9. Android 性感美图在线浏览APP

    周末无聊,遂整理了下近来常用的几个开源库,无意间又发现了一些开放接口,于是乎决定融合在一起,做个简单的"性感美图"浏览的APP,名字呢,就叫"性感沙滩",效果如 ...

  10. day6_python之configparser_模块

    configparser_模块是为了解析.ini文件的配置 a.ini [xiechao] name=xiechao age=18 is_admin=True salary=1000000.12 [x ...