2017-07-22
@click
利用 @click 来绑定事件的思路
如果写过 Vue 相信一定不会忘记 Vue 的模版语法。
@click 可以用于绑定事件,比如:
00<div>
01    <button @click="clicking()">Click Me!</button>
02</div>
Vue 实例化组件的时候,会解析这些模版,然后完成这些事情。
当然本文目的不在讨论 Vue 的模版语法,而是讨论一个实现这样的事情的思路。

# 表征组件的对象

诸多框架均实现了 “网页是一颗组件树” 的抽象,上面许许多多的组件,一般而言都有模版和数据,然后框架做的事情,就是把数据渲染在模版上,把事件绑定好,最后插入到 DOM 树上。
因此,组件,其实是模版和数据的又一个实例,比如如下数据:
00var config = {
01    sayName(){
02        console.log('you click me'); 
03        console.log(`my name is ${this.name}`); 
04    }, 
05    name: 'wow', 
06    template: `
07        <div>
08            <h1 class="title">Hello</h1>
09            <button @click="sayName">sayName</button>
10        </div>
11    `
12}
上述代表了一个简单的组件,上面有标题,和一个按钮,点击的时候,会执行 sayName (这里利用了 @click 来绑定事件)
而且我们假设,调用 render('#container', data) 将会把该组件渲染到 #container 里,同时,也会把模版里面响应的 @click 事件绑定上去。

# tplParser

因为是把组件渲染到 #container 的,所以还需要遍历 #container ,这是树的遍历问题,用递归解决是最便捷的。
经过观察和考虑可以想到,要正确的解析 @click 只需做到:
  1. 遍历所有结点的属性们
  2. 遍历单个属性们里面的属性

针对第一点,使用递归来遍历。
00function tplParser(root, config){
01    Array.from(root.children).forEach(child => {
02        /*
03         * 这里对 child.attributes 进行处理 把 @click 取出来 
04         */
05
06        // Just Regard Child As A Tree's Root 
07        tplParser(child, config); 
08    }); 
09}
由于当结点没有后代的时候, root.children 其实是空的,也意味着里面的 travel 不会被执行,递归收敛。

针对第二点,利用 forEach 就可以了。
00var todoSomething = attr => {
01    // todoSomething with attr 
02}
03Array.from(child.attributes).forEach(todoSomething);

# 完整的写法

00// root 是根节点 
01// config 是传入配置 上面写着对应事件的 handler
02function tplParser(root, config){
03    Array.from(root.children).forEach(child => {
04        // child 的属性 attributes 
05        Array.from(child.attributes).forEach(attr => {
06            if (attr.name.startsWith('@') && attr.value in config){
07                let eventName = attr.name.slice(1); 
08
09                child.addEventListener(
10                    // such as "click"
11                    eventName,
12                    // such as () => console.log('clicking!') 
13                    config[attr.value]
14                );
15            }
16        }); 
17
18        // Just Regard Child As A Tree's Root 
19        tplParser(child, config); 
20    })
21}

# 下一步是什么

在完成了 @click 之后我立即想到了完成数据绑定的思路,具体请看我的下篇博文




回到顶部