背景: 在vue中时使用BetterScroll来滚动列表,而列表的数据是动态获取加载的,使用的是v-for遍历数据。数据加载完后,BetterScroll滚动失效。上网搜索资料,使用了一些方法都没能解决,比如在vue的activated()中调用bs.refresh() 方法。最后感觉应该是v-for的问题,经进一步搜索找到了解决方法。原文如下:
原文:
vue v-for循环渲染完毕在执行方法
在项目时用到了一些插件,比如这次用了下拉菜单插件。
这个插件需要实例化,而下拉框的数据是通过ajax来获取的,然后在用 v-for 渲染数据,再次遇到了一个问题。
就是等插件实例化完毕,数据却还没渲染完毕,所以这就出现一个bug。出现bug解决掉。
第一种解决方法: settimeout
setTimeout(function() {
//实例初始化
},100)
但是这种方法有一个缺点,就是不确定 数据 什么时候渲染完毕。
第一种情况: 假设10毫秒渲染完毕,但是setTimeout需要等100毫秒,浪费了90毫秒。
第二种情况:假设数据需要 200 毫秒执行完毕,但是 100毫秒就执行了 实例初始化,BUG又出现了。
总而言之这种方法不是我们想要的,看第二种方法。
第二种解决方法: watch + vm.nextTick
这两种方法是 vue 的属性和方法。
watch: 监听某一个data数据发生变化就执行方法。
例:
vm = new Vue({
el:'.app',
data: {
a: '1',
},
watch: {
a: function() {
console.log('a的数据发生变化'+this.a);
}
}
})
vm.a = '2';
data 里面的a属性发生了变化变成成了2,就触发了watch的a方法。console.log(a的数据发生变化2);
nextTich: 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div @click="ceshi()">{{ a }}</div>
</body>
<script type="text/javascript">
vm = new Vue({
el:'.app',
data: {
a: '1',
},
methods:{
ceshi(){
a = 2;
/*DOM还没更新*/
this.$nextTick(function(){
/*DOM更新了*/
})
}
}
})
</script>
</html>
$nextTick 里面DOM更新是指页面上的数据是最新的数据。而不是data的a数据更新了。
知道这两种属性之后。我们开始解决一下BUG吧。
先贴完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<setion>
<option value="1" v-for="(item,key) in arr" :key="key">{{ item }}</option>
</setion>
</body>
<script type="text/javascript">
vm = new Vue({
el:'.app',
data: {
arr: [],
},
watch:{
arr: function() {
this.$nextTick(function(){
/*现在数据已经渲染完毕*/
// 转者注:这里就可以调用bs.refresh() 方法了
})
}
},
mounted:function() {
var that = this;
axios.get('url',{
params:{
link: '',
}
}).then(function(res){
that.arr = res;
})
}
})
</script>
</html>
好,这就是我们解决的完整代码。 解释一下什么意思。
在 axios 请求数据是 this.arr被赋值了,watch监听到了 arr 数据发生变化执行arr方法。到了this.$nextTick 它需要等DOM 渲染完毕才执行(也就是等arr在DOM渲染完毕)。
这个方法完美解决需求,既不浪费时间又不会出现数据还没渲染完毕就执行实例初始化。这只是一个插件的实例化,通过这个例子可以应用很多的需求。