1.computed计算属性监听不到数组或者对象的变化

对象:向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新属性,因为 Vue 无法探测普通的新增属性 (比如 this.myObject.newProperty = ‘hi’)

数组:
Vue 不能检测以下数组的变动:
当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength

为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将在响应式系统内触发状态更新:

  1. // Vue.set
  2. Vue.set(vm.items, indexOfItem, newValue)
  3. // Array.prototype.splice
  4. vm.items.splice(indexOfItem, 1, newValue)

2.vue自定义指令—directive(绑定事件,更新数据存在闭包作用域问题)

在项目中,我们自定义一个全局指令my-click:

  1. Vue.directive('my-click',{
  2. bind:function(el, binding, vnode, oldVnode){
  3. el.addEventListener('click',function(){
  4. console.log(el, binding.value)
  5. })
  6. }
  7. })

同时,有一个数组arr:[1,2,3,4,5,6],我们遍历数组,生成dom元素,并为元素绑定指令:

  1. <ul>
  2. <li v-for="(item,index) in arr" :key="index" v-my-click="item">{{item}}</li>
  3. </ul>

image.png
可以看到,当我们点击元素的时候,成功打印了元素,以及传递过去的数据。
可是,当我们把最后一个元素动态的改为8之后(6 —> 8),点击元素,元素是对的,可是打印的数据却仍然是6.
image.png
或者,当我们删除了第一个元素之后,点击元素

image.png
这是为什么呢????带着这个疑问,我去看了看源码。在进行下面的源码分析之前,先来说结论:
组件进行初始化的时候,也就是第一次运行指令的时候,会执行bind钩子函数,我们所传入的参数(binding)都进入到了这里,并形成了一个闭包。
当我们进行数据更新的时候,vue虚拟dom不会销毁这个组件(如果说删除某个数据,会从后往前销毁组件,前面的总是最后销毁),而是进行更新(根据数据改变),如果指令有update钩子会运行这个钩子函数,但是对于元素在bind中绑定的事件,在update中没有处理的话,他不会消失(依然引用初始化时形成的闭包中的数据),所以当我们更改数据再次点击元素后,看到的数据还是原数据。

解决

看过了源码,我们再回到上面的bug,我们应该如何去解决呢?

1、事件解绑,重新绑定

我们在bind钩子中绑定了事件,当数据更新后,会运行update钩子,所以我们可以在update中先解绑再重新进行绑定。因为bind和update中的内容差不多,所以我们可以把bind和update合并为同一个函数,在用自定义指令的简写方法写成下面的代码:

  1. Vue.directive('my-click', function(el, binding, vnode, oldVnode){
  2. //点击事件的回调挂在在元素myClick属性上
  3. el.myClick && el.removeEventListener('click', el.myClick);
  4. el.addEventListener('click', el.myClick = function(){
  5. console.log(el, binding.value)
  6. })
  7. })

image.png

可以看到,数据已经变成我们想要的数据了。

2、把binding挂在到元素上,更新数据后更新binding

我们已经知道了,造成问题的根本原因是初始化运行bind钩子的时候为元素绑定事件,事件内获取的数据是初始化的时候传递过来的数据,因为形成了闭包,那么我们不使用能引起闭包的数据,把数据存到某一个地方,然后去更新这个数据。

  1. Vue.directive('my-click',{
  2. bind: function(el, binding, vnode, oldVnode){
  3. el.binding = binding
  4. el.addEventListener('click', function(){
  5. var binding = this.binding
  6. console.log(this, binding.value)
  7. })
  8. },
  9. update: function(el, binding, vnode, oldVnode){
  10. el.binding = binding
  11. }
  12. })

这样也能达到我们想要的效果。

3、更新父元素

如果我们为父元素ul绑定一个变化的key值,这样,当数据变更的时候就会更新父元素,从而重新创建子元素,达到重新绑定指令的效果。

  1. <ul :key="Date.now()">
  2. <li v-for="(item,index) in arr" :key="index" v-my-click="item">{{item}}</li>
  3. </ul>

这样也能达到我们想要的效果

3.针孔打印问题

vue打印,引入vue-print-nb插件
存在问题:针孔打印不清晰:可以设置

  1. color:#000;
  2. font-family: MicrosoftYaHei, MicrosoftYaHei-Regular;

4.vue父组件传子组件,并打开子组件模态框

需要用setTimeout方法,挂起,等传值完再打开

  1. belongSelectedItemClick (val) {
  2. console.log(val)
  3. this.belongSelectedItem = val
  4. setTimeout(() => {
  5. this.$refs.setBelongDrawerRef.onOpen()
  6. })
  7. },