现象
我们先来看下面的一段代码(可以丢到dotWe上自己运行试试),用v-for产生两个div,然后点击按钮触发其中的一个div发生位置变化。
<template>
<div>
<div v-for="(item, index) of list" :key="index" :class="['box', pos[index]]" ></div>
<div class="btn" @click="onBtnClick"></div>
</div>
</template>
<style>
.box {
position: absolute;
left: 200px;
width: 50px;
height: 100px;
background-color: grey;
}
.btn {
top: 300px;
left: 300px;
width: 200px;
height: 150px;
background-color: blue;
}
.top1 {
top: 30px;
}
.top2 {
top: 150px;
}
</style>
<script>
export default {
data () {
return {
list: [1, 1],
pos: ['top1', 'top1']
}
},
methods: {
onBtnClick() {
this.pos[0] = this.pos[0]=='top1'?'top2':'top1'
}
}
}
</script>
试过之后,你会发现,点击按钮并没有任何变化。可以通过weex的debug工具查看到,其实div的top已经变更为我们设置的值了,只是UI上没有反应出来。但是,如果改变top值的同时,让UI上的元素的内容发生变化,比如有文字产生改变,那么UI能按照预期正常的显示出来。
没有动态响应的原因很简单,之前对vue的理解不够透彻,忘记了vue对数组的动态响应前提是使用数组的push、pop等改变数组的方法,而直接通过索引赋值是不能被观察到的。
解决
- 王道:用this.$set(obj, key, value)方法来改变数组元素
- 歪道:用this.$forceUpdate()这个函数,让我们可以强制组件进行一次刷新。
补充
this.$forceUpdate()也只会在实际的style和class有变化的情况下才会起作用的,假如元素进行动画前,opacity是1,而动画效果是让元素的透明度变为0.5,那么动画完成后,即使当前元素的效果是透明度0.5,但是因为动画并不会真正改变元素动画设置的style和class,所以opacity仍旧是1。
此时,我们去设置opacity为1,并且this.$forceUpdate()强制更新,因为opacity的值前后并没有变化,所以UI并不会改变。只有设置opacity为其他值,和之前的值不同,强制更新才能出来效果。
这点尤为要注意!
网友评论