组件事件
前面学习的props是将数据从父级向子级传递,而不能将数据从子级向父级传递,而今天学习的$emit
方法触发自定义事件可以将数据从子级传递到父级。
1.在子级中,首先是触发事件
<button @click="ClickEventHandle">把子级元素传递给父级</button>
2.然后通过#emit向父级发送触发事件
// 两个参数,一个是触发事件,一个是传递数据
methods:{
ClickEventHandle(){
this.$emit("someEvent","这条数据来自Child")
}
}
}
3.在父级中,首先接受触发事件
<Child @someEvent="getHandle" />
4.然后是执行事件
methods:{
getHandle(data){
this.message=data
}
}
组件事件配合v-model使用
1.在子级中设置监听器
搜索:<input type="text" v-model="search">
2.触发emit,并传递参数
watch:{
search(newValue,oldValue){
this.$emit("searchEvent",newValue)
}
}
3.父级中接受事件
<SearchComponent @searchEvent="getSearch"/>
4.处理事件
methods:{
getSearch(data){
this.messsage=data
}
组件数据传递
插槽内容与出口
前面提到props只能把数据从父级传到子级,属于一般情况,可以通过父级向子级传递函数的方式间接将数据从子级传递到父级
1.父级子级传递方法类型(Function)的props
<ComponentB title="welcome" :onEvent="DataFn" />
2.子级接收该props
props:{
title:String,
onEvent:Function
}
3.子级执行该函数
<h4>{{ onEvent('can you see me?') }}</h4>
4.该函数具体为
methods:{
DataFn(data){
this.messsage=data
}
}
当子级执行该函数时,会用到参数 “can you see me?” ,从而间接把该参数回传给父级,从而父级可以利用该参数
<h4>{{ messsage }}</h4>
完整代码
父级:
<template>
<h1>ComponentA</h1>
<ComponentB title="welcome" :onEvent="DataFn" />
<h4>{{ messsage }}</h4>
</template>
<script>
import ComponentB from "./ComponentB.vue"
export default{
data(){
return{
messsage:""
}
},
components:{
ComponentB
},
methods:{
DataFn(data){
this.messsage=data
}
}
}
</script>
子级
<template>
<h1>ComponentB</h1>
<div>this is Child:<h3>{{title}}</h3></div>
<h4>{{ onEvent('can you see me?') }}</h4>
</template>
<script>
export default{
data(){
return{
messsage:""
}
},
props:{
title:String,
onEvent:Function
}
}
</script>
插槽slots
在某些场景中,我们可能想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段。
举例来说,这里有一个 <FancyButton>
组件,可以像这样使用:
<FancyButton>
Click me! <!-- 插槽内容 -->
</FancyButton>
而 <FancyButton>
的模板是这样的:
<button class="fancy-btn">
<slot></slot> <!-- 插槽出口 -->
</button>
<slot>
元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽内容 (slot content) 将在哪里被渲染。
最终渲染出的 DOM 是这样:
html
<button class="fancy-btn">Click me!</button>
渲染作用域
插槽内容无法访问子组件的数据。Vue 模板中的表达式只能访问其定义时所处的作用域,这和 JavaScript 的词法作用域规则是一致的。换言之:
父组件模板中的表达式只能访问父组件的作用域;子组件模板中的表达式只能访问子组件的作用域。
默认值
在外部没有提供任何内容的情况下,可以为插槽指定默认内容。——其中 no 为默认值
<slot name="upon">no</slot>
具名插槽
<slot>
元素可以有一个特殊的 attribute name
,用来给各个插槽分配唯一的 ID,以确定每一处要渲染的内容:
template
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
这类带 name
的插槽被称为具名插槽 (named slots)。没有提供 name
的 <slot>
出口会隐式地命名为“default”。
在父组件中使用 <BaseLayout>
时,我们需要一种方式将多个插槽内容传入到各自目标插槽的出口。此时就需要用到具名插槽了:
要为具名插槽传入内容,我们需要使用一个含 v-slot
指令的 <template>
元素,并将目标插槽的名字传给该指令:
template
<BaseLayout>
<template v-slot:header>
<!-- header 插槽的内容放这里 -->
</template>
</BaseLayout>
v-slot
有对应的简写 #
,因此 <template v-slot:header>
可以简写为 <template #header>
。其意思就是“将这部分模板片段传入子组件的 header 插槽中”。