前言
之前学习vue,对父子组件传值达成了基本的认识,现在我把它进行系统的整理
父组件向子组件传值prop
首先在父组件中
<son :msg="我是你爸爸"></son>
在子组件的props中
export default {
props:{
'msg':String
}
}
这里我还加了一个数据类型的检测,注意,数据类型是在组件实例创建之前进行验证的
子组件向父组件传值$emit
子组件中,需要触发一个事件,可以是自定义事件,也可以是原生事件,在这里我们先用自定义事件,原生事件比较复杂,我放在后面说
首先我们在子组件中用$emit触发自定义事件,这个自定义事件写在生命周期函数或者是click事件上均可,然后第二个参数是我们要传给父组件的值
this.$emit('hellodad','爸爸我很想你');
然后我们在父组件中监听子组件的自定义事件,并在监听到的时候,触发happy事件
<son v-on:hellodad="happy"></son>
export default {
methods:{
happy(data){
console.log(data);
console.log('hello,my son');
}
},
components:{
son
}
}
data中就是子组件中打印出来的消息啦。
vm.$attrs
那么什么是$attrs
呢,下面是官方定义
包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。
父亲给儿子传了三个属性
<son
msg1:'1'
msg2:'2'
msg3:'3'
></son>
儿子说,我不要那么多,要一个就好了,剩下给你孙子吧
<grandson v-bind="$attrs"></grandson>
export default {
props:['msg1']
}
孙子说,气死了,你怎么尽挑不要的给我
created(){
console.log(this.$attrs);//{v-bind:{msg2:'2',msg3:'3'}}
}
inheritAttrs
官方解释
1.默认情况下父作用域的不被认作 props 的特性绑定 (attribute bindings) 将会“回退”且作为普通的 HTML 特性应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。通过设置 inheritAttrs 到 false,这些默认行为将会被去掉。2.而通过 (同样是 2.4 新增的) 实例属性 $attrs 可以让这些特性生效,且可以通过 v-bind 显性的绑定到非根元素上。
注意:这个选项不影响 class 和 style 绑定。
首先,我们来理解一下第一句话
在父元素中设置
<son msg="son" class="son"></son>
在子元素中不设置props进行接收
export default {
inheritAttrs:false
}
父组件给子组件设置的值就会退化成为子组件的属性
在子组件中设置
exportt default{
inheritAttrs:false
}
看,msg属性消失了,它不会退化为子组件普通的 HTML 特性了,但是class
和style
则不会。这是因为,在父组件中不被认作 props 的特性绑定会覆盖子组件根组件上的同名特性,而class
和style
则会发生合并。
2.然后,我们来理解一下第二句话,因为有$attrs,我们用祖孙三辈组件来进行解释
父亲
<son
msg1:'1'
msg2:'2'
msg3:'3'
></son>
儿子
<grandson v-bind="$attrs"></grandson>
export default {
props:['msg1']
}
可以看到,这些特性生效,且可以通过 v-bind 显性的绑定到元素上。至于是不是根元素,其实主要是看你的写法,如果你是直接在子组件的components
中定义孙子元素,并且把$attrs
绑定在孙子上面,那理解为非根元素也无可厚非。
.native
使用 v-on 的.native
修饰符,可以在直接监听组件的根元素的一个原生事件。
<base-input v-on:focus.native="onFocus"></base-input>
我在给router-link
绑定点击事件的时候,就需要使用.native
修饰符,否则点击事件不会生效。因为router-link是一个自定义标签,他没有自己的事件和方法,所以我们用.native监听这个组件根元素的原生事件,就可以触发点击事件了。
可是有的时候,在你尝试监听一个类似 的非常特定的元素时,这并不是个好主意。比如上述 组件可能做了如下重构,所以根元素实际上是一个
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
这时,父级的 .native
监听器将静默失败。它不会产生任何报错,但是 onFocus
处理函数不会如你预期地被调用。
$listeners
为了解决这个问题,Vue 提供了一个 $listeners 属性,它是一个对象,里面包含了作用在这个组件上的所有监听器。例如:
{
focus: function (event) { /* ... */ }
input: function (value) { /* ... */ },
}
下面是$listeners的官方解释
包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
啥意思呢?我们还是用祖孙三辈举例
父亲和儿子说,请把孙子今天的表现告诉我
<son @actiom="happy"></son>
儿子:帮忙父亲监视孙子
<grandson v-on="$listeners"><grandson>
孙子
this.$emit('action',msg);
有的时候,我们还可以用computed覆写$listeners这个事件监听器
computed:{
mylisteners:function(){
var _this = this;
return Object.assign({},this.$listens,{
input:function()(event) {
_this.$emit('input', event.target.value)
}
}
}
}
.sync
在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,且在父组件和子组件都没有明显的改动来源。
这也是为什么我们推荐以 update:myPropName 的模式触发事件取而代之。举个例子,在一个包含 title prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:
this.$emit('update:title', newTitle)
然后父组件可以监听那个事件并根据需要更新一个本地的数据属性。例如:
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
为了方便起见,我们为这种模式提供一个缩写,即 .sync 修饰符:
<text-document v-bind:title.sync="doc.title"></text-document>
所以.sync的作用就是
<text-document v-on:update:tiltle="doc.title=$event"></text-document>
注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是无效的)。取而代之的是,你只能提供你想要绑定的属性名,类似 v-model。