前言vue3新个性,hooks钩子函数,用过react hooks的应该很相熟,思维是统一的,学习老本也不高,跟一般的函数相比,最大的特点就是能再函数中应用组件/页面的一些生命周期了,这时你应该会马上想到vue2的mixin函数,然而hooks会比mixin更加灵便,且副作用更小。vue3组件传值除了emit和props,举荐provide/injeect,store。跨组件传值曾经不能像之前一样new Vue(),因为实例上的$on、$off 和 $once 实例办法被删除了。所以我找了他的代替计划:miit: Tiny 200b functional event emitter / pubsub.即小型性能事件发射接管,相似vue2版本中的$emit、$on
npm install --save mitt在组件层级简单的状况下,这十分有必要,且集体认为,应用频率较高,该需要出险频率十分高附上链接:https://www.npmjs.com/package...
前置知识点getCurrentInstance: 获取以后组件的实例,顺便提一句,vue3不反对操作prototype一样去挂载全局办法,倡议应用getCurrentInstance().appContext.config.globalProperties拜访全局属性getCurrentInstance 只能在 setup 或生命周期钩子中调用。
需要在组件开发中,不仅有子组件须要调用父组件的场景,也有场景是相同的,父组件须要调用子组件的计划,vue3+ts如果你间接ref.xxx拜访子组件的办法或报错,因为它并不知道你的子组件中有什么办法,有人间接把整个子组件$emit给父组件,而后调用他的属性,不举荐此计划,不思考性能,我感觉很繁琐。那么,咱们实现的emitter就必须要有以下的根底性能:
向上发送事件(dispatch)向下发送事件(broadcast)只调用一次工夫(once)接管事件(on)销毁事件(off)代码实function on(type, handler) { const handleWrapper = (e) => { const { value, type, emitComponentInstance } = e if (type === BROADCAST) { // 监听是否是播送事件 if (isChildComponent(currentComponentInstance, emitComponentInstance)) { // 播送即以后接管的组件是子组件时,因为播送是从向往下 handler && handler(...value) } } else if (type === DISPATCH) { // 监听是dispatch,以后接管的组件是父组件 if (isChildComponent(emitComponentInstance, currentComponentInstance)) { // 判断以后组件是否是发送事件组件的子组件的判断逻辑 handler && handler(...value) } } else { handler && handler(...value) } } // 把接管到的handler保存起来,因为须要off掉,留神这个handler必要放弃惟一 ,function是援用类型,传递给off的时候,必须找到雷同的地址才行。这里的`wrapper`变量能够应用`Symbol`类型 handler[wrapper] = handleWrapper emitter.on(type, handleWrapper) }function broadcast(type, ...args) { emitter.emit(type, { type: BROADCAST, // 事件类型,辨别第一个参数,第一个参数是事件名称 emitComponentInstance: currentComponentInstance, // 以后组件实例 value: args }) }//逻辑同上,工夫类型不同function dispatch(type, ...args) { emitter.emit(type, { type: DISPATCH, emitComponentInstance: currentComponentInstance, value: args }) }// off掉的是惟一雷同的handler!function off(type, handler) { emitter.off(type, handler[wrapper])}// 执行一次的原理就是调用后即off掉function once(type, handler) { const handleOn = (...args) => { handler && handler(...args) off(type, handleOn) } on(type, handleOn)}残缺代码import { getCurrentInstance } from 'vue'import mitt from 'mitt'const DISPATCH = 'dispatch'const BROADCAST = 'broadcast'const wrapper = Symbol('wrapper')const emitter = mitt()export function useEmitter() { const currentComponentInstance = getCurrentInstance() function on(type, handler) { const handleWrapper = (e) => { const { value, type, emitComponentInstance } = e if (type === BROADCAST) { if (isChildComponent(currentComponentInstance, emitComponentInstance)) { handler && handler(...value) } } else if (type === DISPATCH) { if (isChildComponent(emitComponentInstance, currentComponentInstance)) { handler && handler(...value) } } else { handler && handler(...value) } } // Save the real handler because the need to call off handler[wrapper] = handleWrapper emitter.on(type, handleWrapper) } function broadcast(type, ...args) { emitter.emit(type, { type: BROADCAST, emitComponentInstance: currentComponentInstance, value: args }) } function dispatch(type, ...args) { emitter.emit(type, { type: DISPATCH, emitComponentInstance: currentComponentInstance, value: args }) } function off(type, handler) { emitter.off(type, handler[wrapper]) } function once(type, handler) { const handleOn = (...args) => { handler && handler(...args) off(type, handleOn) } on(type, handleOn) } return { on, broadcast, dispatch, off, once }}/** * check componentChild is componentParent child components * @param {*} componentChild * @param {*} componentParent */function isChildComponent(componentChild, componentParent) { const parentUId = componentParent.uid while (componentChild && componentChild?.parent?.uid !== parentUId) { componentChild = componentChild.parent } return Boolean(componentChild)}根本应用const { dispatch, on, broadcast } = useEmitter()on('update:modelValue', (v) => { emit('update:modelValue', v) dispatch('custom.value.change', v)})broadcast('fieldReset', 'reset')