v-model
本质上是一种语法糖 :bind=”value” @input=”method”
表单控件上的使用
适用于 <input> <select> <textarea>
- <input type=”text” > <textarea> text 和 textarea 元素使用 value 属性和 input 事件
- <input type=”checkbox”> <input type=”radio”> 使用checked 属性和 change 事件
- <select> value 作为 prop 并将 change 作为事件
自定义组件上的使用
一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件
model配置项目: model配置项可以操作来自组件上v-model的默认值,prop可以修改绑定的参数,event可以更改
绑定的用于更新的方法名。
如下面的select,当input值改变时,会寻找change方法,在当前子组件作用域中其实是没有这个方法的,但是通过
model.event将默认的input方法改为了change方法,这个时候就能够调用此方法来进行更新。同样input此时默认获
取checkbox,通过修改model.prop来达到目的
1 | // 父组件 |
$listeners
包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on=”$listeners” 传入内部组件——在创建更高层次的组件时非常有用。
用来实现跨组件双向绑定(以封装第三方组件为例)
不使用$listeners
实现双向绑定时,只能通过绑定计算属性,通过计算属性的set 来主动触发this.$emit
如下有一组例子:
第三方组件v-input,简单的输入框v-model。v-transfrom-input是我们对其
进行二次封装的组件,再供给页面中使用。这些逻辑都一块写在listeners.vue中。
第三方组件:v-input
1 | Vue.component("v-input", { |
封装第三方组件:v-transform-input
想实现双向绑定值传递,需要绑定一个计算属性thisValue, 通过计算属性set来主动触发this.$emit(‘input’),实现上层父组件中v-model绑定值的更新。
主动触发是因为当前组件为非表单控件,并没有用户输入事件来主动触发更行上层input方法,所以要添加逻辑来主动进行触发。
1 | Vue.component("v-transform-input", { |
listeners.vue使用封装好的组件
1 | // template |
使用$listeners
利用listeners将父组件作用域绑定的方法绑定此组件作用域的特点。
因为$listeners将父组件上v-model绑定值的input方法都绑定到了v-transform中,所以第三方组件v-input
中触发this.$emit(‘input’)就能在v-transform中找到$listeners绑定来的input方法,这个input方法其实就
是最顶层v-model指令语法糖的默认input方法,更新的也是最顶层的那个value
封装第三方组件
1 | Vue.component("v-transform-input", { |
用来实现跨组件调用方法(以封装第三方组件为例)
在没有使用$listeners时
调用第三方组件提供的方法需要逐层添加事件绑定,来调用$emit
同样的组件:
第三方组件v-input,提供一个setColor方法改变按钮的字体颜色,供上层组件调用,
然后我们对其进行二次封装的v-transfrom-input,再供给页面中使用
第三方组件:v-input
1 | Vue.component("v-input", { |
封装第三方组件:v-transfrom-input
1 | Vue.component("v-transform-input", { |
使用封装好的组件: listeners.vue
1 | // template |
使用$listeners
同样利用listeners将父组件作用域绑定的方法绑定此组件作用域的特点。
上层父组件的otherMethod方法也合并到了当前组件v-transfrom-input的作用域中,v-inputsetColr中调
用this.$emit(‘otherMethod’), 也就能在v-transfrom-input上找到对应方法。
改写封装的第三方组件
1 | Vue.component("v-transform-input", { |
当父组件双向绑定值没有初始化注册
还是那个例子,不做初始化双向绑定就会失效。可能在vue实例第一次渲染时候,没有遍历到这个值,就不会生成相应的obsever。
有待继续发掘。
使用封装好的组件: listeners.vue
1 | // template |
$attrs
包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过v-bind=”$attrs” 传入内部组件——在创建高级别的组件时非常有用。
使用
孙组件
1 | // template |
子组件
1 | // template |
父组件
1 | // template |
查看dom如下
inheritAttrs禁用特性继承
- 默认值为true
- 如果你不希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false
- 不会影响 style 和 class 的绑定。
1 | Vue.component('my-component', { |
小结
v-model表单控件
- 通常默认绑定value,数据更新方法为input
- checkbox, radio 使用为checked,更新方法为change
- select 默认绑定value, 数据更新为change
v-model非表单控件作为中间层组件(如封装第三方组件)
未使用$listeners情况下需要通过v-model双向绑定计算属性,数据更新
触发set方法,在set方法中进而主动触发this.$emit(‘input’)
- 使用$listeners情况下,仅需配合$attrs就能达到目的,v-model也不必写
双向绑定值初始化
- 不管任何形式的值,只要在data中没有初始化,那么双向绑定就不会成功
讨论
- 为什么只有data初始化的值,才能真正做到双向绑定视图更新?