多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] * * * * * ## 1 源代码文件 ### 1-1 指令注册 ~~~ src\seed\lang.share.js directive: function (name, definition) { return this.directives[name] = definition } ~~~ ### 1-2 指令实现 ~~~ src\directives\ ~~~ ## 2 流程分析 ### 2-1 指令注册 ~~~ src\seed\lang.share.js directive: function (name, definition) { return this.directives[name] = definition } ~~~ > name:指令的名称 > definition:指令的配置信息 将指令以name为键,definition为值对应存储到this.directives数组 ###2-2 指令实现入口 ~~~ src\directives\modern.js require('./controller') //处理属性样式 require('./attr.modern') require('./css') require('./visible') //处理内容 require('./expr') require('./text') require('./html') //需要用到事件的 require('./class.hover.active') require('./on') require('./duplex/modern') //处理逻辑 require('./if') require('./for') require('./widget') ~~~ > 加载各个具体指令实现文件 ### 2-3 指令实现举例 ~~~ src\directives\if.js avalon.directive('if', { priority: 5, parse: function (binding, num) { return 'vnode' + num + '.props["ms-if"] = ' + avalon.quote(binding.expr) + ';\n' }, diff: function (cur, pre) { if (cur.type !== pre.type) { var list = cur.change || (cur.change = []) avalon.Array.ensure(list, this.update) } }, update: function (dom, vnode, parent) { var dtype = dom.nodeName.toLowerCase() var vtype = vnode.type if (dtype !== vtype) { if (dom.nodeType === 1) { avalon.caches[vnode.nodeValue] = dom parent.replaceChild(avalon.vdomAdaptor(vnode).toDOM(), dom) } else { var s = dom.signature || dom.nodeValue var keep = avalon.caches[s] if (keep) { parent.replaceChild(keep, dom) patch([keep], [vnode]) } else { var el = avalon.vdomAdaptor(vnode).toDOM() parent.replaceChild(el, dom) avalon.caches[s] = el } } } } }) ~~~ > 调用avalon.directive()注册指令到全局指令数组 > 指令的配置信息包括 > > priority:指令优先级 > > parse:指令解析方法 > > diff:虚拟dom指令处理方法 > > update:虚拟dom指令刷新方法 ## 3 if指令分析 ~~~ avalon.directive('if', { priotity: parse: diff: update: }} ~~~ > 注册if指令到全局指令数组 avalon.directives ~~~ priority: 5, ~~~ > if指令优先级为5 指令的绑定解析排序时使用 ~~~ parse: function (binding, num) { return 'vnode' + num + '.props["ms-if"] = ' + avalon.quote(binding.expr) + ';\n' }, ~~~ > if指令的解析方法 指令的解析过程使用 返回字符串 `vnode1111.props["ms-if"]="binding.expr";` ~~~ diff: function (cur, pre) { if (cur.type !== pre.type) { var list = cur.change || (cur.change = []) avalon.Array.ensure(list, this.update) } }, ~~~ > if指令的比较方法 虚拟dom比较中if指令比较使用 > 判断虚拟节点类型为if后,获取当前if节点变化节点, > 将变化节点的更新方法注册为this.update ~~~ update: function (dom, vnode, parent) { var dtype = dom.nodeName.toLowerCase() var vtype = vnode.type if (dtype !== vtype) { if (dom.nodeType === 1) { avalon.caches[vnode.nodeValue] = dom parent.replaceChild(avalon.vdomAdaptor(vnode).toDOM(), dom) } else { var s = dom.signature || dom.nodeValue var keep = avalon.caches[s] if (keep) { parent.replaceChild(keep, dom) patch([keep], [vnode]) } else { var el = avalon.vdomAdaptor(vnode).toDOM() parent.replaceChild(el, dom) avalon.caches[s] = el } } } } ~~~ > if指令的更新方法 在视图同步刷新过程中使用 > 获取dom节点名称与虚拟dom节点类型 > 比较节点类型,调用对应虚拟dom节点的toDOM存储 ## 4 总结 ### 4-1 意义 指令是mvvm的v层核心,可以看做浏览器运行的动态语言 ### 4-2 思路 指令的实现通过avalon.directive(name,definition) 注册到全局指令数组avalon.directives中 ### 4-3 指令配置的调用过程(指令核心思想) #### 指令priority的使用 ~~~ src\strategy\parser\parseBindings.js function parseBindings(props, num, elem) { ...... if (!bindings.length) { ret += '\tvnode' + num + '.skipAttrs = true\n' } else { avalon.parseExpr(binding) bindings.sort(byPriority).forEach(function (binding) { ret += directives[binding.type].parse(binding, num, elem) }) } ...... } function byPriority(a, b) { return a.priority - b.priority } ~~~ >[info] parseBindings()调用bindigs.sort()按照优先级排序各个指令 #### 指令parse的使用 >[info] for指令解析 ~~~ src\strategy\parser\parseView.js str += avalon.directives['for'].parse(nodeValue, num) ~~~ >[info] widget指令解析 ~~~ src\strategy\parser\parseView.js if (hasWidget) { str += avalon.directives.widget.parse({ expr: hasWidget, type: 'widget' }, num, el) hasWidget = false } ~~~ >[info] 其他指令的解析 ~~~ src\strategy\parser\parseBindings.js var hasBindings = parseBindings(el.props, num, el) if (hasBindings) { str += hasBindings } ~~~ ~~~ src\strategy\parser\parseView.js function parseBindings(props, num, elem) { ...... if (!bindings.length) { ret += '\tvnode' + num + '.skipAttrs = true\n' } else { avalon.parseExpr(binding) bindings.sort(byPriority).forEach(function (binding) { ret += directives[binding.type].parse(binding, num, elem) }) } ..... } ~~~ #### 指令的diff使用 ~~~ src\strategy\diff.js function diff(current, previous) { ...... case '#text': if (!cur.skipContent) { // 调用表达式比较 directives.expr.diff(cur, pre) } case '#comment': if (cur.directive === 'for') { // 调用for指令比较 i = directives['for'].diff(current, previous, i) } else if (cur.directive ) { // 调用if widget指令比较 directives[cur.directive].diff(cur, pre) } break default: if (!cur.skipAttrs) { // 属性比较 diffProps(cur, pre) } if (!cur.skipContent) { // 递归比较子节点 diff(cur.children, pre.children || emptyArr) } break ...... } ~~~ ~~~ src\strategy\diff.js function diffProps(current, previous) { for (var name in current.props) { var match = name.match(rbinding) if (match) { var type = match[1] try { if (directives[type]) { directives[type].diff(current, previous || emptyObj, type, name) } } catch (e) { avalon.log(current, previous, e, 'diffProps error') } } } } ~~~ >[info] 调用指令的diff比较虚拟dom #### 指令的update使用