Vue在事件处理方法中改变传入参数与响应式

事件处理方法、事件处理函数和事件处理程序,广义上可以认为是一回事。我们在调用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'。

Vue在事件处理方法中改变传入参数与响应式

接下来看第二个例子。

  <!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'并没有改变。

Vue在事件处理方法中改变传入参数与响应式02

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>
Vue在事件处理方法中改变传入参数与响应式03

笔记与思考

  1. 我现在就遇到了这个问题,因为好多select用到同一个事件,事件请求完数据以后要把每一个select相对应的的options改变,没法动态改变的话,只能判断是哪个select再改变data.obj.xxx的值了

发表评论

邮箱地址不会被公开。 必填项已用*标注