Vue專欄 - Vue中常用的指令一覽(用原生js對比Vue指令, 讓你深刻理解key值存在的意義是什麼)

Vue專欄 - Vue中的指令

目錄:

筆者挑了一些常用指令來寫寫,比如像v-cloak這類指令, 就被自動忽略啦

  • v-bind

  • v-html

  • v-text

  • v-for

  • v-if, v-else if, v-else

  • v-once

  • v-model

  • v-on

  • 自定義指令

指令

我們之前一直有提到Vue框架的侵入性, 那麼他到底侵入在哪裏, 這裏筆者就來寫寫他侵入性的第一種凸顯, 就是你想用Vue框架開發代碼, 想用它來進行點擊事件, 鼠標事件等操作, 你就要按照他的規則來

在以前的原生js開發中, 我們給dom綁定事件的操作如下

const dom = document.querySelector('.wrapper');
dom.onclick = function() {
    console.log('我被點擊了'); 
}

而Vue中, 我們大可不比如此

...
<body>
    <div class='wrapper' @click = "handleClick"></div>
    <script>
        const vm = new Vue({
            el: '.wrapper',
            methods: {
                handleClick() {
                    console.log('我被點擊了');
                }
            }
        })
    </script>
</body>
...

你不必馬上搞懂上面的例子, 咱先混個臉熟

指令是Vue提供給我們的一項比較常用的功能, 他帶有前綴v-, 指令的職責也就是幫助我們更好的控制一個dom元素,他書寫在我們想要控制的dom元素中, 因爲Vue的虛擬dom緣故, 所以我們也必須儘量少操作原生dom, 這些指令讓我們的開發更加的高效和便捷

那咱們一個一個的來看看吧

v-bind

我們在以前做開發的時候, 肯定會遇到一些業務邏輯, 比如class類名要動態綁定, 或者要給某個dom元素上綁定一定的屬性, 又或者直接跟表單控件的value值進行綁定使其變爲受控組件, 這些業務通常都讓我們大傷腦筋, 倒不是因爲他多難, 只是他寫的代碼着實有點多

比如我現在有個業務, 後臺傳遞過來一個對象, 這個對象是經常會變化的, 該對象有一個name屬性, 我們必須將這個name屬性綁定在類名爲box的dom元素上, 保證每次都穩穩的拿到正確的對象

我們使用原生js的話大致操作如下

...
<body>
    <div class='box'></div>
    <script>
      
        (function() {
            const box = document.querySelector('.box'); // 拿到dom元素
            getData() {
                ajax('api/getObj', 'GET', resp => {
                    box.setAttribute('name', resp.name);
                })
            }  
            
            getData();
        })()

    </script>
</body>
...

在Vue中, v-bind幫我們優雅的處理了這個問題

...
<body>
    <!-- !!!v-bind出現在下方的dom元素中 -->
    <div class='wrapper' v-bind:name='name'></div>

    <script>
        const vm = new Vue({
            el: '.wrapper',
            data: {
                name: 'loki'
            },
            // 這個mounted你現在不必明白他是啥, 同樣, 臉熟就好, 他其實就是會在頁面加載完畢的時候執行, 然後
            // 他一執行 getData也執行了
            mounted() {
                this.getData(); 
            },
            methods: {
                getData() { 
                    ajax('api/getObj', 'GET', resp => {
                        this.name = resp.name; // 看起來更加的優雅, 而且也方便維護  
                    })
                }
            }
        })
    </script>
</body>
...

v-bind有一個語法糖, 用:代替v-bind:

v-bind:name='name'我們可以直接寫成:name='name'

同樣, 我們可以用它來綁定動態class

<div id='app'>
    <!-- 介紹兩種常用的綁定類名的方式, 其他的可以自己查看api -->
    <!-- box一定會出現在類名中, 而active是否展示取決於isActive是否爲true -->
    <div :class="{ 'box': true, 'active': isActive }">
    <div :class="[isActive ? 'active': '']">

</div>

<script>
    const vm = new Vue({
        el: '#app',
        data: {
            isActive: true
        }
    })

</script>

對錶單進行控制

// 由此表單成爲了受控組件
<input :value='inputValue' />

上面的綁定的值, 都建立在被Vue實例接管的情況下, 綁定的變量會去Vue實例中尋找, 我就省略沒書寫了

這個v-bind暫時你可能覺得沒大用處, 但是請記住他, 隨着你對vue理解越來越深刻, 它一定是你的座上賓

v-html

v-html 作用其實跟js中的innerHTML完全一致, 就是將v-html所攜帶的值通過html的形式插入到某個dom中

在原生js中, 我們需要改變一個dom元素中的html模板, 一般是如下操作

(function(){
    const div = document.querySelector('.wrapper');
    div.innerHTML = '<span>helloWorld</span>';
}())

在Vue中, 我們的操作變得很清新脫俗

...
<body>
    <!-- !!!v-html出現在下方的dom元素中 -->
    <div class='wrapper' v-html = 'htmlStr'></div>

    <script>
        const vm = new Vue({
            el: '.wrapper',
            data: {
                htmlStr: '<span>helloWorld</span>'
            }
        })
    </script>
</body>
...

這樣我們就實現了同樣功能

v-text

這哥們相信筆者不用過多介紹大家也能夠猜得出他的作用的,沒錯這哥們和innerText如出一轍, 功能也完全一樣

原生js控制innerText操作如下

    (function() {
        const div = document.querySelector('.wrapper');
        div.innerHTML = 'helloWorld';
    }())

Vue接管了以後如下

    ...
<body>
    <!-- !!!v-text出現下方的dom元素中 -->
    <div class='wrapper' v-text = 'textStr'></div>

    <script>
        const vm = new Vue({
            el: '.wrapper',
            data: {
                textStr: 'helloWorld'
            }
        })
    </script>
</body>
...

v-for

兩個字, 循環, Vue中的循環很秀, 當我們要將一個數組或者對象循環並且讓他們的值放進dom元素中顯示的時候, 就會要用到他, 同樣來看實例

原生js

(function() {
    const arr = ['loki', 'thor'];
    const domArr = arr.map(ele => {
        var li = document.createElement('li');
        li.innerText = ele;
        return li;
    });
    const ul = document.querySelector('ul');
    domArr.forEach(ele => ul.appendChild(ele));
}())

Vue v-for

...
<body>
    <!-- !!!v-for出現下方的dom元素中 -->
    <ul>
        <li v-for='name in arr' :key='name'>{{ name }}</li>
    </ul>

    <script>
        const vm = new Vue({
            el: 'ul',
            data: {
                arr: ['loki', 'thor']
            }
        })
    </script>
</body>
...

v-for的語法 就是
v-for="(ele, index) in data" :key="unique value"

v-for中的in也可以用of代替

  • ele: 遍歷出來的每一項

  • index: 如果是數組, 索引爲數組的index項, 如果是對象, index爲對象的key值非必填

  • data: 被遍歷的數據

  • key: 一個唯一值, 這個key值很重要, 在Vue的底層diff算法中, 他通過key值來更快的尋找到某個虛擬dom並且跟真實dom進行比對, 如果無key值的話, 可能會感知不到變化, 這是diff算法底層的知識, 我可以做個例子演示一波

如果你用數組的index作爲key值, 那麼在某些情況下跟沒有給定key值沒有區別, 還多寫了一些代碼, 如果你不給key值, 那看了代碼讓人覺得頭皮發麻

這裏我給你寫明白了, 讓你看看爲什麼key值不能亂給

...
<body>
      <div id="app">
        <ul>
            <li v-for="(ele, index) in arr" :key="ele">{{ ele }}</li>
        </ul>
        <!-- 下面的@click馬上就會講到, 這裏混個臉熟, 就是綁定點擊事件 -->
        <button @click="reverseArr">reverse</button>
    </div>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                arr: ['loki', 'andy', 'thor']
            },
            methods: {
                reverseArr() {
                    this.arr.unshift('messy');
                }
            }
        })
    </script>
</body>
...

當我們不給定key值或者將key值給爲index, 我們觀察會發現, 在控制檯中的Elements中查看dom元素的時候, 我們僅僅只是增加一個人名, 但是四個li的dom元素都進行了重新渲染,

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Vx5rRfyh-1583326504709)('..')]

而我們如果將key值改爲一個唯一值,情況則不一樣

...
<!-- 下方的key值經過拼接在這個案例中是唯一的, 一般的開發中後端會返回id過來 -->
<li v-for="(ele, index) in arr" :key="`${ele}_${index}`">{{ ele }}</li>
...

我們發現只有新增的dom被重新渲染了, 其他dom都沒有變化, 這樣對性能的消耗大大降低

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-sQYVLyoI-1583326504710)('...')]

所以說這個key值我們必須給, 還得是唯一值, 因爲他會幫我們儘可能的減少dom的操作

v-if, v-else-if, v-else

與JavaScript的條件語句 if, else, else if邏輯相似, Vuejs的條件指令可以根據表達式的值在dom中渲染或者銷燬元素/組件

在過去中, 如果我們想通過某個屬性控制dom元素的存在與否(注意: 不是顯示與否), 我們大概率會通過如下操作

(function() {
    const div = document.querySelector('.wrapper');
    const btn = document.querySelector('.btn');
    let flag = true;
    btn.onclick = function() {
        flag = !flag;
        if(flag) div.innerHTML = '<span>你好, 我是loki</span>';
        else div.innerHTML = '<p>你好, 我是thor</p>'
    }
}())

這樣我們就基本控制了一個元素的銷燬與否, flag爲true的時候p元素是完全被銷燬狀態的, 不存在與dom結構中

而Vue幫助我們實現同樣的功能, 衍生出了v-if, v-else, v-else-if

...
<body>
    <div id='#app'>
        <div class='wrapper'>
            <span v-if="flag">你好, 我是loki</span>
            <p v-else>你好, 我是thor</p>
        </div>
        <button @click='changeStatus' class='.btn'>Click Me</button>
    </div>
    <script>
        
        const vm = new Vue({
            el: '#app',
            data: {
                flag: true
            },
            methods: {
                changeStatus() {
                    this.flag = !this.flag;
                }
            }
        })
    </script>
</body>
...

注意: v-ifv-else, v-else-if必須是兄弟元素緊緊地帖在一起, 就他們中不允許有第三者或者第四者插足, 像下方這種情況就會報錯

<div id='app'>
    <p v-if='flag'>你好</p>
    <span>hello</span>
    <p v-else>我叫loki</p>
</div>

v-show

上面的v-if我們說是讓一個元素永久的銷燬或者存在的, 而假如我們有一個元素是需要經常的切換顯示隱藏的, 我們可能就不是很想用v-if了, 因爲v-if引發的重排對性能消耗是挺大的, 我們是否有一種讓元素隱藏的方案呢, 當然有, 那就是v-show

v-show用法與v-if基本一致, 只是當使用了v-show來控制元素顯示與否的話, 等於給鈣元素設置display:none 和block一樣, 同時該元素綁定的事件仍然可以觸發

v-once

假如我們有一個需求是讓一個元素的內容只在第一次渲染, 後面無論數據怎麼產生變化, 頁面都不會再進行渲染和變更了, 那麼這個時候我們可以用到v-once

v-model

我們知道MVVM模式的核心是雙向數據綁定, 而Vue在這種模式下提出了v-model指令, 我們一起來看看這哥們的神通

我們現在有一個需求要實現的功能如下

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-UHLLVn54-1583326504711)('..')]

上方的功能其實已經稱之爲雙向數據綁定了, 當我們在操控視圖(不斷在輸入框鍵入值的時候, 後臺的數據會變化, 同時後臺的數據產生變化影響了下方的文字顯示產生變化)

就如上方的功能我們如果用原生js寫應該怎麼寫呢? 大家也可以思考思考

(function() {
    // 頁面中有一個input框, 和一個class爲'input-value'的span標籤
    // 原生js
    const input = document.querySelector('input');
    const showValue = document.querySelector('.input-value');

    input.oninput = function(e) {
        let resultValue = e.target.value; // 拿到input的值
        showValue.innerText = resultValue;
    }
}())

用Vue的話其實簡單很多

...
<body>
    <div class="wrapper">
        <input v-model='inputValue' type="text" name="" id="" />
        <p>您當前寫入的值:<span class="input-value">{{ inputValue }}</span></p>
    </div>

    <script>
        const vm = new Vue({
            el: '.wrapper',
            data: {
                inputValue: ''
            }
        })

    </script>
</body>
..

在input上加的一個v-model解決所有難題

你可以把v-model可以放在任何你想要監控的表單控件上, 一旦添加了v-model, 則表單變爲受控組件

實際上,v-model其實是一個語法糖, 它的本來面目其實就是這樣的

...
<body>
    <div class="wrapper">
        <!-- @input是一個事件, 跟oninput功能完全一樣, 先混個臉熟 -->
        <input :value='inputValue' @input='changeValue' type="text" name="" id="" />
        <p>您當前寫入的值:<span class="input-value">{{ inputValue }}</span></p>
    </div>

    <script>
        const vm = new Vue({
            el: '.wrapper',
            data: {
                inputValue: ''
            },
            methods: {
                changeValue(e) {
                    this.inputValue = e.target.value;
                }
            }
        })

    </script>
</body>
..

修飾符, 在v-model中也給我們提供了一些修飾符, 至於修飾符是什麼, 在稍後的事件板塊我會詳細介紹, 這裏等同於混個臉熟, 等看完事件再來回過頭來看看這兒, 會有不同的新收穫

  • .lazy: v-model默認是@input和value的語法糖, 也就是我們沒鍵入一次value都會產生響應的改變, 而我們設置爲lazy以後, v-model就成了@change和value的語法糖了, 必須等到輸入框失去焦點或者按下回車value值纔會進行更改

  • .trim: 自動消除綁定值的前後空格

  • .number: 會將輸入轉換爲Number類型, 因爲我們知道, 我們從input框提取出來的value值其實是String類型, 加上這個修飾符我們可以直接提取到Number類型的值

<!-- 可以連着寫 -->
<input v-model.lazy.trim='inputValue' />

v-on

在原生js中, 相信大家都給dom元素綁定過事件, 我們通常是如下操作

const div = document.querySelector('div');
div.onclick = function() {
    console.log('hello');
}

div.addEventListener('mouseover', function(){
    console.log('change')
}, false)

由於在Vue中我們暫時無法獲得dom元素, 實際上如果直接操控dom, 那麼我們用不用Vue都無所謂了, 所以Vue跟其他指令一樣, 給我們提供了一個v-on指令, 直接寫在被Vue實例接管區域內的dom元素上

...
<body>
      <div id="app">
        <div class='box' v-on:click = 'handleClick'>xxx</div>
    </div>

    <script>
        const vm = new Vue({
            el: '#app',
            methods: {
                handleClick() {
                    console.log('hello');
                }
            }
        })
    </script>
</body>
...

而同時, 跟v-bind一樣, v-on也提供一個語法糖

我們可以使用@來代替v-on:

<div class='box' @click = 'handleClick'>xxx</div>

關於事件源對象e

大家可能會關心事件源對象e, 其實不用擔心, 事件源對象Vue也會完好無損的通過第一個參數來傳遞給我們(前提是我們沒有自己傳參),如果我們自己傳了參, Vue則會通過$event來傳遞給我們

...
<body>
    <div id="app">
        // 注意在這裏需要手動傳入$event
        <div class='box' v-on:click = 'handleClick' @mouseover='handleOver($event,"loki")'>xxx</div>
    </div>

    <script>
        const vm = new Vue({
            el: '#app',
            methods: {
                handleClick(e) {
                    console.log(e);
                },
                handleOver(name, $event) {
                    console.log($event, name)
                }
            }
        })
    </script>
</body>
...

至於事件, 五花八門的, 比如click, mouseover, mouseenter好多包括自定義事件, 稍後會在事件專欄中好好寫寫,

自定義指令

Vue在提供給我們內置指令的同時, 也允許我們自己註冊自定義指令進行擴展, 這些自定義指令會在某些特殊場景中產生奇效

自定義指令我明天再寫, 今天累了

至此, Vue中常用的指令筆者已經分析完畢, 希望可以幫助到你, 也希望筆者說清楚了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章