[vue学习笔记] v-bind和v-model

背景

最近使用element框架的时候用到inputNumber,需要渲染初始化数据并在数据修改后也能更新原数据。(下面的scope.row的数据源是在data里返回)

1
<el-input-number :value="scope.row.amount" @change="changeAmount" size="mini" controls-position="right" :min="1" :max="10"></el-input-number>

可是它的change事件只能传入最后修改值作参数,那我怎么修改原数据。然后我纠结了很久,突然想起这其实不就是表单控件的双向绑定吗..然后我修改为下面代码,成功了..

1
<el-input-number v-model="scope.row.amount" @change="changeAmount" size="mini" controls-position="right" :min="1" :max="10"></el-input-number>

莫名有点生气还是要保持微笑:) 不过其实我是弄混了property和attribute的概念
除此以外我对数据的双向绑定还有vue的响应式原理概念的模糊不清,所以现在来捋一捋

首先,attribute 和 property 有什么不同?

For a given DOM node object, properties are the properties of that object, and attributes are the elements of the attributes property of that object.

对于一个DOM节点(object)来说,attributes也是object的其中一个property,而attributes就是attribute的集合。

When a DOM node is created for a given HTML element, many of its properties relate to attributes with the same or similar names, but it’s not a one-to-one relationship.

当DOM节点生成对应的HTML元素后,它的很多properties就会和它相同(似)名字的attributes有关,但并不都是一一对应关系。
我们看看下面一段html代码会可能比较容易理解一点~
<input id="the-input" type="text" value="Name:">
这个DOM节点有id、type、value和其他properties。

  • id property 反映到 id attributey,且一一对应
  • type property
    • 若为已知值,同上
    • 否则,如当type=”foo”,foo不是输入的有效类型,则该type attribute为foo,而该type property为type property默认值text,即theInput.getAttribute("type") // foo,而theInput.type //text
  • value property
    • theInput.value为随着输入值改变而改变,即当前值
    • theInput.getAttribute("value")一直为Name:,即初始值
      其实看到这里,可能很多人都会有一种感觉,property更趋于某object的共性(代表着内部专属的意义),而attribute则是我们主观给它加的特性(人为的拓展)

v-bind绑定的到底是什么?

现在我们看回本文背景中第一条代码,其中的:value其实是v-bind:value的缩写。
文档v-bind的用法是这样说的:

动态地绑定一个或多个特性,或一个组件 prop 到表达式。
所以我更觉得v-bind绑定的是attribute,给组件传prop就是一个很明显的例子

1
<myComponent :yy="someprop"></mycomponent>

因为这个yy属性真的是我们yy出来的,因为我们在使用一个我们自定义的组件,给它传送的属性自然也是我们自定义出来的,我们赋予它意义并通过它其创造更大的意义。
因此,v-bind默认绑定的就是attribute,而v-bind:value绑定的是value attribute,即初始值。
v-bind有三个修饰符:.prop.camel.sync
当加上.prop的时候就是用来绑定DOM property
看到这里,应该看得出v-bind并不是用来实现数据双向绑定的。
不过,你以为的数据双向绑定就是真的数据双向绑定吗(嗯?)

数据的双向绑定

数据初始化绑定(vue实例属性(在data定义)初始化输入框的原始值, 并渲染文本节点)-》响应式的数据绑定(输入框的value变化会影响与其绑定的vue实例属性) -》订阅/发布模式(观测者检测到数据变化,告知文本节点,节点则相应更新)

时间太晚了+ +… 具体原理稍后再补

vue的响应式系统

data对象里面的属性才是响应式的。

Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。

  • 但什么是响应式呢?
    当你尝试修改一个数据的时候,触发其有关的视图会更新,实现数据的双向绑定。否则,在其他使用了该数据的地方,将不会进行更新。

    • 若某属性没有在data对象上声明,不能使用vue实例.newProperty=xxx成为响应式属性。因为此时vue实例已经创建,Vue 不允许在已经创建的实例上动态添加新的根级响应式属性。
      但可以使用下面两种方法:
      • vue全局set方法 Vue.set(object, key, value) 将响应属性添加到嵌套的对象上:
        Vue.set(vm.someObject, 'b', 2)
      • vm.$set 实例方法
        this.$set(this.someObject,'b',2)
    • 若想向已有对象上添加一些属性,例如使用 Object.assign()_.extend() 方法来添加属性。但是,添加到对象上的新属性不会触发更新。
      但可以创建一个新的对象,让它包含原对象的属性和新的属性:
      1
      2
      3
      //代替 Object.assign(this.someObject, { a: 1, b: 2 })
      this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
  • 异步更新队列
    Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    Vue.component('example', {
    template: '<span>{{ message }}</span>',
    data: function () {
    return {
    message: '没有更新'
    }
    },
    methods: {
    updateMessage: function () {
    this.message = '更新完成'
    console.log(this.$el.textContent) // => '没有更新'
    this.$nextTick(function () {
    console.log(this.$el.textContent) // => '更新完成'
    })
    }
    }
    })

v-model才是用来数据的双向绑定的正主

一开始v-model主要用以表单控件的数据的双向绑定
vue2.2.0新增,自定义组件也可以用v-model

1
2
3
4
5
6
7
8
9
10
11
12
Vue.component('my-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean,
// 这样就允许拿 `value` 这个 prop 做其它事了
value: String
},
// ...
})

1
2
3
4
5
6
7
8
9
<my-checkbox v-model="foo" value="some value"></my-checkbox>
等价于:
<my-checkbox
:checked="foo"
@change="val => { foo = val }"
value="some value">
</my-checkbox>

是不是觉得很眼熟:) ?

参考链接

What is the difference between properties and attributes in HTML? -Stack Overflow
深入理解vue.js双向绑定的实现原理