zoukankan      html  css  js  c++  java
  • 前端MVVM框架avalon揭秘

    MVVM试图更加清晰的讲用户界面(UI)开发从应用程序的业务逻辑与行为中心分离,因为,很多这样的模式的实现都需要利用声明式数据绑定来实现讲View(视图)工作从其他层分离

    所以出现了一大堆自定义的声明式的语法:

    如:Avalon

    1. 作用域绑定(ms-controller, ms-important)
    2. 模板绑定(ms-include)
    3. 数据填充(ms-text, ms-html)
    4. 类名切换(ms-class, ms-hover, ms-active)
    5. 事件绑定(ms-on,……)
    6. 显示绑定(ms-visible)
    7. 插入绑定(ms-if)
    8. 双工绑定(ms-duplex,原来的ms-model)
    9. 样式绑定(ms-css)
    10. 数据绑定(ms-data)
    11. 布尔属性绑定(ms-checked, ms-selected, ms-readonly, ms-disabled, ms-enabled)
    12. 字符串属性绑定(ms-title, ms-src, ms-href……)
    13. 万能属性绑定(ms-attr)
    14. 万能绑定(ms-bind)
    15. 数组循环绑定(ms-each)
    16. 对象循环绑定(ms-with)
      等等………

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

    我们先看一段HTML代码

    <div id='box' ms-controller="box">
    
        <div style=" background: #a9ea00;" ms-css-width="w" ms-css-height="h"  ms-click="click"></div>
    
        <p>{{ w }} x {{ h }}</p>
        <p>W: <input type="text" ms-model="w" data-event="change"/></p>
        <p>H: <input type="text" ms-model="h" /></p>
    
    </div>
    
        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开头的自定义标签,还有{}插值表达式。。等等

    声明1:

    ms-controller="box"
    

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

    声明2:

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

    用来处理样式

    声明3:

    ms-click="click"
    

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

    其实就是把部分的行为操作提升到了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.scan

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

    2. 执行扫描 scanTag

    avalon.scan
    • 依次要检测是当前元素上是否有ms-skip,ms-important,ms-controller属性,用于最开始的处理
    • 如果ms-controller存在就取出vm视图模型对象
    • 清除这个自定义属性
    • 执行sacnAttr 属性扫描

    3. 扫描属性节点 scanAttr

    avalon.scan

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

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

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

    如果还指定了参数

    能找到对应的处理函数

    bindings 保存参数

    4. 执行绑定 executeBindings

    avalon.scan

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

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

    5. 扫描子节点 scanNodes

    avalon.scan

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

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

    如果是文本节点就scanText

    6. 扫描文本 scanText

    avalon.scan

    7.抽出文本绑定 extractTextBindings

    avalon.scan

    文本解析是个比较复杂的东西,可以匹配很多种情况,所以需要加入很多解析的规则

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

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

    8. 表达式匹配scanExpr

    avalon.scan

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

    比如:

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

    分析这个表达式,解析可以分三块
    1.  {{ w }} 

    2    x 

    3   {{ h }}

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

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

    tokens 就有3个组成对象

    1. expr: true
    2. filters: undefined
    3. value: " w "
    1. expr: false
    2. value: " x "
    1. expr: true
    2. filters: undefined
    3. value: " h "

    解析后分解成绑定的数据

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

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

  • 相关阅读:
    mysql实现主从复制
    go get时候 timeout
    linux 修改/etc/profile文件之后 没有效果
    初试 laravel
    php 实现单个大文件(视频)的 断点上传
    UEditor图片左对齐右对齐 要的作用显示之后 保存之后没有效果
    docker 实现 mysql+nginx+php
    redis
    easyPoi框架的excel导入导出
    从生产计划的角度认识精益生产
  • 原文地址:https://www.cnblogs.com/aaronjs/p/3228457.html
Copyright © 2011-2022 走看看