日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

轻量级前端MVVM框架avalon - 模型转换

發布時間:2025/6/17 HTML 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 轻量级前端MVVM框架avalon - 模型转换 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

接上一章 ViewModel

?


modelFactory工廠是如何加工用戶定義的VM?

附源碼

  • 洋洋灑灑100多行內部是魔幻般的實現
1: function modelFactory(scope) { 2: var skipArray = scope.$skipArray, //要忽略監控的屬性名列表 3: model = {}, 4: Descriptions = {}, //內部用于轉換的對象 5: json = {}, 6: callSetters = [], 7: callGetters = [], 8: VBPublics = Object.keys(watchOne); //用于IE6-8 9: skipArray = Array.isArray(skipArray) ? skipArray.concat(VBPublics) : VBPublics; 10: forEach(scope, function(name, value) { 11: if (!watchOne[name]) { 12: json[name] = value; 13: } 14: var valueType = avalon.type(value); 15: if (valueType === "Function") { 16: VBPublics.push(name); //函數無需要轉換 17: } else { 18: if (skipArray.indexOf(name) !== -1) { 19: return VBPublics.push(name); 20: } 21: if (name.charAt(0) === "$" && !systemOne[name]) { 22: return VBPublics.push(name); 23: } 24: var accessor, oldArgs; 25: if (valueType === "Object" && typeof value.get === "function" && Object.keys(value).length <= 2) { 26: var setter = value.set, 27: getter = value.get; 28: accessor = function(neo) { //創建計算屬性 29: if (arguments.length) { 30: if (stopRepeatAssign) { 31: return; //阻止重復賦值 32: } 33: if (typeof setter === "function") { 34: setter.call(model, neo); 35: } 36: if (oldArgs !== neo) { //由于VBS對象不能用Object.prototype.toString來判定類型,我們就不做嚴密的檢測 37: oldArgs = neo; 38: notifySubscribers(accessor); //通知頂層改變 39: model.$events && model.$fire(name, neo, value); 40: } 41: } else { 42: if (openComputedCollect || !accessor.locked) { 43: collectSubscribers(accessor); 44: } 45: return value = json[name] = getter.call(model); //保存新值到json[name] 46: } 47: }; 48: accessor.nick = name; 49: callGetters.push(accessor); 50: } else { 51: value = NaN; 52: callSetters.push(name); 53: accessor = function(neo) { //創建監控屬性或數組 54: if (arguments.length) { 55: if (stopRepeatAssign) { 56: return; //阻止重復賦值 57: } 58: if (value !== neo) { 59: var old = value; 60: if (valueType === "Array" || valueType === "Object") { 61: if (value && value.$id) { 62: updateViewModel(value, neo, Array.isArray(neo)); 63: } else if (Array.isArray(neo)) { 64: value = Collection(neo, model, name); 65: } else { 66: value = modelFactory(neo); 67: } 68: } else { 69: value = neo; 70: } 71: json[name] = value && value.$id ? value.$json : value; 72: notifySubscribers(accessor); //通知頂層改變 73: model.$events && model.$fire(name, value, old); 74: } 75: } else { 76: collectSubscribers(accessor); //收集視圖函數 77: return value; 78: } 79: }; 80: } 81: accessor[subscribers] = []; 82: Descriptions[name] = { 83: set: accessor, 84: get: accessor, 85: enumerable: true 86: }; 87: } 88: }); 89: if (defineProperties) { 90: defineProperties(model, Descriptions); 91: } else { 92: model = VBDefineProperties(Descriptions, VBPublics); 93: } 94: VBPublics.forEach(function(name) { 95: if (!watchOne[name]) { 96: model[name] = scope[name]; 97: } 98: }); 99: callSetters.forEach(function(prop) { 100: model[prop] = scope[prop]; //為空對象賦值 101: }); 102: callGetters.forEach(function(fn) { 103: Publish[expose] = fn; 104: callSetters = model[fn.nick]; 105: fn.locked = 1; 106: delete Publish[expose]; 107: }); 108: model.$json = json; 109: model.$events = {}; //VB對象的方法里的this并不指向自身,需要使用bind處理一下 110: model.$watch = Observable.$watch.bind(model); 111: model.$unwatch = Observable.$unwatch.bind(model); 112: model.$fire = Observable.$fire.bind(model); 113: model.$id = generateID(); 114: model.hasOwnProperty = function(name) { 115: return name in model.$json; 116: }; 117: return model; 118: }
  • VM是用ecma262v5的新API, Object.defineProperties生成的一個充滿訪問器的對象,這樣的對象,能通過用戶對它的屬性的讀寫,觸發定義時的getter, setter函數。getter, setter對rubyer, pythoner, C#er應該很熟悉,我就不展開了。
  • 舊式IE,avalon利用VBScript的類實例,它也存在其他語言的訪問器。不過,VBS對象不像JS對象那樣隨意添加新屬性,刪除已有屬性,因此我們就無法監后添加的新屬性。Object.defineProperties也一樣,它能處理的屬性也只是它定義時的屬性,想監控后來的,需要再調用一次Object.defineProperties。

?


整個工廠方法內部都是圍繞著scope處理

  • 過濾監控的屬性
  • 收集視圖函數
  • 轉換用于定義
  • skipArray //要忽略監控的屬性名列表

    0: "$json" 1: "$skipArray" 2: "$watch" 3: "$unwatch" 4: "$fire" 5: "$events"

    ?

    我們還是已官網的demo為列

    avalon.define("simple", function(vm) {vm.firstName = "司徒"vm.lastName = "正美"vm.fullName = {//一個包含set或get的對象會被當成PropertyDescriptor,set: function(val) {//set, get里面的this不能改成vmvar array = (val || "").split(" ");this.firstName = array[0] || "";this.lastName = array[1] || "";},get: function() {return this.firstName + " " + this.lastName;}}})avalon.scan(document.querySelector("fieldset"));

    ?

    此時傳入的vm為

    $watch: function noop() {firstName: "司徒"fullName: ObjectlastName: "正美"

    ?

    意圖很明顯就是遍歷這些屬性,給出相對應的處理,具體我們接著往下看

    ?????????? 純凈的js對象,所有訪問器與viewModel特有的方法屬性都去掉

    1: if (!watchOne[name]) { 2: json[name] = value; 3: }

    幾個簡單的條件過濾:

    1: //判斷類型 2: var valueType = avalon.type(value); 3: ? 4: if (valueType === "Function") { 5: // 第一個就是$watch" 被重復假如到列表了 6: VBPublics.push(name); //函數無需要轉換 7: } else {

    ?

    跳過過濾的條件后:


    核心的轉換

    • 轉換計算屬性
    • 轉化監控屬性

    ?

    轉換計算屬性:

  • 定義時為一個最多擁有get,set方法的對象(get方法是必需的)
  • 注意,get, set里面的this不能改為vm,框架內部會幫你調整好指向。
  • 判斷的條件,值類型是對象,并且有get方法,并且方法要少于等于2個

    if (valueType === "Object" && typeof value.get === "function" && Object.keys(value).length <= 2) {

    滿足條件的

    vm.fullName = {//一個包含set或get的對象會被當成PropertyDescriptor,set: function(val) {//set, get里面的this不能改成vmvar array = (val || "").split(" ");this.firstName = array[0] || "";this.lastName = array[1] || "";},get: function() {return this.firstName + " " + this.lastName;}}

    具體有什么用我們接著往下看

    ?

    轉化監控屬性

  • 定義時為一個簡單的數據類型,如undefined, string, number, boolean。
  • 監控數組:定義時為一個數組
  • firstName: "司徒"

    ?


    ?

    accessor[subscribers] = [];
    • 別看這個代碼是空的函數,不起眼,雙向綁定就是看他了,我們先Mark下

    //生成defineProperties需要的配置屬性Descriptions[name] = {set: accessor,get: accessor,enumerable: true};
    • Descriptions臨時對象? //收集內部用于轉換的對象
    • enumerable 很重要,為false的話 ,for in就找不到它了

    這樣循環后就把該干嘛的不該干嘛的都給區分開了

    最后都保存在Descriptions中

    此時的Descriptions

    1: Descriptions: Object 2: ? 3: firstName: Object 4: enumerable: true 5: get: function (neo) { //創建監控屬性或數組 6: set: function (neo) { //創建監控屬性或數組 7: ? 8: fullName: Object 9: enumerable: true 10: get: function (neo) { //創建計算屬性 11: set: function (neo) { //創建計算屬性 12: ? 13: lastName: Object 14: enumerable: true 15: get: function (neo) { //創建監控屬性或數組 16: set: function (neo) { //創建監控屬性或數組 ?

    看吧就是這樣給包裝了一下,只是定義了但是還沒生效

    所以defineProperties(model, Descriptions); 給執行以下? (defineProperties的方法見前面)

    ?


    model 就是工廠模式轉換后的新的vm模型對象了, 因為在開始遍歷scope的過濾了一些東東,原本也是用戶定義的,所以這時候我們還得加到新的vm-》model中去、

    //添加用戶定義的未轉換的函數到模型VBPublics.forEach(function(name) {if (!watchOne[name]) {model[name] = scope[name];}});

    轉載于:https://www.cnblogs.com/aaronjs/p/3146848.html

    總結

    以上是生活随笔為你收集整理的轻量级前端MVVM框架avalon - 模型转换的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。