zoukankan      html  css  js  c++  java
  • MVVM框架avalon在兼容旧式IE

    迷你MVVM框架avalon在兼容旧式IE做的努力

    当前标签: avalon

    共3页: 1 2 3 下一页 
    迷你MVVM框架avalon在兼容旧式IE做的努力 司徒正美 2014-03-13 11:40 阅读:741 评论:6  
     
    迷你MVVM框架 avalonjs 组件编写指南 司徒正美 2014-02-28 14:55 阅读:1268 评论:5  
     
    迷你MVVM框架 avalonjs 1.2发布 司徒正美 2014-02-19 09:31 阅读:649 评论:2  
     
    迷你MVVM框架 avalonjs 1.1发布 司徒正美 2014-01-25 12:28 阅读:751 评论:4  
     
    2013年最后的收成:avalon1.0正式发布 司徒正美 2014-01-13 10:25 阅读:4845 评论:45  
     
    迷你MVVM框架 avalonjs 0.99发布 司徒正美 2013-12-18 14:46 阅读:1059 评论:3  
     
    迷你MVVM框架 avalonjs 0.98发布 司徒正美 2013-11-20 15:11 阅读:975 评论:1  
     
    使用avalon实现SKU组合查询功能 司徒正美 2013-11-18 10:47 阅读:1393 评论:1  
     
    angular与avalon对复杂对象的修改 司徒正美 2013-11-17 09:20 阅读:857 评论:1  
     
    for in 循环的输出顺序问题 司徒正美 2013-10-30 09:52 阅读:1474 评论:1  
     
    avalon最佳实践 司徒正美 2013-10-24 10:30 阅读:2442 评论:4  
     
    迷你MVVM框架 avalonjs 0.97发布 司徒正美 2013-10-21 16:52 阅读:1306 评论:4  
     
    ms-class的进化 司徒正美 2013-10-15 21:54 阅读:655 评论:1  
     
    利用状态模式处理多个模态弹出层的显示隐藏 司徒正美 2013-09-24 10:58 阅读:1401 评论:3  
     
    迷你MVVM框架 avalonjs 0.96发布 司徒正美 2013-09-21 11:43 阅读:1101 评论:3  
     
    使用avalon 实现一个订座系统 司徒正美 2013-09-19 14:31 阅读:1516 评论:4  
     
    迷你MVVM框架 avalonjs 0.95发布 司徒正美 2013-09-07 22:14 阅读:1387 评论:2  
     
    使用avalon 实现一个序列号功能 司徒正美 2013-09-07 10:11 阅读:1409 评论:3  
     
    迷你MVVM框架 avalonjs 0.94发布 司徒正美 2013-08-26 09:48 阅读:644 评论:7  
     
    迷你MVVM框架 avalonjs 0.93发布 司徒正美 2013-08-17 09:50 阅读:770 评论:2  
     
     
    很多时候,写代码就像砌砖头,只要我们不关心盖楼的原因、建筑的原理、土木工程基础和工程经验,就算我们砌了100栋高楼,我们也就只是一个砌砖工人,永远也成为不了一个工程师,更别说建筑师了。而那些包工头也只会把我们当成劳动力罢了。——左耳朵耗子

    avalon在兼容旧式IE上做了大量工作,从而让它更接地气,完美地运行于国内的各种奇葩浏览器中。

    首先是Object.defineProperties的模拟,正因为有这东西,才能让avalon是纯事件驱动地同步视图,而不用脏检测,从而获得更高的性能。

     //IE6-8使用VBScript类的set get语句实现
        if (!defineProperties && window.VBArray) {
            window.execScript([
                "Function parseVB(code)",
                "	ExecuteGlobal(code)",
                "End Function"
            ].join("
    "), "VBScript")
    
            function VBMediator(accessingProperties, name, value) {
                var accessor = accessingProperties[name]
                if (arguments.length === 3) {
                    accessor(value)
                } else {
                    return accessor()
                }
            }
            defineProperties = function(name, accessingProperties, normalProperties) {
                var className = "VBClass" + setTimeout("1"),
                        buffer = []
                buffer.push(
                        "Class " + className,
                        "	Private [__data__], [__proxy__]",
                        "	Public Default Function [__const__](d, p)",
                        "		Set [__data__] = d: set [__proxy__] = p",
                        "		Set [__const__] = Me", //链式调用
                        "	End Function")
                //添加普通属性,因为VBScript对象不能像JS那样随意增删属性,必须在这里预先定义好
                for (name in normalProperties) {
                    buffer.push("	Public [" + name + "]")
                }
                buffer.push("	Public [" + 'hasOwnProperty' + "]")
                //添加访问器属性 
                for (name in accessingProperties) {
                    if (!(name in normalProperties)) { //防止重复定义
                        buffer.push(
                                //由于不知对方会传入什么,因此set, let都用上
                                "	Public Property Let [" + name + "](val" + expose + ")", //setter
                                "		Call [__proxy__]([__data__], "" + name + "", val" + expose + ")",
                                "	End Property",
                                "	Public Property Set [" + name + "](val" + expose + ")", //setter
                                "		Call [__proxy__]([__data__], "" + name + "", val" + expose + ")",
                                "	End Property",
                                "	Public Property Get [" + name + "]", //getter
                                "	On Error Resume Next", //必须优先使用set语句,否则它会误将数组当字符串返回
                                "		Set[" + name + "] = [__proxy__]([__data__],"" + name + "")",
                                "	If Err.Number <> 0 Then",
                                "		[" + name + "] = [__proxy__]([__data__],"" + name + "")",
                                "	End If",
                                "	On Error Goto 0",
                                "	End Property")
                    }
                }
                buffer.push("End Class") //类定义完毕
                buffer.push(
                        "Function " + className + "Factory(a, b)", //创建实例并传入两个关键的参数
                        "	Dim o",
                        "	Set o = (New " + className + ")(a, b)",
                        "	Set " + className + "Factory = o",
                        "End Function")
                window.parseVB(buffer.join("
    ")) //先创建一个VB类工厂
                return window[className + "Factory"](accessingProperties, VBMediator) //得到其产品
            }
    

    option元素的value值的提取。在规范中,如果用户没有显式定义value,则会对其innerHTML进行两边对空白操作,作为value值。但如何判定用户是否显示定义value值呢,IE67是没有hasAttribute方法,此外还有其他兼容问题,而jQuery的做法太罗索。看avalon的实现:

        var roption = /^<option(?:s+w+(?:s*=s*(?:"[^"]*"|'[^']*'|[^s>]+))?)*s+value[s=]/i
        var valHooks = {
            "option:get": function(node) {
                //在IE11及W3C,如果没有指定value,那么node.value默认为node.text(存在trim作),但IE9-10则是取innerHTML(没trim操作)
                if (node.hasAttribute) {
                    return node.hasAttribute("value") ? node.value : node.text
                }
                //specified并不可靠,因此通过分析outerHTML判定用户有没有显示定义value
                return roption.test(node.outerHTML) ? node.value : node.text
            },
            //.....
          }
    

    旧式IE下高性能获对所有绑定属性:

        //IE67下,在循环绑定中,一个节点如果是通过cloneNode得到,自定义属性的specified为false,无法进入里面的分支,
        //但如果我们去掉scanAttr中的attr.specified检测,一个元素会有80+个特性节点(因为它不区分固有属性与自定义属性),很容易卡死页面
        if (!"1" [0]) {
            var cacheAttr = createCache(512)
            var rattrs = /s+(ms-[^=s]+)(?:=("[^"]*"|'[^']*'|[^s>]+))?/g,
                    rquote = /^['"]/,
                    rtag = /<w+(?:(["'])[^"]*?(1)|[^>])*>/i
            var getAttributes = function(elem) {
                if (elem.outerHTML.slice(0, 2) == "</") {//处理旧式IE模拟HTML5新元素带来的伪标签
                    return []
                }
                var str = elem.outerHTML.match(rtag)[0]
                var attributes = [],
                        match,
                        k, v;
                if (cacheAttr[str]) {
                    return cacheAttr[str]
                }
                while (k = rattrs.exec(str)) {
                    v = k[2]
                    var name = k[1].toLowerCase()
                    match = name.match(rmsAttr)
                    var binding = {
                        name: name,
                        specified: true,
                        value: v ? rquote.test(v) ? v.slice(1, -1) : v : ""
                    }
                    attributes.push(binding)
                }
                return cacheAttr(str, attributes)
            }
        }
    

    avalon允许使用script, noscript, textaea作为子模块的容器,但script节点需要修改type属性,textarea要手动display:none,noscript无疑是最好的选择,但noscript在IE78中竟然抽风了,在chrome下也有坑。avalon被逼又正则一番了……

    var rnoscripts = /<noscript.*?>(?:[sS]+?)</noscript>/img
    var rnoscriptText = /<noscript.*?>([sS]+?)</noscript>/im
    if (el.tagName === "NOSCRIPT" && !(el.innerHTML || el.fixIE78)) { //IE7-8 innerText,innerHTML都无法取得其内容,IE6能取得其innerHTML
        var xhr = getXHR() //IE9-11与chrome的innerHTML会得到转义的内容,它们的innerText可以
        xhr.open("GET", location, false) //谢谢Nodejs 乱炖群 深圳-纯属虚构
        xhr.send(null)
        //http://bbs.csdn.net/topics/390349046?page=1#post-393492653
        var noscripts = DOC.getElementsByTagName("noscript")
        var array = (xhr.responseText || "").match(rnoscripts) || []
        var n = array.length
        for (var i = 0; i < n; i++) {
            var tag = noscripts[i]
            if (tag) { //IE6-8中noscript标签的innerHTML,innerText是只读的
                tag.style.display = "none" //http://haslayout.net/css/noscript-Ghost-Bug
                tag.fixIE78 = (array[i].match(rnoscriptText) || ["", " "])[1]
            }
        }
    }
    

    A,IMG标签的src, href路径的转义,这个真是够隐秘啊!

      if (!W3C && (method === "src" || method === "href")) {
           val = val.replace(/&/g, "&")//处理IE67自动转义的问题
       }
    

    oninput事件在IE6-9的兼容问题:

                    if (W3C) { //先执行W3C
                        element.addEventListener("input", updateVModel)
                        data.rollback = function() {
                            element.removeEventListener("input", updateVModel)
                        }
                    } else {
                        removeFn = function(e) {
                            if (e.propertyName === "value") {
                                updateVModel()
                            }
                        }
                        element.attachEvent("onpropertychange", removeFn)
                        data.rollback = function() {
                            element.detachEvent("onpropertychange", removeFn)
                        }
                    }
    
                    if (DOC.documentMode === 9) { // IE9 无法在切剪中同步VM
                        var selectionchange = function(e) {
                            if (e.type === "focus") {
                                DOC.addEventListener("selectionchange", updateVModel)
                            } else {
                                DOC.removeEventListener("selectionchange", updateVModel)
                            }
                        }
                        element.addEventListener("focus", selectionchange)
                        element.addEventListener("blur", selectionchange)
                        var rollback = data.rollback
                        data.rollback = function() {
                            rollback()
                            element.removeEventListener("focus", selectionchange)
                            element.removeEventListener("blur", selectionchange)
                        }
                    }
                }
    

    此外还有许多许多,但都是见诸于jQuery源码的常见问题,我就不便贴出来了,它们的实现也与jQuery的相差无几。可见兼容旧式IE是多么头痛纠结的一件事。但由于OA的要求,甲方的要求,公司上头的要求,我们总是奔于疲命。jQuery帮我们搞定了浏览器的兼容问题,但业务上的复杂性,让我们的代码在DOM与业务逻辑上两头跳。用了avalon后,我们就能从搬砖似的DOM操作上解放出来,研究设计模式,算法,分层架构等具有更高附加值的东西。从码农到工程师到架构师的道路迈进!

    如果您觉得这文章对您有帮助,可以打赏点钱给我,鼓励我继续写博,我的支付宝

     
     
     
    标签: avalon
  • 相关阅读:
    在 Docker 搭建 Maven 私有库
    Maven:mirror和repository 区别
    ubuntu DEBIAN_FRONTEND环境变量用法
    Redis常见面试题
    Error:(1, 1) java: 非法字符: ‘ufeff’
    jpa 查询方法和sql查询语句对应关系
    net.sf.json.JSONObject对时间戳的格式化处理
    美团Leaf——全局序列生成器
    Logstash
    Kafka和SpringBoot
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3599531.html
Copyright © 2011-2022 走看看