VueStudyNote
VueStudyNote copied to clipboard
18 实现emit
实现起来很简单,因为之前的代码已经处理了x-on(@),所以直接绑定即可。
实现
框架代码增加 _events字段和$emit方法
class Xiao{
// 事件
_events : any
/**
* 调用事件
*
* @param {*} event
*/
$emit(event: String){
// 无需绑定this,方法生成的时候已经绑定了
this._events[event]()
}
}
更新组件的时候的时候,如果是子组件,初始化数据。
function updateComponent(vm: Xiao) {
let proxy = vm
// 虚拟dom里面的创建函数
proxy.h = h
// 新的虚拟节点
// 指令的信息已经自动附带再vnode里面
let vnode = vm.$render.call(proxy)
// 把实例绑定到vnode中,处理指令需要用到
setContext(vnode, vm)
// 处理子组件
setComponentHook(vnode, vm)
// 其他代码
******
}
/**
* 实现组件功能
*
* 采用snabbdom的hook,在insert和update的时候更新数据。
*
* @param {*} vnode
* @param {*} vm
*/
function setComponentHook(vnode: any, vm: Xiao) {
if (!vnode.sel) {
return
}
// 查看是否组成了组件?
const Comp = Xiao.component(vnode.sel)
if (Comp) {
vnode.data.hook = {
insert: (vnode) => {
log('component vnode', vnode)
// 创建子组件实例
let app = new Comp()
app.$parent = vm
const propsData = vnode.data.props
// 把计算后的props数据代理到当前vue里面
initProps(app, propsData)
// 绑定事件
if(vnode.data.on){
initEvent(app, vnode.data.on)
}
// 保存到vnode中,更新的时候需要取出来用
vnode.childContext = app
// 渲染
app.$mount(vnode.elm)
},
update: (oldvnode, vnode) => {
const app = oldvnode.childContext
// 更新update属性
updateProps(app, vnode.data.props)
vnode.childContext = app
}
}
}
// 递归
if (vnode.children) {
vnode.children.forEach(function (e) {
setComponentHook(e, vm)
}, this)
}
}
/**
* 绑定事件
*
* @param {*} vm
* @param {*} on
*/
export function initEvent(vm: any, on: Object) {
log('initEvent', on)
vm._events = on
}
测试代码
<h1>$emit测试</h1>
<div id="counter-event-example">
<p>{{ total }}</p>
<button-counter @increment="incrementTotal"></button-counter>
<button-counter @increment="incrementTotal2"></button-counter>
</div>
<script>
Xiao.component('button-counter', {
template: '<button @click="incrementCounter">{{ counter }}</button>',
data: function () {
return {
counter: 0
}
},
methods: {
incrementCounter: function () {
console.log('incrementCounter')
this.counter += 1
this.$emit('increment')
}
},
})
new Xiao({
el: '#counter-event-example',
data: {
total: 0
},
methods: {
incrementTotal: function () {
this.total += 1
},
incrementTotal2: function () {
this.total -= 1
}
}
})
</script>