在项目时用到了一些插件,比如这次用了jquery ui的自定义拖拽控件。
控件需要实例化,而列表的数据是通过ajax来获取的,然后在用 v-for 渲染数据,再次遇到了一个问题。
就是等插件实例化完毕,数据却还没渲染完毕,所以这就出现一个bug,拖拽没有实例化。
首先想到的不是vue自带的方法,我先想到的是用settimeout。这里先简单介绍一下setTimeout() 方法:一般用于在指定的毫秒数后调用函数或计算表达式。setTimeout属于异步执行函数,当程序执行时遇到setTimeout会将该函数放入等待队列,等待当前主程序执行完毕后开始执行setTimeout。
第一种解决方法: settimeout
1 | setTimeout(function() { |
但是这种方法有一个缺点,就是不确定数据什么时候渲染完毕。
第一种情况: 假设10毫秒渲染完毕,但是setTimeout需要等100毫秒,浪费了90毫秒。
第二种情况:假设数据需要 200 毫秒执行完毕,但是 100毫秒就执行了 实例初始化,BUG又出现了。
所以,这种方法不是我们想要答案。
第二种解决方法: watch + vm.nextTick
这两种方法是 vue 的属性和方法。
watch: 监听某一个data数据发生变化就执行方法。
1 | vm = new Vue({ |
data 里面的arr数组发生了变化变成成了[1,2,3,4,5],就触发了watch的a方法。console.log(arr的数据发生变化[1,2,3,4,5]);
nextTich: 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
1 | <!DOCTYPE html> |
$nextTick 里面DOM更新是指页面上的数据是最新的数据。而不是data的a数据更新了。
知道这两种属性之后。我们开始解决一下BUG吧。
先贴完整代码:
1 | <!DOCTYPE html> |
上面就是解决bug的完整代码范例。 解释一下什么意思:
在 axios 请求数据是 this.arr被赋值了,watch监听到了 arr 数据发生变化执行arr方法。到了this.$nextTick 它需要等DOM 渲染完毕才执行(也就是等arr在DOM渲染完毕)。
这个方法完美解决需求,既不浪费时间又不会出现数据还没渲染完毕就执行实例初始化。
2018年5月6日补充:
还有另外一种方法忘记说明了,今天刚好写东西的时候注意了一下:
就是我们要做的逻辑依然在mounted执行我们需要的逻辑,就是利用v-if在需要数据渲染的地方进行判断,这样mounted就会在v-if数据存在并且渲染完成后再执行逻辑,当然,如果v-if判断无数据不需要渲染照常执行就不用多说了。
上面的例子可以写成这样:
1 | <!DOCTYPE html> |
完~