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

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

9917c2d554624ff3953a7dba.html

9917c2d554624ff3953a7dba.html

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

elem = elem || root

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

scanTag(elem, vmodels)

}

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

2. 执行扫描 scanTag

9917c2d554624ff3953a7dba.html

9917c2d554624ff3953a7dba.html

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

9917c2d554624ff3953a7dba.html

9917c2d554624ff3953a7dba.html

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

9917c2d554624ff3953a7dba.html

9917c2d554624ff3953a7dba.html

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

9917c2d554624ff3953a7dba.html

9917c2d554624ff3953a7dba.html

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

9917c2d554624ff3953a7dba.html

9917c2d554624ff3953a7dba.html

avalon.scanfunction scanText(textNode, vmodels) {

var bindings = extractTextBindings(textNode)

if (bindings.length) {

executeBindings(bindings, vmodels)

}

}

7.抽出文本绑定 extractTextBindings

9917c2d554624ff3953a7dba.html

9917c2d554624ff3953a7dba.html

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

9917c2d554624ff3953a7dba.html

9917c2d554624ff3953a7dba.html

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无非就干了一件事,扫描到指定的行为,发送数据给处理函数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/527690.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html的opacity标签,css中opacity是什么意思

css样式 给div样式opacity:0 是什么意思透明度 注意 ie低版本要实现透明度必须用ie特有的滤镜 而非简单的opacityCSS中 not(.active) { opacity: 0.3; } 是什么意思css的opacity让div和里面的div透明了怎样才让div里面的div不透明?不透明度会作用于整个元素以及它所…

frm考试可以用计算机,FRM考试,考生自己可以携带计算器吗?

因为FRM考试有大量的计算题,是需要用到计算器的,近日有考生咨询,参加考试,可以自己携带FRM计算器吗?答案当然是肯定,考生是可以携带FRM计算器的,但是要携带协会官方要求的型号,不是什…

不能访问win7计算机,局域网win7无法访问win10,win7访问不了局域网其他电脑

相信大家都遇到过在访问局域网时遇到过很多错误,导致文件无法正常进行共享,共享打印机等情况,那么当我们遇到这样的问题时应该怎么处理呢?接下来是小编给大家介绍的具体解决方法,一起来看看吧!方法/步骤1、…

计算机开关机命令,电脑自动关机命令

有的时候我们需要让电脑在一段时间工作而不能关机,但是工作完成之后不关机会造成用电浪费,那么使用自动关机命令,就不用担心电脑一直开着会浪费电啦。那么电脑自动关机命令怎么设置呢?下面给大家介绍一下吧。电脑自动关机命令1、首…

iphone计算机的声音怎么办,苹果耳机插电脑上没声音怎么办_苹果耳机插win10电脑没声音如何解决-win7之家...

通常我们将苹果耳机插入电脑的话是可以听歌或者语音说话的,然而近日有不少小伙伴将苹果耳机插入到win10电脑上要使用的时候,却发现没有声音,遇到这样的问题该怎么办呢,可能是设置有问题,本文给大家讲解一下苹果耳机插w…

电气与计算机学院院长论坛报告,我校电子系举办2019年电子信息学科院长论坛暨工程教育新进展研讨会...

2019年11月24日,由我校电子与电气工程系主办的“2019年电子信息学科院长论坛暨工程教育新进展研讨会”在国际会议厅举行。来自东北大学、电子科技大学、东南大学、西安交通大学、西安电子科技大学、大连理工大学、北京航空航天大学、北京邮电大学、燕山大学、南京邮…

楼梯计算机公式,各种楼梯面积的计算公式汇总

楼梯计算体积踏步体积梯板体积踏步体积三角形面积(1/2*踏步宽度*踏步高度)* 梯板净宽 * 踏步个数踏步个数 踏宽数1踏宽数 楼梯净长/踏步宽度(楼梯净长:等于踏步段水平投影净长,即扣减(墙)后的长度)踏步高度 楼梯高度/(踏步个数1)梯板净宽 楼梯宽度扣…

虚拟机随服务器启动,VMware Server中虚拟机随宿主机自动启动

访问虚拟机宿主http://:8222或者 https://:8333用宿主的管理员帐号登陆.Configure OptionsEdit HostSettingsEdit Virtual Machine Startup/ShutdownSettingsRefresh Network List选择上面那个加粗的选项点击即可进入并看到下面的界面!在vmware server里面不用那么麻…

dw服务器文件夹在哪里,Dreamweaver CC

Dreamweaver CC教程:查看文件和文件夹查看文件和文件夹您可以在“文件”面板中查看文件和文件夹,而无论它们是否与 Dreamweaver 站点相关联。在“文件”面板中查看站点、文件或文件夹时,您可以更改查看区域的大小。对于 Dreamweaver 站点&…

服务器不能访问共享文件夹权限,win访问服务器共享文件夹权限设置

win访问服务器共享文件夹权限设置 内容精选换一换开发过程中,您有任何问题可以在github上提交issue,或者在华为云对象存储服务论坛中发帖求助。接口参考文档详细介绍了每个接口的参数和使用方法。在OBS中,用户操作的基本数据单元是对象。OBS …

android 图片放大缩小_贴在手机上的显微镜,轻松放大400倍,化身“蚁人”玩转微观世界...

记得在漫威电影《蚁人》里,男猪脚只要穿上那套黑科技制服,按下开关,“咻”的一声就缩到蚂蚁大小,并操控蚂蚁、昆虫和自己并肩作战!!简直不要太酷!蚁人”进入微观世界,就像正常人去了…

按条件增加列_12个公式解决Excel按条件多列求和,掌握两、三个就够用了

【温馨提示】亲爱的朋友,阅读之前请您点击【关注】,您的支持将是我最大的动力!#职场众生相#日常工作中,在Excel表格中按条件求和也是经常用到的,一般根据条件求和的是一列数据,利用SUMIF函数即可解决&#…

小程序制作预算_小程序商城制作多少钱

现在有做微信小程序商城需求的企业越来越多,在选择小程序制作公司的时候,很多公司上来就报价几万,导致价格太贵让用户望而却步,其实微信小程序制作的价格是不同的,并且不同的制作公司报价也不一样,那么做一…

语言 ota_新增飞屏功能 ARCFOX αT首次OTA升级

[爱卡汽车 行业资讯原创]日前,爱卡汽车获悉,极狐 阿尔法T(ARCFOX αT)进行了首次OTA升级,车主将从12月20日起陆续收到OTA升级的推送消息,该车本次系统升级包大小约340M,升级时间约15分钟。据了解,极狐 阿尔…

git merging 怎么处理_如何让 Git 的输出对代码更友好?

关注公众号 “OpenSourceDaily” ,每天推荐给你优秀开源项目大家好,我是欧盆索思(opensource),每天为你带来优秀的开源项目!如今 Git 是每个开发人员必须掌握的技能,几乎每天我们都需要使用 Git,很多人可能…

处理入参_看看优秀的程序员是如何处理NPE的

点击上方 果汁简历 ,选择“置顶公众号”优质文章,第一时间送达西格玛的博客https://urlify.cn/7j2uMz在笔者几年的开发经验中,经常看到项目中存在到处空值判断的情况,这些判断,会让人觉得摸不这头绪,它的出…

id 怎么获取jira 评论_一篇文章教会你使用Python定时抓取微博评论

【Part1——理论篇】试想一个问题,如果我们要抓取某个微博大V微博的评论数据,应该怎么实现呢?最简单的做法就是找到微博评论数据接口,然后通过改变参数来获取最新数据并保存。首先从微博api寻找 抓取评论的接口,如下图…

单片机中存储器扩展位地址线怎么算_51单片机CPU结构各部件的原理详细分析

一、 51单片机串行口工作原理MCS-51系列单片机片内有一个串行I/O端口,通过引脚RXD(P3.0)和TXD(P3.1)可与外设电路进行全双工的串行异步通信。1.串行端口的基本特点8031单片机的串行端口有4种基本工作方式,通…

h5弹框滑动 ios_微信 iOS 版更新:细节大更新,你值得拥有

在9月17日,IOS 微信 7.0.7 正式上线了,和一周前安卓 微信 7.0.7 内测版相似,本次的微信更新并没有新功能的上线,更多的是细节上的改变优化。不知道大家有没有发现,iOS版微信从 7.0.5直接跳过7.0.6,直接更新…

jpa onetoone_拥抱开源从表设计到 JPA 实现

long may the sunshine.今天的我拿起键盘就是猛敲代码。果然,十分钟后各种 JPA 报错开始了。跟新手党一样,看到一个错误就解决一个,没有好好思考为什么会出现这样的错误。于是乎,遇到一个解决一个,解决一个又遇到一个&…