父组件向子组件传值
子组件接受父组件传递的值,需要使用 props
参数,也就是在子组件定义时,引入 props
数组。如下数组所示:
props: ['title', 'str'],
如果在一个子组件定义是添加了上面代码,意味着该组件可以接受两个参数:title 、str
,可以通过属性的形式将参数传递过来。在 template
中可以使用这两个参数。
如下组件中接受了一个父级组件传递来的 title
参数:
let div_inner = {
data: function () {
return {
text: '子级组件自有内容'
}
},
// 使用 props 数组接受父组件中传递的参数
props: ['title'],
template: `<div >{{ text + '===' + title }}</div>`,
}
HTML
<div class="container">
<!-- 设置 title 属性,向组件传递内容 -->
<div-inner title="父组件传递的内容"></div-inner>
</div>
Vue
let vm = new Vue({
el: '.container',
components: {
// 将自定义标签名和组件对象注册
'div-inner': div_inner,
},
})
结果:
还可以使用 v-bind
指令来进行动态的传递参数,使用 v-bind
为组件绑定属性,属性值为 data
所设置,如下代码所示:
组件:
let div_inner = {
data: function () {
return {
text: '子级组件自有内容'
}
},
// 使用 props 数组接受父组件中传递的参数
props: ['title', 'str'],
template: `<div >{{ text + '===' + title + '********' + str}}</div>`,
}
HTML
<div class="container">
<!-- 设置 title 属性,向组件传递内容 -->
<div-inner title="父组件传递的内容"></div-inner>
<!-- 使用 v-bind: 动态绑定数据,可以使用 vue 实例的 data 属性动态传递参数 -->
<div-inner :str='str'></div-inner>
</div>
Vue
let vm = new Vue({
el: '.container',
components: {
'div-inner': div_inner,
},
data: {
str: '这是通过data参数动态设置的数据'
}
})
结果:
props
参数注意事项
子组件使用属性接受父组件传来的参数时,由于 HTML 会将大写字母解析为小写字母,所以在 HTML 的写法中不允许使用大驼峰命名法,如下所示:
<inner-div TitleParam="这是传递的参数"></inner-div>
上面代码片段中使用了子组件 <inner-div>
但是传递参数时,属性名为大驼峰命名法,在浏览器中会发生警告,并且不会解析该参数:
完整代码:
<div class="container">
<!--
在 html 中书写时,如果属性名有大驼峰命名法,需要改为脊柱命名法
如果不改为脊柱命名法,子组件中不会接受到内容,浏览器控制台中产生警告
-->
<inner-div title-param="这是传递的参数"></inner-div>
<!-- <inner-div TitleParam="这是传递的参数"></inner-div> -->
</div>
let inner_div = {
// 定义组件时使用 props 参数接受的数据,命名方式不限
props: ['TitleParam'],
data: function () {
return {
text: '子组件中自带内容'
}
},
// template 参数渲染时命名方式不限
template: "<div>{{ text + '---' + TitleParam }}</div>"
}
let vm = new Vue({
el: '.container',
components: {
'inner-div': inner_div
}
})
如上面注释所说:在定义组件时,使用 props
参数接受的数据,命名方式不受限制;在使用 template
定义组件显示内容是,命名方式同样不受限制。唯一需要注意的是,书写在 HTML 中时,不可使用大驼峰。
传递值的类型
当使用 v-bind
动态绑定属性时,原来的内容是什么就会显示响应的内容。如果将属性写死,那么为字符串形式。
<div class="container">
<!-- 第一个参数通过 v-bind 绑定,第二个参数为普通的属性 -->
<inner-div v-bind:param1="12" param2="12"></inner-div>
</div>
let inner_div = {
props: ['param1', 'param2'],
template: `<div>{{ typeof param1 + "***** " + typeof param2 }}</div>`
}
let vm = new Vue({
el: '.container',
components: {
'inner-div': inner_div
}
})
结果:
子组件向父组件传值
使用子组件向父组件中传值时,需要使用 $emit()
绑定自定义事件,在括号中写入要绑定的自定义事件。如下代码:
<button @click='$emit("change_big")'>点击放大</button>
然后使父组件监听子组件的事件:
<fun-div :style="{fontSize: size + 'px'}" @change_big="func"></fun-div>
上面代码使用监听了子组件的 change_big
事件,该事件调用了 func
函数,完整代码如下:
组件:
let fun_div = {
// 在模板中定义了 click 事件,事件中使用 $emit() 进行绑定
template: `
<div>
测试文本
<button @click='$emit("change_big")'>点击放大</button>
</div>
`
}
JS
let vm = new Vue({
el: '.container',
data: {
size: 10
},
components: {
'fun-div': fun_div
},
methods: {
func: function () {
this.size++
}
},
})
HTML
<div class="container">
<fun-div :style="{fontSize: size + 'px'}" @change_big="func"></fun-div>
</div>
上面代码实现了使用子组件操作父组件中的内容,如果想要将子组件中的值传递给父组件,需要在模板的事件函数中传递参数,在 HTML 标签中的事件函数中传递 $event
参数,就可以在事件处理函数中接收到。如下代码:
子组件:
let fun_div = {
// 模板中 $emit("send", "hello world") 表示事件为 send ,传递的参数为 hello world
template: `<button @click='$emit("send", "hello world")''> 这是子组件,点击传值 </button>`
}
如注释中所说,使用 $emit()
设置了 send
事件,传递的参数为 hello world
。
上面代码将触发单击事件的代码写到了一起,还可以写成下面这样:
let fun_div = {
template: `
<button @click='send("hello world")'> 这是子组件,点击传值 </button>
`,
methods: {
send: function (msg) {
// 通过调用 this.$emit() 触发
this.$emit("send", msg)
}
},
}
Vue 代码:
let vm = new Vue({
el: '.container',
data: {
msg: ''
},
components: {
'fun-div': fun_div
},
methods: {
func: function (val) {
console.log(val);
this.msg = val
console.log(event);
}
},
})
HTML:
<div class="container">
<!-- 父组件监听 send 事件,事件函数中接受 $event 参数,该参数为子组件传递的参数 -->
<div>
{{msg}}
<fun-div @send='func($event)'></fun-div>
</div>
</div>
代码中的第 5 行极为关键,该自定义标签监听了 send
事件(上面子组件自定义的事件),在 func
事件处理函数中传递了 $event
参数,可以获取子组件中传递 hello world
参数。
兄弟组件之间的传值
兄弟组件之间的传值需要借助组件中心实现,所谓组件中心就是 new 一个 Vue 实例,Vue 实例中 $on
用来监听事件, $off
用来销毁事件,$emit()
用来触发事件。
详见 Vue 官方
$on
下面例子中完成了两个兄弟组件之间的通信过程:
tom 组件:
Vue.component('tom-div', {
data: function () {
return {
text: '向jerry发送数据',
msg: ''
}
},
template: `
<div>
<div>tom收到:{{msg}}</div>
<button @click="send">{{text}}</button>
</div>
`,
methods: {
// 按钮被点击时,由事件中心触发对方的事件,
send: function () {
// 通过 $emit 触发对方的事件
eventHub.$emit('jerry-event', '你好 jerry')
}
},
// 当模板加载完成时
mounted() {
// 通过事件中心监听一个自定义事件,当相应按钮触发时,通过事件中心触发事件
// val 可以接受事件中传递的参数
eventHub.$on('tom-event', (val) => {
this.msg += val
})
},
})
jerry 组件:
Vue.component('jerry-div', {
data: function () {
return {
text: '向tom发送数据',
msg: ""
}
},
template: `
<div>
<div>jerry收到:{{msg}}</div>
<button @click="send">{{text}}</button>
</div>
`,
methods: {
send: function () {
eventHub.$emit('tom-event', '你好 tom')
}
},
// 当模板加载完成时
mounted() {
// 通过事件中心监听一个自定义事件,当相应按钮触发时,通过事件中心触发事件
eventHub.$on('jerry-event', (val) => {
this.msg += val
})
}
})
上述两个组件中,结构是相同的,这里拿 jerry 组件来说明。
首先看第 8 - 12 行,创建了 html 模板,模板中有一个按钮,当点击按钮时触发 send
事件函数。
再看 20 - 24 行,使用生命周期钩子(生命周期函数),mountend
当模板加载完毕时开始执行,也就是说当模板加载完成时监听 jerry-event
事件,该事件中接受一个参数。
再看 14 - 18 行,当 11 行的按钮被点击时,触发 send
事件函数,该函数中,使用 $emit()
触发了另一个兄弟中的 tom-jerry
事件。
HTML
<div class="container">
<tom-div></tom-div>
<br>
<jerry-div></jerry-div>
</div>
结果: