最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue2.x響應(yīng)式簡單講解及示例

 更新時間:2021年08月16日 17:22:10   作者:RisingSunBlogs  
這篇文章主要介紹了Vue2.x響應(yīng)式及簡單的示例,應(yīng)用了簡單的源代碼進行講解,感興趣的小伙伴可以參考一下,希望可以幫助到你

一、回顧Vue響應(yīng)式用法

​ vue響應(yīng)式,我們都很熟悉了。當我們修改vue中data對象中的屬性時,頁面中引用該屬性的地方就會發(fā)生相應(yīng)的改變。避免了我們再去操作dom,進行數(shù)據(jù)綁定。

二、Vue響應(yīng)式實現(xiàn)分析

對于vue的響應(yīng)式原理,官網(wǎng)上給了出文字描述 https://cn.vuejs.org/v2/guide/reactivity.html 。

vue內(nèi)部主要是通過數(shù)據(jù)劫持和觀察者模式實現(xiàn)的

數(shù)據(jù)劫持:

vue2.x內(nèi)部使用Object.defineProperty https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

vue3.x內(nèi)部使用的Proxy https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

觀察者模式:http://m.fzitv.net/article/219790.htm

內(nèi)部成員示意圖

各個成員的功能

Vue:

把data中的成員注入到Vue實例中,并把data中的成員轉(zhuǎn)換為getter和setter

Observer:

對data對象中的簡單類型數(shù)據(jù)及對象進行監(jiān)聽,當數(shù)據(jù)發(fā)生變化時通知Dep

Compiler:

解析每個元素中的指令/差值表達式,并替換成相應(yīng)的數(shù)據(jù)

Dep:

觀察者模式中的通知者,添加觀察者,當數(shù)據(jù)變化時通知觀察者

Watcher:

每個引用data中的屬性的地方都有一個watcher對象,負責更新視圖

附:data對象中的屬性充當被觀察者,引用data對象中屬性的地方充當觀察者

三、Vue響應(yīng)式源碼實現(xiàn)

Vue對象實現(xiàn)

功能

  • 負責接受初始化的參數(shù)
  • 把data中的屬性注入到data實例,轉(zhuǎn)換成getter和setter
  • 調(diào)用Observer監(jiān)聽data中所有屬性的變化
  • 調(diào)用compiler解析指令、差值表達式.
class Vue{
    constructor(options){
        // 1、通過屬性保存穿進來的屬性
        this.$options= options||{};
        this.$data= options.data||{};
        this.$el = typeof options.el ==='string' ? document.querySelector(options.el) : options.el;
        // 2、把data參數(shù)中的數(shù)據(jù)轉(zhuǎn)換為getter和setter 掛載到Vue實例上
        this._proxyData(this.$data)
        // 3、調(diào)用observe對象監(jiān)視data數(shù)據(jù)的變化
        new Observer(this.$data)
        // 4、調(diào)用compiler對象渲染頁面
        new Compiler(this)
    }
    _proxyData(data){
        if (data&&Object.keys(data).length>0){
             for (const key in data) {
                Object.defineProperty(this,key,{
                    configurable:true,
                    enumerable:true,
                    get(){
                        return data[key]
                    },
                    set(value){
                        if (data[key]===value) {
                            return;
                        }
                        data[key]=value;
                    }
                })
             }
        }
    }
}

Observer對象實現(xiàn)

功能

  • 把data選項中的屬性進行數(shù)據(jù)劫持
  • data中的某個屬性也是對象的話,進行遞歸轉(zhuǎn)換成響應(yīng)式對象
  • 數(shù)據(jù)變化發(fā)送通知
//數(shù)據(jù)劫持   class Observer {
    constructor(data) {
        this.walk(data)
    }
    walk(data) { 
        //1、判斷data是否是對象    
        if (!data || typeof data !== 'object') {     
            return
        }
        //2、循環(huán)調(diào)用defineReactive進行數(shù)據(jù)劫持
        Object.keys(data).forEach(key => {
            this.defineReactive(data, key, data[key])
        })
    }
    defineReactive(obj, key, val) {
        //創(chuàng)建通知者
        const dep = new Dep()
        //使用walk把引用對象中的屬性變成響應(yīng)式的
        this.walk(val)
        const that=this;
        Object.defineProperty(obj, key, {
            configurable: true,
            enumerable: true,
            get() {
                //通知者收集觀察者
                Dep.target && dep.addSub(Dep.target)
                return val;
            },
            set(newVal) {
                if (newVal === val) {
                    return;
                }
                val = newVal;
                that.walk(newVal)
                //被觀察者發(fā)生變化的時候,通知者對象給每個觀察者發(fā)送通知
                dep.notify()
            }
        })
    }
}

Compile對象實現(xiàn)

功能

  • 負責編譯模板,解析指令、差值表達式
  • 負責頁面首次渲染
  • 當數(shù)據(jù)發(fā)生改變后,負責重新渲染視圖
//編譯器   class Compiler {
    constructor(vm) {
        this.el = vm.$el;
        this.vm = vm;
        this.compile(this.el)
    }
    //編譯模板 判斷節(jié)點是文本節(jié)點還是元素節(jié)點
    compile(el) {
        let childNodes = el.childNodes;
        //處理第一層子節(jié)點
        Array.from(childNodes).forEach(node => {
            if (this.isTextNode(node)) {
                this.compileText(node)
            } else if (this.isElementNode(node)) {
                this.compileElement(node)
            }
            //如果當前節(jié)點還有子節(jié)點  遞歸調(diào)用編譯指令
            if (node.childNodes && node.childNodes.length) {
                this.compile(node)
            }
        })
    }

    //編譯元素節(jié)點,處理指令
    compileElement(node) {  
        //遍歷所有的指令
        Array.from(node.attributes).forEach(attr => {
            //判斷是不是指令節(jié)點
            if (this.isDirective(attr.name)) {
                const nodeName = attr.name;
                const key = attr.nodeValue;
                const directive = nodeName.substr(2)
                this.updater(directive,node,key)
            }
        }) 
    }
    updater(directive,node,key){
        const updaterFn = this[directive+"Updater"]
        updaterFn && updaterFn.call(this,node,this.vm[key],key)
    }
    //v-text
    textUpdater(node,value,key){
        node.textContent=value
        //使用v-text表達式的地方就是一個觀察者
        new Watcher(this.vm,key,newValue => {
            node.textContent = newValue
        })
    }
    //v-model
    modelUpdater(node,value,key){
        node.value =value
        //使用v-model表達式的地方就是一個觀察者
        new Watcher(this.vm,key,newValue => {
            node.value = newValue
        })
      //實現(xiàn)雙向綁定
        node.addEventListener('input',()=>{
            this.vm[key] = node.value
        })
    }
    //v-html
    htmlUpdater(node,value,key){
        node.innerHTML = value
        //使用v-html表達式的地方就是一個觀察者
        new Watcher(this.vm,key,newValue => {
            node.innerHTML = newValue
        })
    }

    //處理差值表達式
    compileText(node) {
        //匹配差值表達式的正則
        let reg = /\{\{(.+?)\}\}/
        //用正則匹配node的textContent,如果匹配到了 就替換
        if (reg.test(node.textContent)) {
            //獲取插值表達式的key
            let key = RegExp.$1;
            let value = node.textContent;
            node.textContent = value.replace(reg, this.vm[key])

            //使用差值表達式的地方就是一個觀察者
            new Watcher(this.vm,key,newValue => {
                node.textContent = newValue
            })
        }
    }

    //是否是指令
    isDirective(attrName) {
        return attrName.startsWith('v-')
    }

    //是否是文本節(jié)點
    isTextNode(node) {
        return node.nodeType === 3
    }

    //是否是元素
    isElementNode(node) {
        return node.nodeType === 1
    }
}

Dep對象實現(xiàn)

功能

  • 收集依賴,添加觀察者
  • 通知所有觀察者
//通知者類   class Dep {
    constructor() {
        //存儲觀察者
        this.subs = []
    }

    /**
     * 收集觀察者
     */
    addSub(sub) {
        if (sub && sub.update) {
            this.subs.push(sub)
        }
    }

    /**
     * 通知觀察者改變狀態(tài)
     */
    notify() {
        this.subs.forEach(sub => {
            sub.update()
        })
    }
}

Watcher對象實現(xiàn)

功能

  • 當數(shù)據(jù)變化時,Dep通知所有Watcher實例更新視圖
  • 自身實例化的時候往Dep對象中添加自己
//觀察者類   class Watcher {
    constructor (vm,key,cb) {
        //Vue實例
        this.vm =vm;
        // data中的key對象
        this.key =key;
        // 更新視圖的回調(diào)函數(shù)
        this.cb = cb
        //把當前觀察者實例存放在Dep的target靜態(tài)屬性中
        Dep.target =this
        //觸發(fā)Observe的getter方法,把當前實例存放在Dep.subs中
        //data中key對應(yīng)的舊值
        this.oldValue = this.vm[this.key]
        Dep.target = null
    }
    //每個觀察者都有一個update方法來改變狀態(tài)
    update(){
        const newValue = this.vm[this.key]
        if ( this.newValue === this.oldValue ) {
            return
        }
        this.cb(newValue)
    }
}

測試

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>index</title>
    <script src="./js/dep.js"></script>
    <script src="./js/watcher.js"></script>
    <script src="./js/compiler.js"></script>
    <script src="./js/observer.js"></script>
    <script src="./js/vue.js"></script>
</head>
<body>
    <p id="app">
        <h1>差值表達式</h1>
        <h3>{{msg}}</h3>
        <h3>{{count}}</h3>
        <h1>v-text</h1>
        <p v-text='msg'></p>
        <h1>v-model</h1>
        <input type="text" v-model="msg" attr="msg">
        <input type="text" v-model="count">
        <h1>v-html</h1>
        <p v-html="htmlText"></p>
    </p>
    <script>
        let vm = new Vue({
            el:"#app",
            data:{
                msg:'信息',
                count:'數(shù)量', 
		person:{name:'張三'},
                htmlText:"<p style='color:red'>你好</p>"
            }
        })
    </script>
</body>

到此這篇關(guān)于Vue2.x響應(yīng)式簡單講解及示例的文章就介紹到這了,更多相關(guān)Vue2.x響應(yīng)式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue實現(xiàn)點擊展開點擊收起效果

    vue實現(xiàn)點擊展開點擊收起效果

    這篇文章主要介紹了vue實現(xiàn)點擊展開,點擊收起效果,首先我們需要定義data里面的數(shù)據(jù),使用computed對data進行處理,需要的朋友可以參考下
    2018-04-04
  • 如何使用fetchEventSource實現(xiàn)sse流式請求

    如何使用fetchEventSource實現(xiàn)sse流式請求

    這篇文章主要介紹了如何使用fetchEventSource實現(xiàn)sse流式請求問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • vue使用微信JS-SDK實現(xiàn)分享功能

    vue使用微信JS-SDK實現(xiàn)分享功能

    這篇文章主要介紹了vue使用微信JS-SDK實現(xiàn)分享功能,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-08-08
  • 解決vue打包 npm run build-test突然不動了的問題

    解決vue打包 npm run build-test突然不動了的問題

    這篇文章主要介紹了解決vue打包 npm run build-test突然不動了的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • VUE中$refs的基本用法舉例

    VUE中$refs的基本用法舉例

    ref 加在子組件上,用this.$refs.(ref值) 獲取到的是組件實例,可以使用組件的所有方法,?在使用方法的時候直接this.$refs.(ref值).方法() 就可以使用了,這篇文章主要介紹了VUE中$refs的基本用法,需要的朋友可以參考下
    2022-12-12
  • vue+VeeValidate 校驗范圍實例詳解(部分校驗,全部校驗)

    vue+VeeValidate 校驗范圍實例詳解(部分校驗,全部校驗)

    validate()可以指定校驗范圍內(nèi),或者是全局的 字段。而validateAll()只能校驗全局。這篇文章主要介紹了vue+VeeValidate 校驗范圍(部分校驗,全部校驗) ,需要的朋友可以參考下
    2018-10-10
  • Vue中的事件處理詳情

    Vue中的事件處理詳情

    這篇文章主要介紹了Vue中的事件處理詳情,文章通過給按鈕綁定一個?click?事件展開詳細內(nèi)容介紹,需要的小伙伴可以參考一下
    2022-05-05
  • 關(guān)于electron打包的坑

    關(guān)于electron打包的坑

    本文主要介紹了關(guān)于electron打包的坑,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03
  • vite+vue3.0+ts+element-plus快速搭建項目的實現(xiàn)

    vite+vue3.0+ts+element-plus快速搭建項目的實現(xiàn)

    本文將結(jié)合實例代碼,介紹vite+vue3.0+ts+element-plus快速搭建項目的實現(xiàn),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • Vue項目中設(shè)置背景圖片方法

    Vue項目中設(shè)置背景圖片方法

    下面小編就為大家分享一篇Vue項目中設(shè)置背景圖片方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-02-02

最新評論

明溪县| 巴林左旗| 安远县| 拜城县| 大荔县| 黑河市| 滨海县| 南郑县| 朔州市| 绥滨县| 龙岩市| 封开县| 手游| 大石桥市| 荣成市| 利辛县| 博白县| 北碚区| 古浪县| 轮台县| 汽车| 株洲县| 临江市| 木兰县| 滕州市| 南昌县| 肥东县| 佛冈县| 德安县| 镇坪县| 宣恩县| 佛山市| 西峡县| 当涂县| 临沭县| 金塔县| 六枝特区| 兴山县| 白朗县| 简阳市| 荥阳市|