1. 父子组件的数据来源
父组件数据在new Vue实例中,data数据形式对象、函数都可以;
子组件数据在Vue.component中,data数据形式必须用函数
2. 父子组件单向绑定
父向子传值(props
)
父级 prop 的更新会向下流动到子组件中,但是反过来则不行,避免子组件意外变更父级组件的状态。
注意
:父组件通过props单向传递给子组件,子组件只能读不能修改
静态赋值 vs 动态赋值
<!--静态赋值-->
<child-item title='hello'></child-item>
<!--动态赋值(变量,表达式)-->
<child-item v-bind:title='title'></child-item>
<child-item v-bind:title="name+':'+title"></child-item>
动态prop示例
<!--创建一个容器包裹模板内容-->
<div id='root'>
<div v-show="doc.show">{{doc.title}}</div>
<!--父组件通过自定义属性向子组件传值-->
<child-item v-bind:title='doc.title'></child-item>
</div>
<script type="text/javascript">
// 注册组件,先于vue实例
Vue.component('child-item',{
// 接受父组件传来的值
props:['title'],
// 子组件内容
template:`
<div>
<h2>子组件布局</h2>
<h2>{{title}}</h2>
</div>
`
});
// 实例vue,操作容器
new Vue({
el:'#root',
data:{
doc:{
title:'你好',
show:true
}
}
});
</script>
父组件向子组件传入对象所有的
property
,可使用不带参数的 v-bind
<!--子组件-->
<child-item v-bind='doc'></child-item>
<script>
Vue.component('child-item',{
// 每一个property作为prop传入
props:['title','show'],
template:`
<div>
<h2>子组件布局</h2>
<h2 v-show='show'>{{title}}</h2>
</div>
`
});
</script>
<!--等价于
<child-item v-bind:doc='doc'></child-item>
<script>
Vue.component('child-item',{
// 每一个property作为prop传入
props:['doc'],
template:`
<div>
<h2>子组件布局</h2>
<h2 v-show='doc.show'>{{doc.title}}</h2>
</div>
`
});
</script>
-->
子向父传值
自定义事件(通过$emit
触发)
父组件通过
v-on
监听子组件实例,子组件可以通过调用内建的$emit
方法并传入事件名称来触发一个事件,同时$emit
的第二个参数是子组件向父组件传递的值,父组件通过$event
接收。
若父组件通过方法update
接收且无参数,默认update($event)
<div id='root'>
<div v-show="doc.show">这是父组件内容:{{doc.title}}</div>
<!--父组件通过$event接收参数,除了写表达式也可以写方法接收并处理参数-->
<child-item v-bind:doc='doc' v-on:update:show="doc.show=$event"></child-item>
<!--等价于 <child-item v-bind:doc='doc' v-on:update:show="update"></child-item>-->
</div>
<script type="text/javascript">
Vue.component('child-item',{
// 接受父组件传来的值
props:['doc'],
template:`
<div>
<h2>子组件布局</h2>
<h2>{{doc.title}}</h2>
<button v-on:click="handle">点击隐藏父组件内容</button>
</div>
`,
methods:{
handle(){
// 用于子组件向父组件触发事件,提供第二个参数(抛出的值)
this.$emit('update:show',!this.doc.show)
}
}
});
new Vue({
el:'#root',
data:{
doc:{
title:'你好',
show:true
}
},
methods:{
/* 接收子组件传递过来的值
update1(val){
this.show=val
}*/
}
});
</script>
3. 父子组件双向绑定
v-model
通常用于表单元素的双向绑定,例如输入框、复选框等。它也可以用于子组件的双向绑定
v-model 实际上就是 props:value
和 $emit('input')
的组合语法糖
:
- v-bind 绑定 value 属性的值 - props:value;
- v-on 绑定 input 事件监听到函数中,函数会获取最新的值赋值到绑定的属性中 - $emit(‘input’);
<custom-input v-model="searchText"></custom-input>
<!-- 等价于 -->
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event">
</custom-input>
单个值示例
<div id="modeltest">
<custom-input v-model="searchText"></custom-input>
</div>
<script type="text/javascript">
Vue.component('custom-input',{
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input',$event.target.value)"
>
`
});
var vm = new Vue({
el: '#modeltest',
data: {
searchText:'请输入相关值'
}
});
</script>
这个组件内的
<input>
必须:
- 将其
value attribute
绑定到一个名叫value
的prop
上- 在其
input
事件被触发时,将新的值通过自定义的input
事件抛出
对象示例
<div id='root'>
<div v-show="doc.show">{{doc.title}}</div>
<child-item v-model='doc'></child-item>
</div>
<script type="text/javascript">
Vue.component('child-item',{
props:['value'],
template:`
<div>
<h2>子组件布局</h2>
<h2>{{value.title}}</h2>
<input
v-bind:value="value.title"
v-on:input="$emit('input',
{...value,// 展开原对象
title: $event.target.value // 仅更新 title
})"
>
<button @click="handle">点我隐藏</button>
</div>
`,
methods:{
handle(){
this.$emit('input', {
...this.value, // 展开原对象
show: !this.value.show // 修改 show 属性
});
}
}
});
new Vue({
el:'#root',
data:{
doc:{
title:'你好',
show:true
}
}
});
</script>
注意
:父组件传递对象时,子组件需要返回完整对象结构,不可以直接写成"$emit(‘input’, $event.target.value)",会破坏对象结构,即doc
从对象
变成了字符串
。
.sync
修饰符
用于简化
update:myPropName
的模式,也是父子组件之间的双向绑定的语法糖
,适用同步多个prop的值
注意
:使用.sync
时,$emit
所调用的事件名必须是update:属性名
<child-item v-bind.sync="show" ></childe-item>
<!--等价于-->
<child-item v-bind:show="show" v-on:update:show="update"></childe-item>
示例
<div id='root'>
<div v-show="doc.show">{{doc.title}}</div>
<child-item v-bind.sync='doc'></child-item>
</div>
<script type="text/javascript">
Vue.component('child-item',{
// 把 doc 对象整个传入,那么其中的每一个 property (如 title) 都作为一个独立的 prop 传进来
props:['title','show'],
template:`
<div>
<h2>子组件布局</h2>
<h2>{{title}}</h2>
<button @click="handle1">点我展示/隐藏父组件</button>
<button @click="handle2">点我修改title</button>
</div>
`,
methods:{
handle1(){
this.$emit('update:show',!this.show)
},
handle2(){
this.$emit('update:title',this.title=='hello'?'你好':'hello')
}
}
});
new Vue({
el:'#root',
data:{
doc:{
title:'你好',
show:true
}
}
});
</script>
带有 .sync 修饰符的 v-bind 不能和表达式一起使用,如
v-bind:title.sync=”doc.title + ‘!’”