【筆記】Vue雙向綁定原理

響應式

  • 是一種面向數據流和變化傳播的編程範式。這意味着能夠在編程語言中很方便地表達靜態或動態的數據流,而相關的計算模型會自動將變化的值經過數據流進行傳播。
  • Vue 2+ 版本基於Object.defineProperty實現數據雙向綁定,即數據變化時,視圖也變化。
  • Object.defineProperty用法:
let obj = {}
Object.defineProperty(obj, 'value', {
    get () {
        return 1
    },
    set (newValue) {
        console.log('set')
        value = newValue
    }
})
// 控制檯 
// obj.value => 1
// obj.value = 2 => set
  • 假設以x和y表示,當x改變時,y也相應變化
// 將x轉換成能夠監聽變化的對象
let x = ref(1)
let ref = initValue => {
    let value = initValue
    return Object.defineProperty({}, 'value', {
        get () {
            return value
        },
        set (newValue) {
            value = newValue
            active() // x變化時觸發y變化
        }
    })
}
// 當x變化時,y相應改變(f函數模擬變化)
let f = n => n * 100 + 100
let active
let onXChange = (cb) => {
    active = cb
    active() // 開始時觸發一次
}
onXChange(() => {
    y = f(x.value)
    console.log(y)
})
x.value = 2 // 300
  • 因爲一個變量的修改會涉及到模板中多處的變化,須要將依賴變量的地方收集起來,等更新時批量操做

依賴收集.png

  • 增長一個用來收集依賴的類Dep
class Dep {
    constructor() {
        // Set 數據結構 相似於數組,但成員都是惟一的
        // 經過new生成Set數據結構
        this.deps = new Set()
    }
    depend () {
        // 依賴收集
        if (active) {
            // 經過add()方法向Set結構加入成員
            this.deps.add(active)
        }
    }
    notify () {
        // 觸發
        this.deps.forEach(dep => dep())
    }
}
  • 改造一下onXChange函數,避免重複收集
  • 在get中收集依賴,在set中觸發
  • 最終實現:
// 假如x變化,y和z都要變化
let x
let y
let z
let fy = n => n * 100 + 100
let fz = n => n + 1

let active
let onXChange = (cb) => {
    active = cb
    active()
    active = null // 避免重複收集
}
// 當X變化時,引發y和z的變化,一個變化引起多個變化
class Dep {
    constructor() {
        // Set 數據結構 相似於數組,但成員都是惟一的
        // 經過new生成Set數據結構
        this.deps = new Set()
    }
    depend () {
        // 依賴收集
        if (active) {
            // 經過add()方法向Set結構加入成員
            this.deps.add(active)
        }
    }
    notify () {
        // 觸發
        this.deps.forEach(dep => dep())
    }
}
let ref = initValue => {
    let value = initValue
    let dep = new Dep()
    return Object.defineProperty({}, 'value', {
        get () {
            dep.depend()
            return value
        },
        set (newValue) {
            value = newValue
            dep.notify()
        }
    })
}

x = ref(1)
onXChange(() => {
    y = fy(x.value)
    console.log(y)
})
onXChange(() => {
    z = fz(x.value)
    console.log(z)
})

x.value = 2
/*
控制檯打印
200
2
300
3
*/
相關文章
相關標籤/搜索