前面我们是将所有的逻辑放到一个App.vue中:
我们来分析一下下面代码的嵌套逻辑,假如我们将所有的代码逻辑都放到一个App.vue组件中:
<template>
<div>
<h2>Headerh2>
<h2>NavBarh2>
div>
<div>
<h2>Bannerh2>
<ul>
<li>商品列表1li>
<li>商品列表2li>
<li>商品列表3li>
<li>商品列表4li>
<li>商品列表5li>
ul>
div>
<div>
<h2>Footerh2>
<h2>免责声明h2>
div>
template>
<script>
export default {
};
script>
<style scoped>style>
- **父**组件**传**递给**子**组件:`通过props属性`;
- **子**组件传递给**父**组件:`通过$emit触发事件`;
代码:
ShowMessage.vue
<template>
<div>
<h2>{{title}}h2>
<p>{{content}}p>
<p>-----------p>
div>
template>
<script>
export default {
props: ['title', 'content']
}
}
script>
<style scoped>
style>
App.vue
<template>
<div>
<show-message
id="abc"
class="why"
title="哈哈哈"
content="我是哈哈哈哈"
message-info=""
>show-message>
<show-message title="呵呵呵" content="我是呵呵呵呵">show-message>
<show-message :title="title" :content="content">show-message>
<show-message
:title="message.title"
:content="message.content"
>show-message>
<show-message v-bind="message">show-message>
div>
template>
<script>
import ShowMessage from "./ShowMessage.vue";
export default {
components: {
ShowMessage
},
data() {
return {
title: "嘻嘻嘻",
content: "我是嘻嘻嘻嘻",
message: {
title: "嘿嘿嘿",
content: "我是嘿嘿嘿",
},
};
},
};
script>
<style scoped>style>
分为以下三种情况:
- 当组件有单个根节点时,非Prop的Attribute将自动添加到根节点的Attribute中:
![-](https://img-blog.csdnimg.cn/ebef1bf2f6d444ad895c43a9ef51ba5a.png)
inheritAttrs: false
:
this.$emit
的方式发出去事件;CounterOperation.vue
<template>
<div>
<button @click="increment">+1button>
<button @click="decrement">-1button>
<input type="text" v-model.number="num">
<button @click="incrementN">+nbutton>
div>
template>
<script>
export default {
// vue3要先注册 触发哪些事件
// 数组写法
// emits: ["add", "sub", "addN"],
// 对象写法的目的是为了进行参数的验证
emits: {
add: null,
sub: null,
// 对传递参数的验证
addN: (num, name, age) => {
console.log(num, name, age);
if (num > 10) {
return true
}
return false;
}
},
data() {
return {
num: 0
}
},
methods: {
increment() {
console.log("+1");
this.$emit("add");
},
decrement() {
console.log("-1");
this.$emit("sub");
},
incrementN() {
this.$emit('addN', this.num, "why", 18);
}
}
}
script>
<style scoped>
style>
父组件App.vue
<template>
<div>
<h2>当前计数: {{counter}}h2>
<counter-operation @add="addOne"
@sub="subOne"
@addN="addNNum">
counter-operation>
div>
template>
<script>
import CounterOperation from './CounterOperation.vue';
export default {
components: {
CounterOperation
},
data() {
return {
counter: 0
}
},
methods: {
addOne() {
this.counter++
},
subOne() {
this.counter--
},
addNNum(num, name, age) {
console.log(name, age);
this.counter += num;
}
}
}
script>
<style scoped>
style>
TabControl.vue
<template>
<div class="tab-control">
<div class="tab-control-item"
:class="{active: currentIndex === index}"
v-for="(title, index) in titles"
:key="title"
@click="itemClick(index)">
<span>{{title}}span>
div>
div>
template>
<script>
export default {
emits: ["titleClick"],
props: {
titles: {
type: Array,
default() {
return []
}
}
},
data() {
return {
currentIndex: 0
}
},
methods: {
itemClick(index) {
this.currentIndex = index;
this.$emit("titleClick", index);
}
}
}
script>
<style scoped>
.tab-control {
display: flex;
}
.tab-control-item {
flex: 1;
text-align: center;
}
.tab-control-item.active {
color: red;
}
.tab-control-item.active span {
border-bottom: 3px solid red;
padding: 5px 10px;
}
style>
父组件App.vue
<template>
<div>
<tab-control :titles="titles" @titleClick="titleClick">tab-control>
<h2>{{contents[currentIndex]}}h2>
div>
template>
<script>
import TabControl from './TabControl.vue';
export default {
components: {
TabControl
},
data() {
return {
titles: ["衣服", "鞋子", "裤子"],
contents: ["衣服页面", "鞋子页面", "裤子页面"],
currentIndex: 0
}
},
methods: {
titleClick(index) {
this.currentIndex = index;
}
}
}
script>
<style scoped>
style>
<template>
<div>
<home>home>
div>
template>
<script>
import Home from './Home.vue';
export default {
components: {
Home
},
provide: {
name: "why",
age: 18,
}
}
script>
<style scoped>
style>
Home.vue是中间的组件:
<template>
<div>
<home-content>home-content>
div>
template>
<script>
import HomeContent from './HomeContent.vue';
export default {
components: {
HomeContent
}
}
script>
HomeContent.vue是获取数据的组件:
<template>
<div>
<h2>HomeContenth2>
<h2>{{name}}-{{age}}h2>
div>
template>
<script>
export default {
inject: ["name", "age"]
}
script>
如果Provide中提供的一些数据是来自data,那么我们可能会想要通过this来获取:
这个时候会报错:
如何解决这个问题呢?
npm install mitt
eventbus.js
:
这种工具类文件一般放在utils文件夹里面
import mitt from 'mitt';
const emitter = mitt();
// 可以创建很多个emitter对象const emitter = mitt();export default emitter;
// export const emitter1 = mitt();
// export const emitter2 = mitt();
// export const emitter3 = mitt();
export default emitter;
代码:
这里用About.vue触发事件,HomeContent.vue监听事件
App.vue
<template>
<div>
<home/>
<about/>
div>
template>
<script>
import Home from './Home.vue';
import About from './About.vue';
export default {
components: {
Home,
About
}
}
script>
<style scoped>
style>
Home.vue
<template>
<div>
<home-content>home-content>
div>
template>
<script>
import HomeContent from './HomeContent.vue';
export default {
components: {
HomeContent
}
}
script>
<style scoped>
style>
About.vue
<template>
<div>
<button @click="btnClick">按钮点击button>
div>
template>
<script>
import emitter from './utils/eventbus';
export default {
methods: {
btnClick() {
console.log("about按钮的点击");
emitter.emit("why", {name: "why", age: 18});
// emitter.emit("kobe", {name: "kobe", age: 30});
}
}
}
script>
<style scoped>
style>
HomeContent.vue
<template>
<div>
div>
template>
<script>
import emitter from './utils/eventbus';
export default {
created() {
emitter.on("why", (info) => {
console.log("why:", info);
});
emitter.on("kobe", (info) => {
console.log("kobe:", info);
});
// 监听所有事件
emitter.on("*", (type, info) => {
console.log("* listener:", type, info);
})
}
}
script>
<style scoped>
style>
其他API的补充,如果在某些情况下我们想要取消事件,可以使用下面的API:
// 取消emitter中所有的监听
emitter.all.clear();
// 定义一个函数
function onFoo() {}
emitter.on("foo", onFoo); // 监听
emitter.off("foo", onFoo); // 取消监听