1.实现跨层组件通信
重温一下常用的父子组件通信方法:
//父组件
<template>
<my-header :title="title" @changeTitle="changeTitle"></my-header>
</tempale>
<script>
import myHeader from "@/components/Header.vue"; //引入组件
export default {
data(){
return{
title:"父传子测试"
}
},
components:{
"my-header":myHeader
},
methods:{
changeTitle(val){
this.title = val
}
}
}
</script>
//子组件 myheader.vue
<template>
<h1>{{ title }}</h1>
<button @click="triggerMethod">触发父组件方法</button>
</tempalte>
<script>
export default{
props: {//接收父组件出来的title
title:{
type: String,
default: ""
}
},
methods:{
triggerMethod:function(){
this.$emit("changeTitle","传参数"); //子组件通过$emit 与父组件通信
}
}
}
</script>
复制代码
provide/inject(提供/注入),可以实现跨层组件(祖孙)间通信,不需要将数据一层一层向下传递。
//父组件 Father.vue
<template>
<son></son>
</template>
<script>
import { defineComponent, reactive, provide, computed } from "vue";
import son from "@/components/Son";
export default defineComponent({
components: {
son
},
setup() {
let params = reactive({
name: "来自父亲的参数"
})
provide("name", computed(()=> params.name)); //用计算属性返回值能够动态传递来子/孙组件(当子孙组件通过方法触发修改name值时)
function changeName(val){
params.name = val; //子孙组件触发
}
provide("changeName",changeName);
}
})
</script>
复制代码
//儿子组件 Son.vue
<template>
<h2>{{ name }}</h2>
<button @click="changeName('儿子组件触发')">儿子组件触发Name修改</button>
<div class="grandson">
<grandson></grandson>
</div>
</template>
<script>
import grandson from "@/components/grandson";
import { defineComponent, inject } from "vue";
export default defineComponent({
components: { grandson },
setup() {
let name = inject("name"); //接收Father组件传来的name
let changeName = inject("changeName"); //接收方法
return {
name,
changeName,
};
},
});
</script>
复制代码
//孙子组件 grandson.vue
<template>
<h2>{{ name }}</h2>
<button @click="changeName('孙子组件触发')">孙子组件触发Name修改</button>
</template>
<script>
import { defineComponent, inject, watch } from "vue";
export default defineComponent({
name: "HelloWorld",
setup() {
let name = inject("name");
let changeName = inject("changeName");
watch(name,(newValue,oldValue)=>{
//这里可以监听name的变化
})
return {
name,
changeName,
};
},
});
</script>
复制代码
效果:子孙组件都接收到Father组件传来的参数"来自Father组件的参数"。
动态gif:当点击儿子组件或者孙子组件按钮时,触发changeName事件在Father组件上修改name值。
2.自动化批量引入模块
日常开发中经常会遇到导入多个模块,每个都要import,很麻烦。
使用webpack的api,通过require.context函数获取一个特定的上下文,实现自动化导入模块功能。
require.context(directory, useSubdirectories = false, regExp = /^.//);
//1.directory {String} -读取文件的路径
//2.useSubdirectories {Boolean} -是否遍历文件的子目录
//3.regExp {RegExp} -匹配文件的正则
let moduleFiles = require.context('../model', false, /\.js$/)
let res = {};
moduleFiles.keys().map(path => {
let methods = moduleFiles(path);
console.log(methods)
Object.keys(methods).forEach(key => {
if (key === "default") {
res[methods[key].name] = methods[key];
} else {
res[key] = methods[key];
}
})
})
export default res
复制代码
3.使用函数式组件
对于某些组件,如果我们只是用来显示一些数据,不需要管理状态、监听数据等。那么我们可以使用函数式组件代替传统组件。
//father.vue
<template>
<child :name="name"></child>
</template>
// child.vue
<template functional>
<div class="component">{{ props.name }}</div> //通过props接收父组件的传参
</template>
复制代码
4. 优雅更新Props
//father.vue
<template>
<div class="son">
<son v-model:name="name"></son>
</div>
</template>
//son.vue
<template>
<h2>{{ name }}</h2>
<button @click="changeName('儿子组件触发')">儿子组件触发Name修改</button>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
props: {
name: String,
},
setup(props) {
function changeName(val) {
this.$emit("update:name", val); //不需要再通过触发父组件的方法修改
}
return {
changeName,
};
},
});
</script>
复制代码
vue2.x 这样写<son :name.sync="name"></son>
vue3.x 详情参考官方文档 v3.cn.vuejs.org/guide/migra…
5.Vue3实现兄弟组件通信
Vue3移除了 $on
、$off
和 $once
方法。$emit
仍然包含于现有的 API 中,因为它用于触发由父组件声明式添加的事件处理函数。官方推荐: 事件总线模式可以被替换为使用外部的、实现了事件触发器接口的库,例如 mitt 或 tiny-emitter。
详情:v3.cn.vuejs.org/guide/migra…
//eventBus.js
import Emitter from 'tiny-emitter'
const emitter = new Emitter();
export default {
$on: (...args) => emitter.on(...args),
$once: (...args) => emitter.once(...args),
$off: (...args) => emitter.off(...args),
$emit: (...args) => emitter.emit(...args),
}
复制代码
//兄弟组件1
import emitter from "@/assets/eventBus";
setup() {
emitter.$on("some-event", (...arg) => {
console.log(arg);
});
}
//兄弟组件2
<template>
<div class="about">
<h1>This is an about page</h1>
<button @click="triggerSiblingMethod">触发兄弟组件</button>
</div>
</template>
<script>
import { defineComponent } from "vue";
import emitter from "@/assets/eventBus";
export default defineComponent({
setup() {
function triggerSiblingMethod() {
emitter.$emit("some-event", "value1", "value2", 3);
}
return {
triggerSiblingMethod,
};
},
});
</script>
复制代码
点击兄弟组件2的按钮后,兄弟组件1输入下面信息。