23-mini-vue 实现 emit 功能

实现 emit 功能

  1. 功能点
  • 实现 emit 函数,用于触发组件自定义事件
  • 需求分析
    • 在组件实例上挂载 emit 方法
    • 组件通过 props 接收事件处理函数
    • 触发事件时调用对应的处理函数
  1. 代码实现
  • 页面上要实现的功能
js 复制代码
// Foo.js 子组件
import { h } from '../lib/guide-mini-vue.esm.js'

export const Foo = {
  setup(props,{emit}) { // ✅ emit 解构传递
    // console.log(props.count, 'count');
    const handleClick = () => {
      emit('add',1,2,3) // ✅ emit 触发父组件自定义事件,并进行参数传递
      emit('add-money-brother') // ✅ emit 触发父组件自定义事件(烤肉串命名)
    }
    return {
      handleClick
    }
  },
  render() {
    const btn = h('button', {
      onClick: this.handleClick
    }, 'emit click')
    return h("div", {
    }, ["foo:" + this.count, btn])
  },
}
js 复制代码
// App.js 父组件
import { h } from '../lib/guide-mini-vue.esm.js'
import { Foo } from './Foo.js'

window.self = null
export const App = {
  name: 'App',
  render() {
    window.self = this
    return h("div",{
      id: 'root',
      class: ['red', 'hard'],
    },
    [h("p",{class:"red"}, "hi"),h(Foo,{count: 1,
      onAdd(a,b,c) { // ✅ 自定义事件触发 + 传参
        console.log('我是父组件',a,b,c);
      },
      onAddMoneyBrother() { // ✅ 烤肉串式命名自定义事件触发
        console.log('I am Father Component');
        
      }
    })]
    )
  },
  setup() {
    return {
      msg: "mini-vue-haha",
    }
  }
}
  • 具体的实现步骤
js 复制代码
// componentEmit.ts  
// ✅ 这里的 emit 方法,挂载在实例上,后续直接传入 setup, 在页面被解构出来使用
//     换句话说,这里的 emit 就是页面上调用的 emit
//     可是页面上 传入的都是 add / add-money-brother 这些名称参数,要和父组件中的 自定义事件名对上,拿到对应的方法执行,就得做一番转换
// TPP 先实现一个特定的需求,然后扩展到通用的需求,这里直接展示的是最终结果
export function emit(instance, event, ...args) {
  // 调用 子组件传过来的函数
  const { props } = instance
  const camelize = (str) => { // ✅ 驼峰转化
    return str.replaceAll(/-(\w)/g, (_, c: string) => {
      return c ? c.toUpperCase() : ''
    })
  }
  const capitalize = (str) => { // ✅ 首字母大写
    return str.charAt(0).toLocaleUpperCase() + str.slice(1)
  }
  const handlerkey = (str) => { // ✅ 拼接出 事件处理函数名
    return str ? 'on' + capitalize(str) : ''
  }
  const handlerName = handlerkey(camelize(event))
  const handler = props[handlerName]
  handler && handler(...args)
}
js 复制代码
// component.ts
import { emit } from "./componentEmit"
export function createComponentInstance(vnode) {
  const component = {
    vnode,
    type: vnode.type,
    setupState: {},
    props: {},
    emit:()=>{} // ✅ 这里初始化占一个位置
  }
  component.emit = emit.bind(null, component) as any // ✅ 这里 null 是this指向, component 作为第一个参数传入
  return component
}
function setupStatefulComponents(instance: any) {
  const Component = instance.vnode.type
  const { setup } = Component
  instance.proxy = new Proxy({_: instance}, PublicInstanceProxyHandlers)
  if(setup) { 
    const setupResult = setup(shallowReadonly(instance.props),{ 
      emit: instance.emit // ✅ 这里将实例上的 emit 传入
    })
    handleSetupResult(instance, setupResult)
  }
}
js 复制代码
// shared/ index.ts ✅ 方法抽离 
export const camelize = (str) => {
  return str.replaceAll(/-(\w)/g, (_, c: string) => {
    return c ? c.toUpperCase() : ''
  })
}
const capitalize = (str) => {
  return str.charAt(0).toLocaleUpperCase() + str.slice(1)
}
export const handlerkey = (str) => {
  return str ? 'on' + capitalize(str) : ''
}
相关推荐
lerhxx6 小时前
AI 应用如何高效优雅地恢复中断?—— "连接解耦 + 状态持久化"
前端·javascript
计算机魔术师6 小时前
METR 演示 AI 智能体如何篡改 Inspect 评估记录以掩盖不当行为
前端
前端snow6 小时前
ai agent --- 异步处理之 Rabbit MQ
前端
念何架构之路6 小时前
zap扩展生态与总结
java·前端·数据库
独孤九剑打醒他7 小时前
【原创开源】【概念设计】源 - 栅 - 漏 - 栅 - 源 横向双栅 MOS,低压交流多值逻辑芯片探索
前端·其他·架构·开源·硬件工程
mantou1327 小时前
我给 AI Agent 做了个「油猴」:让 Claude Code / Codex 直接用你已登录的浏览器
前端·javascript·后端
默_笙7 小时前
🍕 一个主编、三个工种、两本手册:搭一支 AI 调研队
前端·javascript
纸片人7 小时前
Blender 建模 + Three.js 展示:和 AI 一起做一个光储充超充站数字孪生大屏
前端
智能直播7 小时前
网络RTMP拉流不卡顿、声音不同步?一文讲透缓冲区、时间戳与MEDAI V2实战调优
前端
第七页独白7 小时前
汽车零件厂如何通过 QMS 真正落地 IATF 16949——QMS软件系统:品质检验-内审稽核-8d客诉管理:全星质量管理软件系统
java·前端·数据库