props传递数据
简单的不跨层级传递
父->子:v-bind:value
子->父:this.$emit()
子组件中使用props进行属性接收,如果只是简单的给子组件传递数据,使用v-bind已经够用。更多情况子组件改变了props传递的数据后,需要立即同步到父组件中。
需要更新父组件中数据
第一种做法,给绑定message数据,使用@update:message=”updateEvent”进行事件绑定。
第二种做法使用语法糖,vue2中可以给属性绑定xxx.sync,在子组件中使用this.$emit(“update:xxx”, “this is text.”)能够同步更新父组件中xxx的值。
父Boss组件中
// 简单的传递数据给子组件<Manager :message="msg"></Manager>// 子组件更新了数据,要同步到父组件<Manager :message="msg" @update:message="updateEvent"></Manager>// 简写的语法糖<Manager :message.sync="msg"></Manager>
子Manager组件,在methods中进行事件派发
manager(){this.$emit("update:message", "请假休闲休息");}
vue3中去掉.sync属性,改用v-model:xxx=”demoText”
<Manager v-model:message="msg"></Manager>
ts中保证props的类型PropType
interface ColumnProps{id: string;title: string;avatar: string;description: string;}export default ButtonComponent({name:'ColumnList',props:{list:{type: Array as PropType<ColumnProps[]>,//type: <PropType<ColumnProps>> Array,required:true}}})
为了类型推论,让我们在使用属性的时候获取更丰富的类型提示,比如在这里我们定义了一个属性 list,使用 vue 默认的 Array,只能确定它是一个数组类型,不能确定数组里面的每一项到底是什么样子的。你在 setup 中,看 props.list 就是一个any数组,但是如果使用PropType
多层级传递
$parent / $children
Boss组件 -> Manager1组件 -> Worker1组件
-> Manager2组件 -> Worker2组件
$dispatch/$broadcast
使用场景:多层级组件间事件的通信。主要使$emit方法
在main.js中定义
// 向上传递事件 $dispatchVue.prototype.$dispatch = function(eventName, value){let parent = this.$parent;while(parent){parent.$emit(eventName, value);parent = parent.$parent;}}//element中的实现 https://github.com/ElemeFE/element/blob/dev/src/mixins/emitter.jsdispatch(componentName, eventName, params) {var parent = this.$parent || this.$root;var name = parent.$options.componentName;while (parent && (!name || name !== componentName)) {parent = parent.$parent;if (parent) {name = parent.$options.componentName;}}if (parent) {parent.$emit.apply(parent, [eventName].concat(params));}}// 向下通知事件 $broadcastVue.prototype.$broadcast = function(eventName,value){let $broad = (children)=>{children.forEach(child => {child.$emit(eventName, value);if(child.$children){$broad(child.$children)}})}$broad(this.$children);}
$attrs/$listeners
使用场景:多层级间组件通信,可以把顶级的属性/事件,在中间层通过$attrs/$listeners进行传递,使用层直接接收。
$attrs:表示属性的集合
$listeners:表示方法的集合(vue3已废弃)
示例:boss组件中的属性和方法直接传递给worker
Boss组件
//在boss组件中使用manager,并将属性传递给manger,但是manger不用解析,不使用<Manager :message="msg" :value="value" @work="change"></Manager>
Manger组件
// Manager组件中使用Worker组件,可以使用$attrs传递所有属性,$listeners传递事件<Worker v-bind="$attrs" v-on="$listeners"></Worker>
注意:要给该组件设置一个属性,inheritAttrs: false。表示不把属性显示在Dom
Worker组件
<template><div><p>{{ message }}</p><button @click="handle">员工2号</button></div></template><script>export default {name: "worker2",props: {message: {type: String,default: "",},},methods: {handle() {console.log("员工2号执行boss中的click事件",this.$listeners);this.$listeners.work("员工2号按时完成工作");},},};</script>
员工组件可以接收到Boss的所有属性和方法。
Provide/Inject
使用场景:多层级间组件通信,可以在顶层定义数据provide,中间层不用处理,直接在使用层用inject接收
注意:此方案多使用于组件开发,业务开发中不要使用。
boss组件传递数据给worker组件
// bossexport default {provide() {// 此操作会把boss组件的data传递给下层return { boss: this };},components: {Manager1,Manager2,},data() {return {msg: "老板说,经理都来加班!!!",value: "老板说,经理都来加班!!!",money: "1个亿",};},}
woker组件可以直接通过inject来使用
<template><div><h3>{{this.boss.money}}</h3></div></template>// jsexport default {name: "worker1",inject:["boss"],}
Ref
使用场景:父组件可以拿到子组件中定义的方法,直接在父组件中使用。
ref可以用的dom元素上,获取到dom节点。
在boss组件中定义
// 使用manager<Managerref="manager"></Manager>// jsmounted() {this.$refs.manager1.bossUseManagerMethod();},
在Manger组件中定义方法
methods:{bossUseManagerMethod(){console.log("bossUseManagerMethod");}}
使用ref时⚠️注意:
通过 :ref =某变量 添加ref(即加了:号),
如果想获取该ref时需要加 [0]即this.$refs[refsArrayItem] [0];
如果不是:ref =某变量的方式而是 ref =某字符串时则不需要加 即this.$refs[refsArrayItem]
EventBus
使用场景:多组件间以及跨组件间进行事件通信
vue2,直接在main.js中定义
Vue.prototype.$Bus = new Vue()
共有四个组件boss/manger/worker1/worker2
woker1和worker2是manger的子组件,worker1中触发一个事件,boss和worker2组件都能接收到。
首先在worker1组件中定义事件
mounted(){this.$Bus.$emit("useBus");}
在boss组件和worker2组件使用$on接收,$off是取消事件
mounted() {// 因为boss组件先于worker1组件挂载,要使用$nextTick下次循环调用this.$nextTick(() => {this.$Bus.$on("useBus", () => {console.log("boss组件被触发");});});}
worker2组件接收$bus事件。
mounted() {this.$nextTick(() => {this.$Bus.$on("useBus", () => {console.log("员工2号组件被触发");});});},
vue3中,不推荐使用
但是也可以单独定义一个Bus文件
// 为保持和vue2版本中使用bus一致,emit,on,off前面都加了$class Bus{list: { [key: string]: Array<Function> };constructor() {// 收集订阅信息,调度中心this.list = {};}// 订阅$on(name: string, fn: Function) {this.list[name] = this.list[name] || [];this.list[name].push(fn);}// 发布$emit(name: string, data?: any) {if (this.list[name]) {this.list[name].forEach((fn: Function) => {fn(data);});}}// 取消订阅$off(name: string) {if (this.list[name]) {delete this.list[name];}}}export default new Bus() as Bus;
jsx语法render函数(IView框架常用语法)
作用域插槽v-slot(element框架常用语法)
