- 1.computed计算属性监听不到数组或者对象的变化
- vue自定义指令—directive(绑定事件,更新数据存在闭包作用域问题)">2.vue自定义指令—directive(绑定事件,更新数据存在闭包作用域问题)
- 3.针孔打印问题
- 4.vue父组件传子组件,并打开子组件模态框
1.computed计算属性监听不到数组或者对象的变化
对象:向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新属性,因为 Vue 无法探测普通的新增属性 (比如 this.myObject.newProperty = ‘hi’)
数组:
Vue 不能检测以下数组的变动:
当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength
为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将在响应式系统内触发状态更新:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
2.vue自定义指令—directive(绑定事件,更新数据存在闭包作用域问题)
在项目中,我们自定义一个全局指令my-click:
Vue.directive('my-click',{
bind:function(el, binding, vnode, oldVnode){
el.addEventListener('click',function(){
console.log(el, binding.value)
})
}
})
同时,有一个数组arr:[1,2,3,4,5,6],我们遍历数组,生成dom元素,并为元素绑定指令:
<ul>
<li v-for="(item,index) in arr" :key="index" v-my-click="item">{{item}}</li>
</ul>
可以看到,当我们点击元素的时候,成功打印了元素,以及传递过去的数据。
可是,当我们把最后一个元素动态的改为8之后(6 —> 8),点击元素,元素是对的,可是打印的数据却仍然是6.
或者,当我们删除了第一个元素之后,点击元素
这是为什么呢????带着这个疑问,我去看了看源码。在进行下面的源码分析之前,先来说结论:
组件进行初始化的时候,也就是第一次运行指令的时候,会执行bind钩子函数,我们所传入的参数(binding)都进入到了这里,并形成了一个闭包。
当我们进行数据更新的时候,vue虚拟dom不会销毁这个组件(如果说删除某个数据,会从后往前销毁组件,前面的总是最后销毁),而是进行更新(根据数据改变),如果指令有update钩子会运行这个钩子函数,但是对于元素在bind中绑定的事件,在update中没有处理的话,他不会消失(依然引用初始化时形成的闭包中的数据),所以当我们更改数据再次点击元素后,看到的数据还是原数据。
解决
看过了源码,我们再回到上面的bug,我们应该如何去解决呢?
1、事件解绑,重新绑定
我们在bind钩子中绑定了事件,当数据更新后,会运行update钩子,所以我们可以在update中先解绑再重新进行绑定。因为bind和update中的内容差不多,所以我们可以把bind和update合并为同一个函数,在用自定义指令的简写方法写成下面的代码:
Vue.directive('my-click', function(el, binding, vnode, oldVnode){
//点击事件的回调挂在在元素myClick属性上
el.myClick && el.removeEventListener('click', el.myClick);
el.addEventListener('click', el.myClick = function(){
console.log(el, binding.value)
})
})
可以看到,数据已经变成我们想要的数据了。
2、把binding挂在到元素上,更新数据后更新binding
我们已经知道了,造成问题的根本原因是初始化运行bind钩子的时候为元素绑定事件,事件内获取的数据是初始化的时候传递过来的数据,因为形成了闭包,那么我们不使用能引起闭包的数据,把数据存到某一个地方,然后去更新这个数据。
Vue.directive('my-click',{
bind: function(el, binding, vnode, oldVnode){
el.binding = binding
el.addEventListener('click', function(){
var binding = this.binding
console.log(this, binding.value)
})
},
update: function(el, binding, vnode, oldVnode){
el.binding = binding
}
})
这样也能达到我们想要的效果。
3、更新父元素
如果我们为父元素ul绑定一个变化的key值,这样,当数据变更的时候就会更新父元素,从而重新创建子元素,达到重新绑定指令的效果。
<ul :key="Date.now()">
<li v-for="(item,index) in arr" :key="index" v-my-click="item">{{item}}</li>
</ul>
这样也能达到我们想要的效果
3.针孔打印问题
vue打印,引入vue-print-nb插件
存在问题:针孔打印不清晰:可以设置
color:#000;
font-family: MicrosoftYaHei, MicrosoftYaHei-Regular;
4.vue父组件传子组件,并打开子组件模态框
需要用setTimeout方法,挂起,等传值完再打开
belongSelectedItemClick (val) {
console.log(val)
this.belongSelectedItem = val
setTimeout(() => {
this.$refs.setBelongDrawerRef.onOpen()
})
},