国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從一個最簡單例子寫一個極簡雙向綁定

Bowman_han / 2158人閱讀

摘要:目標你好上面是最常見的的用法現在我就只實現一件事改變執行這一句時頁面會及時更新開始動工第一步先聲明一個類我們一開始定義的屬性是定義在中的我們想要這樣賦值的時候和的相關聯需要中間做一個代理修改代碼執行函數實現代理觀察的屬性要想實現這樣賦值的時

目標
html

{{ someStr }}
js let myMvvm = new Mvvm({ el: document.getElementById("app"), data: { someStr: "你好" } })

上面是最常見的vue的用法, 現在我就只實現一件事

myMvvm.someStr = "改變"   // 執行這一句時, 頁面會及時更新
開始動工

1、 第一步, 先聲明一個Mvvm類

class Mvvm {
    constructor (option) {
        this.$option = option || {}
    }
}

我們一開始定義的 someStr屬性是定義在option.data中的, 我們想要 myMvvm.someStr這樣賦值的時候和option的data相關聯, 需要中間做一個代理,修改代碼

class Mvvm {
    constructor (option) {
        this.$option = option || {}
        this._proxyData(option.data, this) // 執行函數實現代理
    }
    _proxyData (obj, context) { 
        Object.keys(obj).forEach(key => {
            Object.defineProperty(context, key, {
                configurable: false,
                enumerable: true,
                get () {
                    return obj[key]
                },
                set (val) {
                    obj[key] = val
                }
            })
        })
    }
}

2、觀察option的data屬性
要想實現 myMvvm.someStr = 1 這樣賦值的時候,頁面能及時更新,那么我們就要對someStr的賦值過程做一個監聽才行, 開心的是 , Object.defineProperty可以輕易做到這點
寫一個observe類

class Observe {
    constructor (obj) {
        Object.keys(obj).forEach(key => {
            this.defineReactive(obj, key, obj[key])
        })
    }
    defineReactive (obj, key, val) {
        let initVal = val
        Object.defineProperty(obj, key, {
            enumerable: true,
            configurable: false,
            get () {
                return initVal
            },
            set (val) { // 每一次的復制我們都可以在這里獲知,自然可以為所欲為了
                initVal = val
                return initVal
            }
        })
    }
}
然后修改一下Mvvm這個類的constructor
constructor (option) {
    this.$option = option || {}
    this._proxyData(option.data, this)
    new Observe(option.data)
}

3、實現元素的實時更新
現在為止, 還只是顯示 一個 {{someStr}} 而已, 我們現在需要做的是讓能變成 你好 這個值
寫一個Compile類

{{someStr}}是一個文本節點,先聲明一個可以渲染文本節點的函數

let compileText = function (node, vm, str) {
    let val = vm[str]
    if (val) {
        node.nodeValue = val 
    }
}

class Compile {
    constructor(el, vm) { // el 是 #app這個元素  vm是Mvvm這個實例
        let frag = this.node2Fragment(el)
        this.vm = vm
        this.compileElement(frag) // 讀取子節點進行渲染
        el.appendChild(frag)
    }
    node2Fragment(el) { // 創建一個文檔片段把#app元素的子節點拷貝
        let frag = document.createDocumentFragment()
        let child
        while (child = el.firstChild) {
            frag.appendChild(child)
        }
        return frag
    }
    compileElement(el) { // 渲染節點
        let childNodes = el.childNodes;
        [].forEach.call(childNodes, (node) => { // 遍歷所有的子節點
            if (this.isElementNode(node)) { // 如果是元素節點, 重復便利
                this.compileElement(node)
            } else if (this.isTextNode(node)) { // 如果是文本節點
                let matchStr = this.isMustache(node.nodeValue) // 判斷這個文本值是不是 {{}} 這種類型
                if (matchStr) { // 如果有匹配到
                    compileText(node, this.vm, matchStr)
                }
            }
        })
    }
    isElementNode(node) { // 元素節點
        return node.nodeType === 1
    }
    isTextNode(node) { // 文本節點
        return node.nodeType === 3
    }
    isMustache(str) {
        if (!str) {
            return null
        }
        let reg = /{{(.*)}}/
        let arr = str.match(reg)
        return arr ? arr[1].replace(/s/g, "") : null
    }

}
現在修改一下 Mvvm這個類的constructor函數
constructor(option) {
    this.$option = option || {}
    this._proxyData(option.data, this)
    new Observe(option.data)
    new Compile(option.el, this)
}

現在你好這個值終于是被渲染出來, 我們踏出了第一步, 現在開始實現 myMvvm.someStr = 1 也能及時更新

在實現complie的時候, 我們知道渲染的時候調用了compileText函數,那么我們現在更改someStr時及時渲染,就只要再執行這個函數就可以了, 我們可以把這個更新函數放到一個隊列里, 每次更新someStr的時候, 把這個隊列里的更新函數執行一遍就可以了
我們實現一個Dep類

// 這里聲明兩個變量待會使用
let updateFn
let canMount
class Dep {
    constructor () {
        this.queue = []
    }
    mount () {
        this.queue.push(updateFn)
    }
    notify () {
        this.queue.forEach(fn => fn())
    }
}

然后修改一下Observe類的defineReactive函數

defineReactive(obj, key, val) {
    let initVal = val
    let dep = new Dep()
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: false,
        get() {
            if (canMount) { // 防止每次get都會執行這里
                dep.mount()
            }
            return initVal
        },
        set(val) { // 每一次的復制我們都可以在這里獲知,自然可以為所欲為了
            if (val !== initVal) {
                initVal = val
                dep.notify()
            }
            return initVal
        }
    })
}

實現一個生成更新函數 的方法
let bindTextUpdater = function (node, vm, matchStr) {
    canMount = true
    updateFn = compileText.bind(null, node, vm, matchStr)
    updateFn()
    canMount = false
}

然后最后一步
修改一下Complie類的compileElement方法
let childNodes = el.childNodes;
        [].forEach.call(childNodes, (node) => { // 遍歷所有的子節點
            if (this.isElementNode(node)) { // 如果是元素節點, 重復便利
                this.compileElement(node)
            } else if (this.isTextNode(node)) { // 如果是文本節點
                let matchStr = this.isMustache(node.nodeValue) // 判斷這個文本值是不是 {{}} 這種類型
                if (matchStr) { // 如果有匹配到
                    bindUpdater(node, this.vm, matchStr) // 綁定更新函數
                }
            }
        })

現在執行 myMvvm.someStr = 155 會發現簡單的例子實現了

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/52897.html

相關文章

  • 一個簡單例子一個極簡雙向綁定

    摘要:目標你好上面是最常見的的用法現在我就只實現一件事改變執行這一句時頁面會及時更新開始動工第一步先聲明一個類我們一開始定義的屬性是定義在中的我們想要這樣賦值的時候和的相關聯需要中間做一個代理修改代碼執行函數實現代理觀察的屬性要想實現這樣賦值的時 目標 html {{ someStr }} js let myMvvm = new Mvvm({ el: documen...

    zhaochunqi 評論0 收藏0
  • 一個簡單例子一個極簡雙向綁定

    摘要:目標你好上面是最常見的的用法現在我就只實現一件事改變執行這一句時頁面會及時更新開始動工第一步先聲明一個類我們一開始定義的屬性是定義在中的我們想要這樣賦值的時候和的相關聯需要中間做一個代理修改代碼執行函數實現代理觀察的屬性要想實現這樣賦值的時 目標 html {{ someStr }} js let myMvvm = new Mvvm({ el: documen...

    niceforbear 評論0 收藏0
  • 160行代碼仿Vue實現極簡雙向綁定[詳細注釋]

    摘要:兼容性更詳細的可以看一下實現思路系列的雙向綁定,關鍵步驟實現數據監聽器,用重寫數據的,值更新就在中通知訂閱者更新數據。 showImg(https://segmentfault.com/img/remote/1460000015375220?w=640&h=426); 前言 現在的前端面試不管你用的什么框架,總會問你這個框架的雙向綁定機制,有的甚至要求你現場實現一個雙向綁定出來,那對于...

    endiat 評論0 收藏0
  • Vue.js 官方示例初探(ES6 改

    摘要:雙嘆號強制類型轉換為布爾值。官方示例代碼用注冊了全局組件,會把自動注冊為屬性,所以沒有手動寫屬性。如果對象是響應的,將觸發視圖更新。這是用來布爾值,又學了一招和分別代表單擊和雙擊事件綁定。 如果覺得有幫助,歡迎 star哈~ https://github.com/jiangjiu/blog-md/issues/11 感謝作者 @尤小右 大大邊寫的超級帶感的 Vue.js 前端框架,贈送...

    Jason 評論0 收藏0
  • Vue源碼解析:雙向綁定原理

    摘要:無論是還是都提倡單向數據流管理狀態,那我們今天要談的雙向綁定是否和單向數據流理念有所違背我覺得不是,從上篇文章語法樹轉函數了解到,雙向綁定,實質是的單向綁定和事件偵聽的語法糖。源碼解析今天涉及到的代碼全在文件夾下。 通過對 Vue2.0 源碼閱讀,想寫一寫自己的理解,能力有限故從尤大佬2016.4.11第一次提交開始讀,準備陸續寫: 模版字符串轉AST語法樹 AST語法樹轉rend...

    oliverhuang 評論0 收藏0

發表評論

0條評論

Bowman_han

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<