我们知道,vue有一个重要的理念就是组件化,即将重复使用的功能点抽提出来作为组件,需要使用的页面只需要引用该组件即可得到相应的功能点。
而组件化的一个重要特性就是作用域隔离,即一个组件实例拥有一个私有的作用域,当在页面中引用了该组件之后,只有该组件实例能访问该作用域。
但是当在同一个页面多次使用同一个组件的时候,如果只创建了一个实例,但是却对这个实例调用了两次,这两个调用就会造成相互干扰的问题,因为这时候这两个调用访问的是同一个作用域。比如有现在有一个yanggb组件,我引入到我的页面中(创建了一个组件实例),然后调用两次(在页面上调用组件实例两次),那么当我给第一个调用绑定的对象变量的一个属性赋值了100,那么第二个调用绑定的同一个对象变量的该属性也会被赋值100,因为这两个调用在同一个作用域内绑定了同一个对象变量,而JavaScript内一切对象皆为引用,也就导致第二个调用的值跟着第二个调用的值变化了。
// 引用yanggb组件并创建一个实例 const yanggb = () => import('@/components/yanggb') // 注册该组件实例 components: { yanggb } // 在页面上两次调用该组件实例 <yanggb :value="100"></yanggb> <yanggb></yanggb>
这个时候,如果该组件是直接显示的:value属性中绑定的值的话,那么两个调用都会显示100的值。
其实解决办法在这里已经呼之欲出了,既然创建一个实例调用两次会相互影响,那么我创建两个实例分别调用一次不就不会相互干扰了吗?我们来试一下。
// 引用同一个yanggb组件但创建两个个实例 const yanggb = () => import('@/components/yanggb') const yanggb1 = () => import('@/components/yanggb') // 注册两个组件实例 components: { yanggb, yanggb1 } // 在页面上分别调用两个组件实例 <yanggb :value="100"></yanggb> <yanggb1></yanggb1>
那么这个时候因为两个实例拥有相互独立的私有作用域,也就不会导致相互干扰的结果了,第二个实例的调用不会显示100的值。
PS:以上的【实例】和【调用】相关字眼是个人的理解,只是为了方便理解,并不一定正确。
另外,在解决问题的过程中,查到一些相关的解决方案,其中一个是使用JSON.stringify()和JSON.parse()两个方法配合使用来RE-双向绑定(个人理解是强行派生出新的对象,解除对原对象的引用,并将该新对象绑定到该组件调用上),但是总觉得有点奇怪,因为这样只是在同一个作用域内解除了对同一个对象的多次引用,不太符合组件化的设计理念与特性,并可能产生意料之外的问题,不是很喜欢这种方法。
"很多人都在告诉我要懂事,但是没有一个人告诉我要快乐。"