動態

詳情 返回 返回

【筆記】Vue-1-響應式原理 - 動態 詳情

響應式

  • 是一種面向數據流和變化傳播的編程範式。這意味着可以在編程語言中很方便地表達靜態或動態的數據流,而相關的計算模型會自動將變化的值通過數據流進行傳播。
  • 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 watch = (cb) => {
    active = cb
    active() // 開始時觸發一次
}
watch(() => {
    y = f(x.value)
    console.log(y)
})
x.value = 2 // 300
  • 現在如果x的變化也會引起z的變化,那麼就再需要增加一個active
  • 因此,由於一個變量的修改會涉及到模板中多處的變化,需要將依賴變量的地方收集起來,等更新時批量操作

依賴收集.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())
    }
}
  • 改造一下watch函數,避免重複收集
  • 在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 watch = (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)
watch(() => {
    y = fy(x.value)
    console.log(y)
})
watch(() => {
    z = fz(x.value)
    console.log(z)
})

x.value = 2
/*
控制枱打印
200
2
300
3
*/

Add a new 評論

Some HTML is okay.