需求
由循环生成的一组按钮,每个关联一个对话框,要求点击某一按钮时应弹出对应的对话框,代码片段如下:
<span v-for="(run, index) in runs" :key="index">
<el-button type="text" @click="inputDialogVisible[index] = true">({{index}})</el-button>
<el-dialog :visible.sync="inputDialogVisible[index]">
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="inputDialogVisible[index] = false">确 定</el-button>
</div>
</el-dialog>
</span>
<script>
import alignerApi from "@/api/corpus/aligner";
export default {
data() {
return {
inputDialogVisible: [],
};
},
}
</script>
问题
点击按钮时对话框未弹出,页面也没有更新。
解决
查阅 Vue 官方文档“列表渲染”一节,找到“数组更新检测”部分:
变更方法
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
注意事项
由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。深入响应式原理中有相关的讨论。
由此可见,Vue 只监视 inputDialogVisible 本身的改变,而忽略其内部对象的改变。
在上述代码中, inputDialogVisible[index] = true 并没有改变 inputDialogVisible 本身,只是改变了数组内部的对象。由于没有调用变更方法,Vue 无法监测到变化而不会更新界面,导致对话框无法弹出。
解决的方法是,将 inputDialogVisible[index] = true 这一逻辑由变更方法来实现,改为 inputDialogVisible.splice(index, 1, true)。
注:包裹后的变更方法相当于执行了两步:第一步,调用原生方法;第二步,更新界面。
变更后的代码片段如下:
<span v-for="(run, index) in runs" :key="index">
<el-button type="text" @click="inputDialogVisible.splice(index, 1, true)">({{index}})</el-button>
<el-dialog :visible.sync="inputDialogVisible[index]">
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="inputDialogVisible.splice(index, 1, false)">确 定</el-button>
</div>
</el-dialog>
</span>
<script>
import alignerApi from "@/api/corpus/aligner";
export default {
data() {
return {
inputDialogVisible: [],
};
},
}
</script>
参考文献: