迷你MVVM框架 avalonjs 1.3.6發布


本版本是一次重要的升級,考慮要介紹許多東西,也有許多東西對大家有用,也發到首頁上來了。

本來是沒有1.36的,先把基於靜態收集依賴的1.4設計出來后,發現改動太多,為了平緩升級起見,才減少了一部分新特性,做成1.36。因此是先有1.4,才有1.36。

本版本針對公司(去哪兒網,畢竟是帶薪在公司里搞這框架)的訪問瀏覽器的占有率,加大對國產瀏覽器的測試。涉及瀏覽器有QQ瀏覽器, 搜狗瀏覽器, 獵豹瀏覽器, 傲游瀏覽器,但沒有360瀏覽器,我們公司的同事還是很注意安全的。這么多瀏覽器,現在還差兩個case才能在獵豹瀏覽器上通過。原因是獵豹瀏覽器是雙核的,框架一些內部判定分支不小心掉進坑里了。如往常一樣,對於正常的IE6-8,avalon是全部通過。

下面簡單羅列一下新特性與修復情況:

  • 【新特性】添加avalon.isFunction方法,不用多說,大家都知道怎么用,但在IE6-8與W3C下,它的實現是不一樣的。待會兒說。
  • 【新特性】添加data-duplex-focus輔助指令, 當ms-duplex位於文本域,密碼域,文本區上,添加了此指令,會自動獲取焦點,光標位於最后的文本后。詳見這里
  • 【新特性】ms-duplex-*添加數據轉換功能。詳見這里
  • 【優化】重構sanitize過濾器,詳見這里這里
  • 【優化】重構html綁定,將會導致內存泄漏的replaceNodes替換掉,這里
  • 【優化】重構if綁定,將會導致內存泄漏的msInDocument、ifSanctuary、 placehoder屬性移除掉,詳見這里
  • 【優化】重構repeat綁定,將會導致內存泄漏的startRepeat、 endRepeat、 parent、callbackElement屬性移除掉,原template屬性改成為一個字符串。詳見這里
  • 【優化】重構modelFactory,通過靜態分析收集監控屬性與計算屬性及函數間的依賴關系,$watch回調的存放數組與視圖刷新函數的存放數組合而為一,詳見下面commit 簡化計算屬性監控數組的訂閱數組 對函數內部的監控屬性進行依賴收集
  • 【優化】重構avalon.contains,IE6-8下,對游離於DOM樹外的文本節點,訪問其parentNode,有時會拋錯。詳見這里
  • 【優化】提高cacheExpr的緩存命中率,詳見這里
  • 【優化】重構IE6-8下設置元素透明度,待會兒講。
  • 【警告】重構avalon.Array.ensure的行為,通過返回值是數字還是undefined判定其是否已經添加新元素,詳見這里
  • 【警告】廢棄dettachVModels的配置項,詳見這里

下面是介紹一些具體特征的實現。

首先是isFunction方法,avalon遇到的問題與當年的jQuery是一樣的。jQuery 1.4 源碼 449 行(core.js 431 行),判斷是否為函數的方法如下(思路來源於 Douglas Crockford 的《The Miller Device》):

isFunction: function( obj ) {
    return toString.call(obj) === "[object Function]";
},

同時 jQuery 的作者也作了部分注釋:

See test/unit/core.js for details concerning isFunction. Since version 1.3, DOM methods and functions like alert aren't supported. They return false on IE (#2968).

即:此方法在 IE 下無法正確識別 DOM 方法和一些函數(例如 alert 方法等)。如果我們用alert(typeof document.getElementById),在IE6-8下會彈出object,而不是期待中的function。因此我們必須對IE6-8或舊式IE內核瀏覽器進行特殊處理,參考了網上的實現,avalon現在的源碼如下:

 var isFunction = typeof alert === "object" ? function(fn) {
        try {//正則判斷傳入的對象字符串后(fn+""),是否起始位置含有 function,即:/^\s*\bfunction\b/.test(fn+"")
            return /^\s*\bfunction\b/.test(fn + "")
        } catch (e) {
            return false
        }
    } : function(fn) {
        return serialize.call(fn) == "[object Function]"
    }

但這個方法目前還有一點問題,在獵豹瀏覽器下判定eval方法會出錯,大抵是在IE8文檔模式下IE9用戶代理字符串模式下出錯。

ms-duplex-*添加數據轉換功能,現在ms-duplex-bool調整為ms-duplex-boolean, ms-duplex-text調整為ms-duplex-string,增加ms-duplex-number,並且它們三個在所有表單元素都上都有效果。預計在1.4中,會添加更多自定義格式與錯誤提示功能。

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <title>ms-duplex</title>
        <script src="../avalon.js" type="text/javascript"></script>
        <script>
            var model = avalon.define({
                $id: "test",
                aaa: "111",
                bbb: false,
                ccc: [222],
                ddd: [true],
                eee: [],
                fff: 222
            })
            model.$watch("aaa", function(a) {
                console.log(a)
            })
            model.ccc.$watch("length", function(a) {
                console.log(model.ccc)
            })
            model.ddd.$watch("length", function(a) {
                console.log(model.ddd)
            })
            model.eee.$watch("length", function(a) {
                console.log(model.eee)
            })
            model.$watch("fff", function(a) {
                console.log(a)
            })
        </script>
    </head>
    <body ms-controller="test">
        <fieldset><legend>radio</legend>
            <p><input ms-duplex="aaa" type="radio">根據當前checked屬性取反設置其checked,只應用於單個控件</p>
            <p><input ms-duplex-string="aaa" value="111" type="radio">
                <input ms-duplex-string="aaa" value="222"type="radio">
                根據其value屬性設置其checked</p>
            <p><input ms-duplex-number="aaa" value="111" type="radio">
                <input ms-duplex-number="aaa" value="222"type="radio">
                根據其value屬性設置其checked,要求應用於復數個控件,類型轉換為number</p>
            <p><input ms-duplex-boolean="bbb" value="true" type="radio">
                <input ms-duplex-boolean="bbb" value="false"type="radio">
                根據其value屬性設置其checked,要求應用於復數個控件,類型轉換為boolean,原來的ms-duplex-bool</p>
            <p><input ms-duplex-string="bbb" value="true" type="radio">
                <input ms-duplex-string="bbb" value="false"type="radio">
                根據其value屬性設置其checked,要求應用於復數個控件,類型轉換為string,原來的ms-duplex-text</p>
        </fieldset>
        <fieldset><legend>checkbox</legend>
            <p><input ms-duplex-radio="bbb" type="checkbox">根據當前checked屬性取反設置其checked,只應用於單個控件</p>
            <p><input ms-duplex-number="ccc" value="111" type="checkbox">
                <input ms-duplex-number="ccc" value="222"type="checkbox">
                根據其value屬性設置其checked,要求應用於復數個控件,類型轉換為number</p>
            <p><input ms-duplex-boolean="ddd" value="true" type="checkbox">
                <input ms-duplex-boolean="ddd" value="false"type="checkbox">
                根據其value屬性設置其checked,要求應用於復數個控件,類型轉換為boolean</p>
            <p><input ms-duplex-string="eee" value="男" type="checkbox">
                <input ms-duplex-string="eee" value="女"type="checkbox">
                根據其value屬性設置其checked,要求應用於復數個控件,類型轉換為string</p>
        </fieldset>
        <fieldset><legend>text,texteara, password</legend>
            <p><input ms-duplex-number="aaa">{{typeof aaa}}</p>
            <p><input ms-duplex-boolean="bbb">{{typeof bbb}}</p>
        </fieldset>
        <fieldset><legend>select</legend>
            <select ms-duplex-number="fff">
                <option>111</option>
                <option>222</option>
                <option>333</option>
            </select>
        </fieldset>
    </body>
</html>

最后是舊式IE設置透明度的問題,大家都知道要使用透明濾鏡。但透明濾鏡其實有兩個版本,一個是簡化版,style.filter="alpha(opacity=50)",一個是完整版, style.filter="progid:DXImageTransform.Microsoft.Alpha(opacity=50)"。jQuery是使用前者,但問題來了,透明濾鏡還有一個設置項,enabled,如果它等於0或false,那么就不會透明。為了預防這樣的高手出現,取透明度時就要小心了。

  var salpha = "DXImageTransform.Microsoft.Alpha"
  cssHooks["opacity:get"] = function(node) {
            //這是最快的獲取IE透明值的方式,不需要動用正則了!
            var alpha = node.filters.alpha || node.filters[salpha],
                    op = alpha && alpha.enabled ? alpha.opacity : 100
            return (op / 100) + "" //確保返回的是字符串
        }

在設置透明度時,最開始不存在濾鏡,我們就必須操作node.style.filter屬性,以后有了,就可以使用node.filters對象進行操作。jQuery只打算操作在style上玩。參考mootools的實現,我搞鼓出第一種操作透明度的方式。

        cssHooks["opacity:set"] = function(node, name, value) {
            var style = node.style
            var opacity = isFinite(value) && value <= 1 ? "alpha(opacity=" + value * 100 + ")" : ""
            var filter = style.filter || "";
            style.zoom = 1
            //不能使用以下方式設置透明度
            //node.filters.alpha.opacity = value * 100
            style.filter = (ralpha.test(filter) ?
                    filter.replace(ralpha, opacity) :
                    filter + " " + opacity).trim()
            if (!style.filter) {
                style.removeAttribute("filter")
            }
        }

顯然這是沒有有效利用透明濾鏡的特性。深入研究后,搞出第二種,它將在1.4上出現。

//https://github.com/RubyLouvre/avalon/issues/517
        cssHooks["opacity:set"] = function(node, name, value) {
            var style = node.style
            var filter = style.filter || ""
            if (filter.indexOf(salpha) === -1) {
                style.filter += "progid:" + salpha + "(opacity=100)"
            }
            var alpha = node.filters[salpha] || {}
            if (value <= 1 && isFinite(value)) {
                style.zoom = alpha.enabled = 1
                alpha.opacity = value * 100
            } else {
                alpha.enabled = 0
            }
        }

這樣更簡單,更高效。總之,在DOM上是存在各種奇奇怪怪的屬性與方法,與它們打交道,正是我們前端寫碼的樂趣所在。掌握的細節越多,我們的選擇就越多,寫出的代碼就越優雅高效。

迷你MVVM框架在github的倉庫https://github.com/RubyLouvre/avalon

官網地址http://rubylouvre.github.io/mvvm/

avalon的新UI庫地址OniUI, 多達36個UI,強大的換膚功能


朋友們用avalon做的東西


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM