Vue.js-11:第十一章 - Vue 中 ref 的使用

墨墨墨墨小宇發表於2019-04-29

前言

        在之前的前端開發中,為了實現我們的需求,通常採用的方案是通過 JS/Jquery 直接操縱頁面的 DOM 元素,得益於 Jquery 對於 DOM 元素優異的操作能力,我們可以很輕易的對獲取到的 DOM 元素進行操作。但是,當我們開始在前端專案中使用 Vue 這類的 MVVM 框架之後,對於 DOM 的操作我們就應當完全的交給框架,而我們只需要關注於資料。難道,在 Vue 中就不能手動獲取到頁面上的 DOM 元素了嗎,答案當然是可以手動獲取到 DOM 元素的,在 Vue 中我們可以通過使用 ref 實現獲取 DOM 元素的功能,當然,這也只是 ref 其中一項的功能。本章,我們就來學習 Vue 中 ref 的相關使用。

        系列目錄地址:Vue.js 牛刀小試

        倉儲地址:Chapter02-Bronze Get Elements

乾貨合集

        ref 在 Vue 中是用來給元素或是子元件註冊引用資訊到父元件或是 Vue 例項上,註冊後的引用資訊都會呈現在父元件/Vue 例項的 $.refs 上,這時,我們就可以通過 $.refs 獲取到引用的 DOM 物件或是子元件資訊。

        例如,我們可以獲取到頁面上新增了 ref 的 input 輸入框的值,對於子元件來說,我們可以直接獲取到子元件 data 選項中的資料,或是直接呼叫子元件的方法。

        一、 虛擬 DOM 元素

        在我們使用 JS/Jquery 直接對 DOM 元素進行操作時,不管是對元素樣式的修改(背景顏色從紅色變成藍色)還是對頁面中的某些佈局進行動態調整(通過點選按鈕在列表中新增一行新的資料),這都會造成頁面的重新渲染,從而影響我們網站的效能。而在 Vue 中,通過在記憶體中生成與真實 DOM 與之對應的資料結構(虛擬 DOM),當頁面發生變化時,通過新的虛擬 DOM 樹與舊的虛擬 DOM 樹進行比對,就能很快的找出差異點,從而得出應施加到真實 DOM 上的改動。

虛擬DOM(圖片版權屬於 Vue 作者尤雨溪)

        二、 使用 ref 獲取頁面 DOM 元素

        在使用 JS/Jquery 獲取頁面的 DOM 元素時,我們一般是根據 id、class、標籤、屬性等其它標識來獲取到頁面上的 DOM 元素。嗯,可以說,我們很難拋棄 Jquery 的一個重大原因,就是當我們需要獲取到頁面上的 DOM 元素時,使用 Jquery 的 API 相比於原生的 JS 程式碼,簡單到極致,有木有。

document.getElementById('id').value => $('#id').val()
複製程式碼

        那麼,難道我們在 Vue 中獲取 DOM 元素還是採用這樣的方式?

        答案當然是否定的,這種直接操縱 DOM 元素的方式,與我們使用 Vue 的初衷不符,雖然能達成效果,但是卻不提倡,這裡我們就可以使用 ref 來獲取頁面上的 DOM 元素。

        在下面的程式碼中,我在 input 上新增了一個 ref 屬性,之後,我們就可以在 Vue 例項中獲取到這個 input 輸入框的值。這裡,我在 beforeMount、mounted 這兩個 Vue 中的生命週期鉤子函式以及一個按鈕的點選事件中嘗試獲取到這個 input 輸入框的值。

<div id="app">
    <input type="text" ref="msgText" v-model="msg" />
    <button @click="getElement">獲取元素值</button>
</div>

<script>
    var vm = new Vue({
        el: "#app",
        data: {
            msg: 'Hello ref'
        },
        beforeMount() {
            console.log('beforeMount: ' + this.$refs.msgText.value)
        },
        mounted() {
            console.log('mounted: ' + this.$refs.msgText.value)
        },
        methods: {
            getElement() {
                console.log(this.$refs.msgText.value)
            }
        }
    });
</script>
複製程式碼

獲取 DOM 元素
        執行程式碼,從結果中可以看到,在 beforeMount 這個鉤子函式中,我們是無法獲取到這個 DOM 元素的值,結合之前學習的 Vue 生命週期的相關知識,當執行到 beforeMount 鉤子函式時,Vue 雖然已經將模板編譯完成,但是尚未掛載到頁面 DOM 元素上,因此我們可以得出 ref 是在頁面渲染完成後才被建立的。
\$refs
        可以看到,當我們在 input 輸入框中新增了 ref 屬性後,在當前的 Vue 例項的 $.refs 上就掛載了當前的 input 框物件。

        三、 使用 ref 獲取子元件物件

        同使用 ref 獲取頁面的 DOM 元素相似,當我們需要獲取子元件時,只需要將使用到子元件上的地方新增 ref 屬性即可。在下面的示例程式碼中,我新增了一個子元件,當我們點選 Vue 例項上的按鈕時,會先呼叫子元件的方法,然後獲取子元件的資料。

<div id="app">
    <input type="text" ref="msgText" v-model="msg" />
    <button @click="getElement">獲取元素值</button>

    <hr>

    <child ref="childComponent"></child>
</div>

<template id="child">
    <div>
        <input type="datetime" name="datetime" v-model="local">
        <button @click="getLocalData">獲取當前時間</button>
    </div>
</template>

<script>
    var vm = new Vue({
        el: "#app",
        data: {
            msg: 'Hello ref'
        },
        mounted() {
            console.log('mounted: ' + this.$refs.msgText.value)
        },
        methods: {
            getElement() {
                console.log('input 輸入框的值為:' + this.$refs.msgText.value)
                this.$refs.childComponent.getLocalData()
                console.log('子元件 input 輸入框的值為:' + this.$refs.childComponent.local)
            }
        },
        components: {
            'child': {
                template: '#child',
                data() {
                    return {
                        local: ''
                    }
                },
                methods: {
                    getLocalData() {
                        var date = new Date()
                        this.local = date.toLocaleString()
                    }
                },
            }
        }
    });
</script>
複製程式碼

使用 ref 獲取子元件物件
        可以看到,當我們將 ref 新增到子元件上,我們就可以在 Vue 例項上獲取到這個註冊的元件引用,同註冊的 DOM 元素一樣,我們都可以使用新增的 ref 屬性值作為 key 獲取到註冊的物件。此時,我們就可以獲取到這個子元件上的 data 選項和 methods 選項。
父元件呼叫子元件方法

總結

        因為 Vue 採用 Virtual DOM 的做法渲染網頁,如果我們直接操作 DOM,很容易產生實際網頁跟 Vue 產生的 Virtual DOM 不同步的問題,而通過使用 ref 屬性之後,在一些需要獲取 DOM 元素的情況下,我們就可以很方便的獲取 DOM 元素。當然,當我們決定在專案中使用 Vue,還是需要轉變我們的思路,將操作 DOM 轉變成運算元據。同樣的,通過將 ref 屬性新增到子元件上,我們就可以很輕鬆的獲取到子元件的相關資訊,這無疑給父元件獲取子元件資料、呼叫子元件的方法提供了一種新的思路。

參考

        1、網頁效能管理詳解

        2、重排重繪,看這一篇就夠了

        3、Vue作者尤雨溪:Vue 2.0,漸進式前端解決方案

        4、vue中的 ref 和 $refs

佔坑

        作者:墨墨墨墨小宇
        個人簡介:96年生人,出生於安徽某四線城市,畢業於Top 10000000 院校。.NET程式設計師,槍手死忠,喵星人。於2016年12月開始.NET程式設計師生涯,微軟.NET技術的堅定堅持者,立志成為雲養貓的少年中面向谷歌程式設計最厲害的.NET程式設計師。
        個人部落格:yuiter.com
        部落格園部落格:www.cnblogs.com/danvic712

相關文章