switer / switer.github.io

Personal homepage
https://switer.github.io
5 stars 0 forks source link

What is directive ? #28

Open switer opened 9 years ago

switer commented 9 years ago

在 Angular, Vue.js等MVVM框架中,都包含指令(directive)的概念,directive实际上是一种针对DOM操作的抽象封装,并通过框架处理,将DOM操作逻辑与DOM元素进行自动化绑定,用一个简单的声明式语法简化了DOM操作逻辑中的给元素命名查询目标元素进行DOM操作步骤。

举个小例子,比如我们有一个header组件,它的HTML片段内容是:

<div class="header">
    <button>按钮</button>
</div>

如果我们希望给这里的按钮添加一个高亮的class,用zepto的代码是这样写的:

var $ = require('zepto');
var $btn = $('.header button')
$btn.addClass('highlight')

由以上小例子可以看出,我们在写JS交互逻辑的时候,几乎所有的JS交互逻辑都像以下流程一样:

初始化/数据变更/事件触发 --> 给目标元素命名(或者使用DOM树结构)--> 用选择器选中目标元素 --> 进行DOM操作

为此,封装DOM操作并自动化将DOM操作与元素绑定,可以减少1/2的交互逻辑代码(1个步骤替换3步骤),甚至做到根据DOM操作与元素与及数据进行绑定,那就可以用一个绑定声明减少了全部的手动步骤。

根据这一思路,我们先实现DOM操作封装与

<div class="header">
    <button binding-class="highlight:isOn">按钮</button>
</div>

组件的HTML中声明了一个click事件,绑定JS模块中的onBtnClick函数,JS模块的代码为:

// 绑定时依赖的数据
var data = {
    isOn: true
}
// 封装DOM操作
function addClassOrRemove (el, clazz, cnd) {
    var $el = $(el)
    cnd ? $el.addClass(clazz) : $el.remove(clazz) 
}
// 将DOM操作与元素绑定,返回操作步骤
function classBinding () {
    var tar = document.querySelector('[binding-class]')
    var dec = $(tar).attr('binding-class')
    var clazz = desc.split(':')[0]
    var field = desc.split(':')[1].trim()
    return function () {
        addClassOrRemove(tar, clazz, data[field])
    }
}
// 进行绑定操作,获取绑定后的操作方法
var updateClassAction = classBinding()
// 初始化时更新
updateClassAction()

显然,在完成DOM操作与DOM元素的绑定后,以后的每次更新触发场景中一个步骤就可以完成DOM元素的更新。 我们需要更懒惰一点,把手动触发更新的操作也省略了,如何? 那么我们需要现实监听数据的变更,在不考虑兼容IE9的情况下,我们可以使用ES5的defineProperty方法来实现:

var data = {}
var _isOn
Object.defineProperty(data, 'isOn', {
    get: function () {
        return _isOn
    },
    set: function (nextValue) {
        _isOn = nextValue
        // 在监听到数据变更后立即触发UI更新
        updateClassAction()
    }
})

这就是MVVM的数据绑定的实现,在框架帮助下完成以上一系列的绑定行为,要完成根据状态给按钮添加/移除高亮的class,我们只需要这样一个属性标志:

<div class="header">
    <button binding-class="highlight: isOn">按钮</button>
</div>

个人认为,使用属性声明的方式自动化绑定优于具名选择器的方式操作DOM元素。从开发效率角度,我们省去了给元素命名查询目标元素进行DOM操作这3步操作,从维护性角度,我们也省却了知道文档结构知道选择器标志2个步骤。