MVVM试图更加清晰的讲用户界面(UI)开发从应用程序的业务逻辑与行为中心分离,由于,不少这样的模式的实现都须要利用声明式数据绑定来实现讲View(视图)工做从其余层分离css

因此出现了一大堆自定义的声明式的语法:html

如:Avalonnode

顾名思义,自定义声明语法,那么游览器自己是不能识别的,那么如何游览器能过识别自定义的HTML语法,它能让你讲行为关系到HTML元素或者属性上,甚至能让你创造具备自定义行为的新元素呢,咱们暂且讲这个过程称之为“HTML编译”吧。数组

咱们先看一段HTML代码浏览器

{{ w }} x {{ h }}

W:

H:

avalon.define("box", function(vm) {

vm.w = 100;

vm.h = 100;

vm.click = function() {

vm.w = parseFloat(vm.w) + 10;

vm.h = parseFloat(vm.h) + 10;

}

})

avalon.scan(document.getElementById('box'));

HTML结构中充斥了大量的ms开头的自定义标签,还有{}插值表达式。。等等ruby

声明1:

ms-controller="box"

avalon提供ms-controller, ms-important来指定VM在视图的做用范围。好比有两个VM,它们都有一个firstName属性,在DIV中,若是咱们用 ms-controller="VM1", 那么对于DIV里面的{{firstName}}就会解析成VM1的firstName中的值。app

声明2:

ms-css-width="w" ms-css-height="h"

用来处理样式框架

声明3:

ms-click="click"

avalon经过ms-on-click或ms-click进行事件绑定,并在IE对事件对象进行修复,并统一了全部浏览器对return false的处理dom

其实就是把部分的行为操做提高到了dom上了,而后有框架在后台给你处理好,经过加入各类自定义的属性可让任何的HTML元素都实现这样的行为函数

具体看源码的执行流程:

总的来讲就是匹配每一给节点上的属性,经过匹配分配到指定的bindingHandlers处理函数上,以后的处理本章不暂时不涉及

//扫描入口

avalon.scan = function(elem, vmodel)

//扫描子节点

function scanNodes(parent, vmodels, callback)

//开始扫描

function scanTag(elem, vmodels)

//扫描文本

function scanText(textNode, vmodels)

//扫描表达式

function scanExpr(str)

//扫描属性节点

function scanAttr(el, vmodels)

//抽取绑定

function executeBindings(bindings, vmodels)

//抽取文本绑定

function extractTextBindings(textNode)

看看命名就大概能猜出函数的做用了

1.入口函数  avalon.scan

avalon.scanavalon.scan = function(elem, vmodel) {

elem = elem || root

var vmodels = vmodel ? [].concat(vmodel) : []

scanTag(elem, vmodels)

}

默认从文本的根documentElement开始,若是传递了第一个elem,那么就是指定了扫描的做用域了,相似 jQuery( selector, [ context ] )

2. 执行扫描 scanTag

avalon.scanvmodels = vmodels || []

var a = elem.getAttribute(prefix + "skip")

var b = elem.getAttribute(prefix + "important")

var c = elem.getAttribute(prefix + "controller")

//这三个绑定优先处理,其中a > b > c

if (typeof a === "string") {

return

} else if (b) {

if (!VMODELS[b]) {

return

} else {

vmodels = [VMODELS[b]]

elem.removeAttribute(prefix + "important")

}

} else if (c) {

var newVmodel = VMODELS[c]

if (!newVmodel) {

return

}

vmodels = [newVmodel].concat(vmodels)

elem.removeAttribute(prefix + "controller")

}

scanAttr(elem, vmodels) //扫描特性节点

if (!stopScan[elem.tagName.toLowerCase()] && rbind.test(elem.innerHTML)) {

scanNodes(elem, vmodels)

}

依次要检测是当前元素上是否有ms-skip,ms-important,ms-controller属性,用于最开始的处理

若是ms-controller存在就取出vm视图模型对象

清除这个自定义属性

执行sacnAttr 属性扫描

3. 扫描属性节点 scanAttr

avalon.scanfunction scanAttr(el, vmodels) {

var bindings = []

for (var i = 0, attr; attr = el.attributes[i++]; ) { 1

if (attr.specified) { 2

var isBinding = false

if (attr.name.indexOf(prefix) !== -1) { 3

//若是是以指定前缀命名的

var type = attr.name.replace(prefix, "")

if (type.indexOf("-") > 0) { 4

var args = type.split("-")

type = args.shift()

}

isBinding = typeof bindingHandlers[type] === "function" 5

}

if (isBinding) {

bindings.push({ 6

type: type,

args: args || [],

element: el,

remove: true,

node: attr,

value: attr.nodeValue

})

}

}

}

executeBindings(bindings, vmodels)

}

attributes 属性返回包含被选节点属性的 NamedNodeMap。

若是在文档中设置了属性值,则 specified 属性返回 true.

是不是avalon的HTML指示 "ms-"开头

若是还指定了参数

能找到对应的处理函数

bindings 保存参数

4. 执行绑定 executeBindings

avalon.scanfunction executeBindings(bindings, vmodels) {

bindings.forEach(function(data) {

var flag = bindingHandlers[data.type](data, vmodels)

if (flag !== false && data.remove) { //移除数据绑定,防止被二次解析

data.element.removeAttribute(data.node.name)

}

})

}

找到对应的类型的bindingHandlers方法,传入数据与vm对象,实现处理

移除数据绑定,防止被二次解析

5. 扫描子节点 scanNodes

avalon.scanfunction scanNodes(parent, vmodels, callback) {

var nodes = aslice.call(parent.childNodes);

callback && callback();

for (var i = 0, node; node = nodes[i++]; ) {

if (node.nodeType === 1) {

scanTag(node, vmodels) //扫描元素节点

} else if (node.nodeType === 3) {

scanText(node, vmodels) //扫描文本节点

}

}

}

其实就循环处理子节点列表了,注意要过滤空文本类型

若是是元素节点就递归循环scanTag方法

若是是文本节点就scanText

6. 扫描文本 scanText

avalon.scanfunction scanText(textNode, vmodels) {

var bindings = extractTextBindings(textNode)

if (bindings.length) {

executeBindings(bindings, vmodels)

}

}

7.抽出文本绑定 extractTextBindings

avalon.scanfunction extractTextBindings(textNode) {

var bindings = [],

tokens = scanExpr(textNode.nodeValue)//分解表达式

if (tokens.length) {

while (tokens.length) { //将文本转换为文本节点,并替换原来的文本节点

var token = tokens.shift()

var node = DOC.createTextNode(token.value)

if (token.expr) { //若是分解的是表达式

var filters = token.filters

var binding = {

type: "text",

node: node,

args: [],

element: textNode.parentNode,

value: token.value,

filters: filters

}

if (filters && filters.indexOf("html") !== -1) {

avalon.Array.remove(filters, "html")

binding.type = "html"

binding.replaceNodes = [node]

}

bindings.push(binding) //收集带有插值表达式的文本

}

documentFragment.appendChild(node)

}

textNode.parentNode.replaceChild(documentFragment, textNode)

}

return bindings

}

文本解析是个比较复杂的东西,能够匹配不少种状况,因此须要加入不少解析的规则

scanExpr 就是扫描的表达式的匹配

documentFragment 先把这个结构让到文档碎片中,性能处理

8. 表达式匹配scanExpr

avalon.scanfunction scanExpr(str) {

var tokens = [],

value, start = 0,

stop

if (rexpr.test(str)) {

do {

var stop = str.indexOf(openTag, start)

if (stop === -1) {

break

}

value = str.slice(start, stop)

if (value) { // {{ 左边的文本

tokens.push({

value: value,

expr: false

})

}

start = stop + openTag.length

stop = str.indexOf(closeTag, start)

if (stop === -1) {

break

}

value = str.slice(start, stop)

if (value) { //{{ }} 之间的表达式

var leach = []

if (value.indexOf("|") > 0) { // 注意排除短路与

value = value.replace(rfilters, function(c, d, e) {

leach.push(d + (e || ""))

return c.charAt(0)

})

}

tokens.push({

value: value,

expr: true,

filters: leach.length ? leach : void 0

})

}

start = stop + closeTag.length;

} while (1);

value = str.slice(start);

if (value) { //}} 右边的文本

tokens.push({

value: value,

expr: false

})

}

}

return tokens

}

代码很长,可是处理的东西确很简单的

好比:

"{{ w }} x {{ h }}" 一个插值表达式,那么应该如何解析

分析这个表达式,解析能够分三块

1.  {{ w }}

2    x

3   {{ h }}

左右两边都是vm视图全部关联的属性,中间x就是求值

那么解析的规则,分解3个部分,组成处理数据

tokens 就有3个组成对象

expr: true

filters: undefined

value: " w "

expr: false

value: " x "

expr: true

filters: undefined

value: " h "

解析后分解成绑定的数据

而后就是一次循环了, 遇到条件stopScan就终止了

因此总结scan无非就干了一件事,扫描到指定的行为,发送数据给处理函数

html 属于mvvm框架,前端MVVM框架avalon揭秘 - HTML编译器相关推荐

  1. 前端框架MVC/MVVM分析系列

    Backbone Backbone.js 是一个在JavaScript环境下的 模型-视图-控制器 (MVC) 框架.任何接触较大规模项目的开发人员一定会苦恼于各种琐碎的事件回调逻辑.以及金字塔般的代 ...

  2. Mvvm 前端数据流框架精讲

    原文链接, 如果感兴趣可以加QQ群: 157937068, 一起交流. 本次分享是带大家了解什么是 mvvm,mvvm 的原理,以及近几年产生了哪些演变. 同时借 mvvm 这个话题拓展到对各类前端数 ...

  3. 又想到了模板引擎和前端MVVM框架

    最近接手了一个和报表有关的项目.项目后端的大部分工作都是在操作数据库,作为一个后端新手谈不上有什么感觉.但对于看了前端的写法之后,还是有一点点感想. 项目前端主要使用jQuery及其插件,也许这就是大 ...

  4. Fre:又一个小而美的前端MVVM框架

    halo,大家好,好久不贱呢! 最近因为看了一些 be 的小说,整个人都比较致郁::>_<:: 就在昨天,我用了一天的时间写了 fre,又一个小而美的前端MVMM框架 可能你觉得,有了 v ...

  5. Fre:又一个小而美的前端MVVM框架 1

    halo,大家好,好久不贱呢! 最近因为看了一些 be 的小说,整个人都比较致郁::>_<:: 就在昨天,我用了一天的时间写了 fre,又一个小而美的前端MVMM框架 可能你觉得,有了 v ...

  6. 一个 MVC 框架以 MVVM 之「魂」复活了!

    Mokit 最初编写于 2012 年,是一个面向移动应用的前端 mvc 框架,v3 版本进行了大量的重构或重写,并尽可能的保持了和之前版本类似的 API, v3 是一个「极轻量」的 MVVM 框架,相 ...

  7. 实现 MVVM 类 Vue 迷你框架(五)

    如何实现 MVVM 类 Vue 迷你框架(五) 上面几节课我们已经把数据代理,响应式处理搞完了,接下来需要做什么呢?当然是最难的一部分了,就是我们的编译模板. 使用到的dom编程方法 element. ...

  8. WPF -- MVVM框架 - CommunityToolkit.Mvvm

    目录 1. 简介 2. Nuget安装 3. 开发环境 4. 属性通知 5. 命令 5.1 RelayCommand 5.2 AsyncRelayCommand 6. Messenger 7. Ioc ...

  9. 前端Js框架 UI框架汇总 特性 适用范围 选择

    身为一个资深后端工程师,面对层出不穷的前端框架,总让人眼花缭乱,做一个综合解析贴,从全局着眼,让我们明白各种前端框架的应用范围,为如何选择前端框架,从不同的维度提供一些线索,做为一个长期优化贴,欢迎指 ...

最新文章

  1. 关于CSS样式浏览器兼容问题的一些注意事项
  2. 长春高中计算机考试时间安排,长春部分高中期末考试时间出炉!
  3. Photoshop CS3 ICO 图标保存插件
  4. RabbitMQ基础介绍
  5. bottomnavigationview放大两边没有_有没有什么HAPPYEND的动漫?
  6. 力扣——LCP 37. 最小矩形面积(困难)
  7. css中的@符号的用处
  8. 电力技术监督导则_会议报道:2019年电力行业燃煤发电企业节能监督管理专业技术人员及燃煤发电机组能效水平对标管理办法培训班...
  9. 线性代数知识荟萃(4)——矩阵相抵
  10. webdriver中PDF控件无法显示的问题(IE兼容性)
  11. Adobe Photoshop入门教程:零基础学会PS抠图拼贴
  12. 推动区块链技术应用创新河南开展区块链应用场景需求和典型应用案例征集工作
  13. 【有料c++题目周刊 | 第四期】贝克街神探
  14. 校招----深信服测试笔经面经
  15. nginx 过滤ip
  16. 大数据时代,做大数据开发要学Java框架吗?
  17. 我有好的东西和大家一起分享
  18. 974. Subarray Sums Divisible by K [Medium]
  19. 路由器恢复出厂设置上网方式服务器无响应,路由器恢复出厂设置后不能联网了如何解决...
  20. Unity3D相关知识点笔记汇总

热门文章

  1. 玩 High API 系列之:智能云相册
  2. 云原生时代,开发者如何构筑容器安全?
  3. 大数据成长之路:谈谈那些必须学习的Linux基础知识
  4. 牵手大企,关于图形计算、HPC与AI,NVIDIA言有尽而意无穷!
  5. 2019年普通高等程序员招生统一考试
  6. 腾讯也有“神盾局”?秀出“技术肌肉”就靠TA了……
  7. datax参数设置_DataX Web数据增量同步配置说明
  8. 学计算机就业靠谱吗,2018年计算机专业就业怎么样?
  9. 2021计算机应用基础统考,2021年度计算机应用基础统考练习题及答案.doc
  10. quercus mysql_让PHP运行在Glassfish中:quercus配置