欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

​ vue響應(yīng)式,我們都很熟悉了。當(dāng)我們修改vue中data對(duì)象中的屬性時(shí),頁(yè)面中引用該屬性的地方就會(huì)發(fā)生相應(yīng)的改變。避免了我們?cè)偃ゲ僮鱠om,進(jìn)行數(shù)據(jù)綁定。

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

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

vue內(nèi)部主要是通過(guò)數(shù)據(jù)劫持和觀(guān)察者模式實(shí)現(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

觀(guān)察者模式:http://www.dbjr.com.cn/article/219790.htm

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

各個(gè)成員的功能

Vue:

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

Observer:

對(duì)data對(duì)象中的簡(jiǎn)單類(lèi)型數(shù)據(jù)及對(duì)象進(jìn)行監(jiān)聽(tīng),當(dāng)數(shù)據(jù)發(fā)生變化時(shí)通知Dep

Compiler:

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

Dep:

觀(guān)察者模式中的通知者,添加觀(guān)察者,當(dāng)數(shù)據(jù)變化時(shí)通知觀(guān)察者

Watcher:

每個(gè)引用data中的屬性的地方都有一個(gè)watcher對(duì)象,負(fù)責(zé)更新視圖

附:data對(duì)象中的屬性充當(dāng)被觀(guān)察者,引用data對(duì)象中屬性的地方充當(dāng)觀(guān)察者

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

Vue對(duì)象實(shí)現(xiàn)

功能

  • 負(fù)責(zé)接受初始化的參數(shù)
  • 把data中的屬性注入到data實(shí)例,轉(zhuǎn)換成getter和setter
  • 調(diào)用Observer監(jiān)聽(tīng)data中所有屬性的變化
  • 調(diào)用compiler解析指令、差值表達(dá)式.
class Vue{
    constructor(options){
        // 1、通過(guò)屬性保存穿進(jìn)來(lái)的屬性
        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實(shí)例上
        this._proxyData(this.$data)
        // 3、調(diào)用observe對(duì)象監(jiān)視data數(shù)據(jù)的變化
        new Observer(this.$data)
        // 4、調(diào)用compiler對(duì)象渲染頁(yè)面
        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對(duì)象實(shí)現(xiàn)

功能

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

Compile對(duì)象實(shí)現(xiàn)

功能

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

    //編譯元素節(jié)點(diǎn),處理指令
    compileElement(node) {  
        //遍歷所有的指令
        Array.from(node.attributes).forEach(attr => {
            //判斷是不是指令節(jié)點(diǎn)
            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表達(dá)式的地方就是一個(gè)觀(guān)察者
        new Watcher(this.vm,key,newValue => {
            node.textContent = newValue
        })
    }
    //v-model
    modelUpdater(node,value,key){
        node.value =value
        //使用v-model表達(dá)式的地方就是一個(gè)觀(guān)察者
        new Watcher(this.vm,key,newValue => {
            node.value = newValue
        })
      //實(shí)現(xiàn)雙向綁定
        node.addEventListener('input',()=>{
            this.vm[key] = node.value
        })
    }
    //v-html
    htmlUpdater(node,value,key){
        node.innerHTML = value
        //使用v-html表達(dá)式的地方就是一個(gè)觀(guān)察者
        new Watcher(this.vm,key,newValue => {
            node.innerHTML = newValue
        })
    }

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

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

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

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

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

Dep對(duì)象實(shí)現(xiàn)

功能

  • 收集依賴(lài),添加觀(guān)察者
  • 通知所有觀(guān)察者
//通知者類(lèi)   class Dep {
    constructor() {
        //存儲(chǔ)觀(guān)察者
        this.subs = []
    }

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

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

Watcher對(duì)象實(shí)現(xiàn)

功能

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

測(cè)試

<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>差值表達(dá)式</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)式簡(jiǎn)單講解及示例的文章就介紹到這了,更多相關(guān)Vue2.x響應(yīng)式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue修改iview組件的樣式的兩種方案(element同)

    Vue修改iview組件的樣式的兩種方案(element同)

    使用vue必然會(huì)用到等iview組件庫(kù),但是iview的組件的樣式跟自己寫(xiě)的div的樣式修改不太一樣,所以本文給大家介紹了Vue修改iview組件的樣式的兩種方案(element同),需要的朋友可以參考下
    2024-04-04
  • 解決Vue中 父子傳值 數(shù)據(jù)丟失問(wèn)題

    解決Vue中 父子傳值 數(shù)據(jù)丟失問(wèn)題

    這篇文章主要介紹了解決Vue中 父子傳值 數(shù)據(jù)丟失問(wèn)題,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-08-08
  • 詳解vue2 $watch要注意的問(wèn)題

    詳解vue2 $watch要注意的問(wèn)題

    本篇文章主要介紹了詳解vue2 $watch要注意的問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • elementui的el-popover修改樣式不生效的解決

    elementui的el-popover修改樣式不生效的解決

    在使用element-ui的時(shí)候,有一個(gè)常用的組件,那就是el-popover,本文就介紹一下elementui的el-popover修改樣式不生效的解決方法,感興趣的可以了解一下
    2021-06-06
  • vue3自定義hooks/可組合函數(shù)方式

    vue3自定義hooks/可組合函數(shù)方式

    這篇文章主要介紹了vue3自定義hooks/可組合函數(shù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • vue中路由傳參以及跨組件傳參詳解

    vue中路由傳參以及跨組件傳參詳解

    這篇文章主要給大家介紹了關(guān)于vue中路由傳參以及跨組件傳參的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • 關(guān)于vue自適應(yīng)布局(各種瀏覽器,分辨率)的示例代碼

    關(guān)于vue自適應(yīng)布局(各種瀏覽器,分辨率)的示例代碼

    這篇文章主要介紹了vue自適應(yīng)布局(各種瀏覽器,分辨率),主要使用了flex布局的flex:1屬性和自適應(yīng)的css+vh+百分比這種方式,開(kāi)局設(shè)置overflow:hidden,主體main部分要設(shè)置:overflow:auto,需要的朋友可以參考下
    2022-09-09
  • Vue封裝遠(yuǎn)程下拉框組件的實(shí)現(xiàn)示例

    Vue封裝遠(yuǎn)程下拉框組件的實(shí)現(xiàn)示例

    本文主要介紹了Vue封裝遠(yuǎn)程下拉框組件的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • vue+axios+java實(shí)現(xiàn)文件上傳功能

    vue+axios+java實(shí)現(xiàn)文件上傳功能

    這篇文章主要為大家詳細(xì)介紹了vue+axios+java實(shí)現(xiàn)文件上傳功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • 對(duì)vue中v-on綁定自定事件的實(shí)例講解

    對(duì)vue中v-on綁定自定事件的實(shí)例講解

    今天小編就為大家分享一篇對(duì)vue中v-on綁定自定事件的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09

最新評(píng)論