Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

18 实现emit #20

Open
xwjie opened this issue Jan 21, 2018 · 0 comments
Open

18 实现emit #20

xwjie opened this issue Jan 21, 2018 · 0 comments

Comments

@xwjie
Copy link
Owner

xwjie commented Jan 21, 2018

实现起来很简单,因为之前的代码已经处理了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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant