2018年首个计划是学习vue源码,查阅了一番资料之后,决定从第一个commit开始看起,这将是一场持久战!本篇介绍directive的简单实现,主要学习其实现的思路及代码的设计(directive和filter扩展起来非常方便,符合设计模式中的 开闭原则 )。
构思API
<div id="app" sd-on-click="toggle | .button">
 <p sd-text="msg | capitalize"></p>
 <p sd-class-red="error" sd-text="content"></p>
 <button class="button">Toggle class</button>
</div>
var app = Seed.create({
 id: 'app',
 scope: {
  msg: 'hello',
  content: 'world',
  error: true,
  toggle: function() {
   app.scope.error = !app.scope.error;
  }
 }
});
实现功能够简单吧--将scope中的数据绑定到app中。
核心逻辑设计
指令格式
以 sd-text="msg | capitalize" 为例说明:
- sd 为统一的前缀标识
- text 为指令名称
- capitalize 为过滤器名称
其中 | 后面为过滤器,可以添加多个。 sd-class-red 中的red为参数。
代码结构介绍
main.js 入口文件
// Seed构造函数
const Seed = function(opts) {
};
// 对外暴露的API
module.exports = {
 create: function(opts) {
  return new Seed(opts);
 }
};
directives.js
module.exports = {
 text: function(el, value) {
  el.textContent = value || '';
 }
};
filters.js
module.exports = {
 capitalize: function(value) {
  value = value.toString();
  return value.charAt(0).toUpperCase() + value.slice(1);
 }
};
就这三个文件,其中directives和filters都是配置文件,很易于扩展。
实现的大致思路如下:
1.在Seed实例创建的时候会依次解析el容器中node节点的指令
2.将指令解析结果封装为指令对象,结构为:
| 属性 | 说明 | 类型 | 
|---|---|---|
| attr | 原始属性,如 sd-text | String | 
| key | 对应scope对象中的属性名称 | String | 
| filters | 过滤器名称列表 | Array | 
| definition | 该指令的定义,如text对应的函数 | Function | 
| argument | 从attr中解析出来的参数(只支持一个参数) | String | 
| update | 更新directive时调用 typeof def === 'function' ? def : def.update | Function | 
| bind | 如果directive中定义了bind方法,则在 bindDirective中会调用 | Function | 
| el | 存储当前element元素 | Element | 
