emit 大家应该不陌生了,在很多时候父子组件需要进行事件传递的时候使用到,emit的字符串处理可能会繁琐一些
emit
首先就是写好父子组件的代码
App.js
export const App = {
name: 'App',
render() {
// emit
return h('div', {}, [h('div', {}, 'App'), h(Foo, {
// onAdd(a, b) {
// console.log('onAdd', a, b);
// },
onAddFooFoo(a, b) {
console.log('onAddFooFoo', a, b)
}
})])
},
setup() {
return {}
}
}
Foo.js
emit是setup第二个参数对象里的一个属性
export const Foo = {
render() {
const btn = h('button', {
onClick: this.emitAdd
}, 'emitAdd')
const foo = h('p', {}, 'foo')
return h('div', {}, [foo, btn])
},
setup(props, { emit }) {
const emitAdd = () => {
console.log('emitAdd')
// emit('add', 1, 2)
emit('add-foo-foo', 1, 2)
}
return {
emitAdd
}
}
}
首先解决setup传值问题,还是和props的处理方式一致
component.ts
import { emit } from "./componentEmit"
export function createComponentInstance(vnode) {
const component = {
vnode,
type: vnode.type,
setupState: {},
props: {},
emit: (event) => { } // 加上预设值
}
component.emit = emit.bind(null, component)
// 这里是一个处理方法,让用户使用emit时不需要传入instance
return component
}
function setupStatefulComponent(instance: any) {
const Component = instance.type
instance.proxy = new Proxy({ _: instance }, publicInstanceProxyHandlers)
const { setup } = Component
if (setup) {
// setup可以返回一个function,也可以返回一个object
// 返回function我们认为是它是组件的一个render函数
// 返回object认为是一个会把object注入到当前的组件的上下文中
const setupResult = setup(shallowReadonly(instance.props), {
emit: instance.emit // 这里就直接把emit放到对象里传过去
})
handleSetupResult(instance, setupResult)
}
}
接下来就实现给component.emit = emit的componentEmit.ts文件了
componentEmit.ts
import { camelize, toHandlerKey } from "../shared/index";
export function emit(instance, event, ...args) { // ...args 是为了接受多项传值
console.log('emit' + event);
const { props } = instance //那边bind的传值
const emitHandlerName = toHandlerKey(camelize(event))
const emitHandler = Reflect.get(props, emitHandlerName)
emitHandler && emitHandler(...args) // 展开多项传值,并传过去
}
shared.ts
camelize函数是为了实现xx-xx-xx这种串烧式写法,替换为驼峰写法,多重串烧也可以处理
capitalize函数是为了处理首字母大写
toHandlerKey函数是为了实现onXxx这种写法,并做了处理
export const camelize = (str: string) => str.replace(/-(\w)/g, (_, c: string) => c ? c.toUpperCase() : '')
// 等同于 const camelize = (str: string) => {
// return str.replace(/-(\w)/g, (_, c: string) => {
// return c ? c.toUpperCase() : ''
// })
// }
export const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1)
export const toHandlerKey = (str: string) => str ? `on${capitalize(str)}` : ''
结语
emit的实现式很简单的,主要是对字符串的处理是比较多的,不适应串烧写法会更简单,当然我这里也不是一比一完全还原了vue3的emit写法,只是核心。好好学习,天天向上!!