溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Vue中的MVVM模式原理是什么

發(fā)布時(shí)間:2023-03-09 14:58:04 來源:億速云 閱讀:122 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“Vue中的MVVM模式原理是什么”的相關(guān)知識(shí),小編通過實(shí)際案例向大家展示操作過程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“Vue中的MVVM模式原理是什么”文章能幫助大家解決問題。

    1. MVVM模式

    傳統(tǒng)的組件是靜態(tài)渲染,數(shù)據(jù)更新需要操作DOM。Vue框架采用了MVVM(Model-View-ViewModel)模式來管理應(yīng)用程序的數(shù)據(jù)模型(Model)和視圖界面(View)的交互,即數(shù)據(jù)驅(qū)動(dòng)視圖,從而避免了操作DOM。

    MVVM的基本思想是將模型數(shù)據(jù)和用戶視圖解耦(Decoupling),即Model和View分離開來,使得它們之間的依賴關(guān)系降到最小。然后通過ViewModel來協(xié)調(diào)它們之間的通信。當(dāng)Model發(fā)生變化時(shí),我們不需要手動(dòng)更新View,而是可以通過Vue的響應(yīng)式機(jī)制,讓Vue自動(dòng)更新View。同樣,當(dāng)用戶與View交互時(shí),我們也不需要手動(dòng)修改Model,而是可以通過Vue的指令和事件機(jī)制,讓Vue自動(dòng)更新Model。這種解耦機(jī)制使得我們可以更加專注于業(yè)務(wù)邏輯的實(shí)現(xiàn),而不需要過多地關(guān)注View和Model之間的細(xì)節(jié)。

    Vue中的MVVM模式原理是什么

    • Model:Vue應(yīng)用程序中的數(shù)據(jù)模型,通常是一個(gè)JavaScript對(duì)象或數(shù)組。這些數(shù)據(jù)模型被存儲(chǔ)在Vue實(shí)例的data屬性中。

    • View:Vue應(yīng)用程序中的視圖界面,通常是由HTML模板和Vue指令組成的。Vue的模板語法允許開發(fā)人員在HTML中綁定數(shù)據(jù)和表達(dá)式,以實(shí)現(xiàn)動(dòng)態(tài)更新。

    • ViewModel:ViewModel是Vue應(yīng)用程序的核心,它是一個(gè)Vue實(shí)例,它充當(dāng)Model和View之間的橋梁。ViewModel負(fù)責(zé)管理數(shù)據(jù)和行為,它可以將Model數(shù)據(jù)綁定到View上,同時(shí)也可以響應(yīng)View上的事件和用戶交互。ViewModel中包含了一個(gè)Watcher和Directive,它們可以監(jiān)聽Model數(shù)據(jù)的變化,并自動(dòng)更新View。

    2. Vue響應(yīng)式

    Vue的響應(yīng)式機(jī)制是指當(dāng)Vue實(shí)例中的數(shù)據(jù)發(fā)生變化時(shí),與之關(guān)聯(lián)的視圖會(huì)自動(dòng)更新。實(shí)現(xiàn)Vue響應(yīng)式機(jī)制需要借助ES5的Object.defineProperty()方法,使用該方法監(jiān)聽對(duì)象屬性的變化。

    Object.defineProperty(obj, prop, descriptor)用來定義對(duì)象的屬性。函數(shù)中傳入三個(gè)參數(shù),obj表示要定義屬性的對(duì)象,prop表示要定義的屬性名,descriptor是一個(gè)包含屬性描述符的對(duì)象。下面這段代碼是該函數(shù)的基本使用:

    let data = {};
    let name = '小明';
    Object.defineProperty(data, "name", {
        get: function(){
            console.log('get')
            return name
        },
        set: function(newValue){
            console.log('set')
            name = newValue
        }
    })
    // 測(cè)試
    console.log(data.name)
    data.name = '小紅'
    console.log(data.name)

    Vue中的MVVM模式原理是什么

    3. Vue監(jiān)聽對(duì)象

    3.1 監(jiān)聽普通對(duì)象

    以下代碼模擬了的監(jiān)聽對(duì)象的過程,當(dāng)data對(duì)象中的數(shù)據(jù)發(fā)生變化時(shí),就會(huì)調(diào)用updateView()函數(shù),觸發(fā)視圖更新。

    // 觸發(fā)視圖更新,模擬Model變化后,View發(fā)生改變,簡(jiǎn)單起見就直接打印一個(gè)結(jié)果
    function updateView(){
    	console.log('視圖更新')
    }
    // 重新定義屬性,實(shí)現(xiàn)對(duì)數(shù)據(jù)的監(jiān)聽
    function defineReactive(target, key, value){
    	// 核心 API
    	Object.defineProperty(target, key, {
    		get(){
    			return value
    		},
    		set(newValue){
    			if(newValue !== value){
    				value = newValue
    				updateView()
    			}
    		}
    	})
    }
    // 監(jiān)聽對(duì)象屬性
    function observer(target){
    	// 如果監(jiān)聽的數(shù)據(jù)類型不是對(duì)象,直接返回原數(shù)據(jù)
    	if(typeof target !== 'object' || target === null){
    		return target
    	}
    	// 重新定義對(duì)象的每個(gè)屬性
    	for(let key in target){
    		defineReactive(target, key, target[key])
    	}
    }
    // 數(shù)據(jù)
    let data = {
    	name: '小明',
    	age: 20,
    	info: {
    		address: '北京'
    	}
    }
    // 監(jiān)聽數(shù)據(jù)
    observer(data)
    // 測(cè)試
    data.name = '小紅'
    data.age = 21
    data.name  // 會(huì)觸發(fā)getter函數(shù)
    data.age

    Vue中的MVVM模式原理是什么

    3.2 監(jiān)聽復(fù)雜對(duì)象(深度監(jiān)聽)

    假如數(shù)據(jù)對(duì)象中還包含對(duì)象,此時(shí)就需要進(jìn)行深度監(jiān)聽,例如data中的info數(shù)據(jù)。只需要在上述的defineReactive()函數(shù)中,再次調(diào)用observer()函數(shù),對(duì)傳入的對(duì)象的屬性值value進(jìn)行監(jiān)聽。

    設(shè)置新值時(shí),如果設(shè)置的值還是一個(gè)對(duì)象類型,此時(shí)還需要對(duì)新值進(jìn)行監(jiān)聽。

    function updateView(){
    	console.log('視圖更新')
    }
    // 重新定義屬性,實(shí)現(xiàn)對(duì)數(shù)據(jù)的監(jiān)聽
    function defineReactive(target, key, value){
    	// 再次對(duì)傳入的對(duì)象的屬性值調(diào)用監(jiān)聽函數(shù)
    	observer(value)
    	// 核心 API
    	Object.defineProperty(target, key, {
    		get(){
    			return value
    		},
    		set(newValue){
    			// 對(duì)新設(shè)置的值進(jìn)行監(jiān)聽
    			observer(newValue)
    			if(newValue !== value){
    				value = newValue
    				updateView()
    			}
    		}
    	})
    }
    // 監(jiān)聽對(duì)象屬性
    function observer(target){
    	// 如果監(jiān)聽的數(shù)據(jù)類型不是對(duì)象,直接返回原數(shù)據(jù)
    	if(typeof target !== 'object' || target === null){
    		return target
    	}
    	// 重新定義對(duì)象的每個(gè)屬性
    	for(let key in target){
    		defineReactive(target, key, target[key])
    	}
    }
    // 數(shù)據(jù)
    let data = {
    	name: '小明',
    	age: 20,
    	info: {
    		address: '北京'
    	}
    }
    // 監(jiān)聽數(shù)據(jù)
    observer(data)
    // 測(cè)試
    data.name = '小紅'
    data.age = {num: 21}
    data.age.num = 22  
    data.info.address = '上海'

    Vue中的MVVM模式原理是什么

    4. Vue監(jiān)聽數(shù)組

    // 觸發(fā)更新視圖
    function updateView() {
        console.log('視圖更新')
    }
    // // 重新定義數(shù)組原型
    const oldArrayProperty = Array.prototype
    // 創(chuàng)建新對(duì)象,原型指向 oldArrayProperty ,再擴(kuò)展新的方法不會(huì)影響原型
    const arrProto = Object.create(oldArrayProperty);
    // 對(duì)數(shù)常用的方法進(jìn)行擴(kuò)展
    ['push', 'pop', 'shift', 'unshift', 'splice'].forEach(methodName => {
        arrProto[methodName] = function () {
            oldArrayProperty[methodName].call(this, ...arguments)
            updateView() // 觸發(fā)視圖更新
            Array.prototype[methodName].call(this, ...arguments)
        }
    })
    // 重新定義屬性,監(jiān)聽起來
    function defineReactive(target, key, value) {
        // 深度監(jiān)聽
        observer(value)
        // 核心 API
        Object.defineProperty(target, key, {
            get() {
                return value
            },
            set(newValue) {
                if (newValue !== value) {
                    // // 深度監(jiān)聽
                    observer(newValue)
                    // 設(shè)置新值
                    // 注意,value 一直在閉包中,此處設(shè)置完之后,再 get 時(shí)也是會(huì)獲取最新的值
                    value = newValue
                    // 觸發(fā)更新視圖
                    updateView()
                }
            }
        })
    }
    // 監(jiān)聽對(duì)象屬性
    function observer(target) {
        if (typeof target !== 'object' || target === null) {
            // 不是對(duì)象或數(shù)組
            return target
        }
        // 修改數(shù)組的原型
        if (Array.isArray(target)) {
            target.__proto__ = arrProto
        }
        // 重新定義各個(gè)屬性(for in 也可以遍歷數(shù)組)
        for (let key in target) {
            defineReactive(target, key, target[key])
        }
    }
    // 準(zhǔn)備數(shù)據(jù)
    const data = {
        // name: '小明',
        // age: 20,
        // info: {
        //     address: '北京' // 需要深度監(jiān)聽
        // },
        nums: [10, 20, 30]
    }
    // 監(jiān)聽數(shù)據(jù)
    observer(data)
    // 測(cè)試
    data.nums.push(4) // 監(jiān)聽數(shù)組

    5. 使用 Object.defineProperty 監(jiān)聽數(shù)據(jù)的缺點(diǎn)

    • 深度監(jiān)聽需要對(duì)數(shù)據(jù)對(duì)象遞歸到底,一次性計(jì)算量大。

    • 如果數(shù)據(jù)新增屬性和刪除屬性,則無法監(jiān)聽到,需要使用 Vue.set()Vue.delete() 方法。

    • 無法原生監(jiān)聽數(shù)組,需要特殊處理。

    關(guān)于“Vue中的MVVM模式原理是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI