事件处理方法、事件处理函数和事件处理程序,广义上可以认为是一回事。我们在调用Vue事件处理方法的时候,可以传入参数,并对传入的参数进行修改。如果传入的参数是data上绑定的数据,那么我们在方法里把传入的参数修改后,data上绑定的数据是否也会跟着变化呢?
我们先看第一个例子。
<!DOCTYPE html> <html lang="en"> <head> <style> .btn { width: 90px; height: 30px; background: #888; } </style> </head> <body> <button v-on:click="click(obj)" class="btn"> 点击{{ obj.name }} </button> <script src="vue.js"></script> <script> let vm = new Vue({ el: '.btn', data: { obj: { name: 'name1', } }, methods: { click(val) { val.name = 'name2'; console.log(val); console.log(this.obj); } } }) </script> </body> </html>
我们在data上绑定了一个对象obj,该对象有一个属性name,其值是'name1'。按钮.btn上有click处理方法,点击的时候会把data上的obj作为参数传入。click方法会将传入参数的name属性修改为'name2'。接着在控制台打印出传入的参数和data绑定的obj。
我们在浏览器里点击该按钮试一下。可以看到无论是打印参数还是obj,都是一个对象,对象有name属性为'name2'。
接下来看第二个例子。
<!DOCTYPE html> <html lang="en"> <head> <style> .btn { width: 90px; height: 30px; background: #888; } </style> </head> <body> <button v-on:click="click(name)" class="btn"> 点击{{name}} </button> <script src="vue.js"></script> <script> let vm = new Vue({ el: '.btn', data: { name: 'name1' }, methods: { click(val) { val = 'name2'; console.log(val); console.log(this.name); } } }) </script> </body> </html>
这次data上直接绑定了一个name,name的值是'name1'。我们在点击的时候,把传入的参数修改为'name2'。接着,我们在控制台打印传入的参数和data绑定的name。
可以看到,打印出的结果是,参数val是'name2',而this.name仍然是'name1'并没有改变。
this.name为什么没有改变,不是说vue里data上绑定的值是响应式的吗?响应式不就意味着在函数里把参数val修改了,data绑定的值也应该跟着变化么?
下面说说应该怎么理解。
data上绑定的响应式数据,只有vue实例能观测到其修改了才能进行响应式。我们在v-on:click="click(name)"里,传入的实参name其实是一个字符串,这是一个JavaScript基本类型值。click处理函数并不知道其处理的参数val是vue实例绑定的数据,因此this.name也就不会发生变化。
同理,在第一个例子里,click处理函数也并不知道其处理的参数val是vue实例绑定的数据。那么为何我们发现 this.obj发生了变化?
说this.obj发生了变化,其实并不严谨。obj是一个JavaScript引用类型数据,它是一个指针,指向的是堆内存的地址。我们例子里的this.obj堆内存地址并没有发生变化。obj只是其属性name发生了变化而已。我们的Vue实例初始化的时候,在观测obj指向的内存地址上的name属性。因此name变化了,this.obj的name在{{obj.name}}就变化了。
结论就是,Vue事件处理方法传入的参数与Vue响应式并没有直接关系。我们应区分为两块知识点来对待,一个是JS函数调用的参数类型,一个是Vue响应式的原理。
我们把第一个例子的代码修改成如下,看看控制台打印结果,会有更深刻的体会的。
<!DOCTYPE html> <html lang="en"> <head> <style> .btn { width: 90px; height: 30px; background: #888; } </style> </head> <body> <button v-on:click="click(obj)" class="btn"> 点击{{ obj.name }} </button> <script src="vue.js"></script> <script> let vm = new Vue({ el: '.btn', data: { obj: { name: 'name1', } }, methods: { click(val) { // val.name = 'name2'; val = 3; console.log(val); console.log(this.obj); } } }) </script> </body> </html>
我现在就遇到了这个问题,因为好多select用到同一个事件,事件请求完数据以后要把每一个select相对应的的options改变,没法动态改变的话,只能判断是哪个select再改变data.obj.xxx的值了