1. 程式人生 > 實用技巧 >二. Vue指令

二. Vue指令

1. Vue指令理解

Vue指令指的是以 v- 開頭的一組特殊語法

2. 內容繫結

2.1 v-text指令 與 {{}} 插值表示式

注:{{}} 插值表示式也被稱作 Mustache語法

作用

設定標籤的文字值

注:

v-text 會替換全部內容,使用差值表示式 {{}} 可以替換指定內容

② 兩種方式都支援寫表示式

v-text 與 {{}} 區別

使用 v-text 取值會將標籤中原有的資料覆蓋,而插值表示式不會

使用 v-text 可以避免在網路環境差的情況下出現插值閃爍(先出現 {{xx}}

<div id="app">
    <h2 v-text="message"></h2>
    <!-- 另一種寫法:插值表示式 -->
    <h2>瞅啥!{{message}}</h2> 
    <!-- 支援寫表示式如字串的拼接 -->
    <h2 v-text="message + '_' + person.name"></h2>
    <h2>瞅啥!{{message + "GG" + person.name}}</h2> 
</div>
2.2 v-html指令

作用

設定元素的innerHTML

使用場景

內容中有html結構會被解析為標籤,而v-text指令無論內容是什麼只會解析為文字

解析文字使用 v-text,需要解析html結構使用v-html

<div id="app">
    <p v-html="message"></p>
    <p v-html="content"></p>
</div>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue!',
            content:"<a href='#'>Hello Vue!</a>",
        },       
    })
</script>
2.3 v-once指令

加上 v-once,當前元素和元件只渲染一次,不會隨著vue例項中data資料的改變而改變

<div id="app">
    <h2>{{message}}</h2>
    <h2 v-once>{{message}}</h2>
</div>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            message: '你好啊'
        }
    })
</script>
2.4 v-pre指令

用於跳過這個元素和它子元素的編譯過程,用於顯示原本的 Mustache語法

<div id="app">
    <h2>{{message}}</h2>
    <h2 v-pre>{{message}}</h2>
</div>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            message: '你好啊'
        }
    })
</script>
2.5 v-cloak指令

可以解決插值閃爍的問題

<!--  當有v-cloak屬性時就執行該樣式 --> 
<style>
    [v-cloak] {
        display:none;
    }
</style>
<div id="app" v-cloak>
    <h2>{{message}}</h2>
    <h2 v-pre>{{message}}</h2>
</div>
<script>
    //在vue解析之前,div中有一個屬性v-cloak
    //在vue解析之後,div中的該v-cloak屬性會被刪除
    const app = new Vue({
        el: '#app',
        data: {
            message: '你好啊'
        }
    })
</script>

3. 事件繫結

3.1 v-on指令

作用

為元素繫結事件

用法

事件名不需要寫on

v-on: 指令可以簡寫為 @

繫結的方法定義在methods屬性中

方法內部通過this關鍵字可以訪問定義在data中資料

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HelloVue</title>
    <!-- 開發環境版本,包含了有幫助的命令列警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        window.onload = function(){
            var app = new Vue({
                el: '#app',
                data: {
                    food:"西紅柿操蛋"
                }, 
                methods:{
                    doIt:function(){
                        alert("我被點選了!!");
                    },
                    //changeFood:function(){
                    //        this.food += "還行吧!";
                    //}
                    //注意:函式也可以寫簡化形式
                    changeFood(){
                        this.food += "還行吧!";
                    }
                }      
            })
        }
    </script>
</head>
<body>
    <div id="app">
        <!-- <button v-on:click="doIt">點選事件</button> -->
        <button @click="doIt">點選事件</button>
        <button @dblclick="doIt">雙擊事件</button>
        <h2 @click="changeFood">{{ food }}</h2>
    </div>
</body>
</html>
3.2 事件引數

事件繫結的方法寫成函式呼叫的形式,可以傳入自定義引數。定義方法時需要定義形參來接收傳入的實參。

如果該方法不需要額外引數,那麼方法後的()可以不新增。

注意:

① 如果方法本身有一個引數且我們沒有新增(),那麼會預設將原生事件event引數傳遞進去

② 如果方法本身有一個引數且我們添加了()但沒有傳入實參,那麼該引數為undefined

如果在傳入某個自定義引數的時候同時需要傳入 event 時,可以通過 $event 作為實參傳入事件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HelloVue</title>
    <!-- 開發環境版本,包含了有幫助的命令列警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        window.onload = function(){
            var app = new Vue({
                el: '#app',
                data: {
                    
                }, 
                methods:{
                    //新增自定義引數
                    doIt:function(p1,p2){
                        alert(p2 + "雙擊" + p1);
                    },
                    sayHi:function(){
                        alert("Hello!")
                    }
                }      
            })
        }
    </script>   
</head>
<body>
    <div id="app" >
        <button @click="doIt(666,'老鐵')">點選</button>
        <!-- 事件修飾符:如點選enter鍵才觸發-->
        <input type="text" @keyup.enter="sayHi">
    </div>
</body>
</html>
3.3 事件修飾符

事件的後面跟上 .事件修飾符 可以對事件進行限制

事件修飾符有多種...

  • .stop 阻止事件冒泡
<div id="app" >
   <div class="box" @click="divClick">
       <!-- 阻止事件冒泡-->
       <input type="button" value="按鈕" @click.stop="btnClick">
   </div>
</div>
  • .prevent 阻止標籤的預設行為
<div id="app" >
    <!-- 阻止事件的預設行為,如此例點選後不會跳轉到百度-->
    <a href="http://www.baidu.com" @click.prevent="aClick">百度</a>
     <!-- 注意:事件修飾符是可以連點的-->
     <a href="http://www.baidu.com" @click.prevent.stop="aClick">百度</a>
</div>
  • .capture
  • .self 針對於當前標籤的事件觸發,即只觸發自己標籤上特定動作的事件
<div id="app" >
    <!-- self:只觸發自己標籤上特定動作的事件,如此例忽略子元素的事件冒泡-->
    <div @click.self="divClick">
        <input type="button" value="按鈕" @click="btnClick">
        <input type="button" value="按鈕1" @click="btnClick1">
        <input type="button" value="按鈕2" @click="btnClick2">
    </div>
</div>
  • .once 讓指定的事件只觸發一次
  • .passive
3.4 按鍵修飾符

事件的後面跟上 .按鍵修飾符 可以對事件進行限制
按鍵修飾符有多種...

  • .enter

  • .tab

  • .delete

  • .esc

  • .space

    ...

3.5 案例:計數器
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HelloVue</title>
    <!-- 開發環境版本,包含了有幫助的命令列警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        window.onload = function(){
            var app = new Vue({
                el: '#app',
                data: {
                    num:1
                }, 
                methods:{
                    //遞增
                    add:function(){
                        if(this.num >= 10) {
                            alert("數量不能大於10");
                        } else{
                            this.num++;
                        }
                    },
                    //遞減
                    sub:function(){
                        if(this.num <= 0) {
                            alert("數量不能小於0");
                        } else {
                            this.num--;
                        }
                    }
                }      
            })
        }
    </script>
</head>
<body>
    <div id="app" >
        <div class="input-num">
            <button @click="sub">-</button>
            <span>{{num}}</span>
            <button @click="add">+</button>
        </div>
    </div>
</body>
</html>

4. 顯示切換

4.1 v-show指令

作用

切換元素的顯示狀態

原理

修改元素的display 屬性,實現顯示隱藏

指令後面的內容最終都會解析為布林值,值為true元素顯示,值為false元素隱藏

資料改變之後,對應元素的顯示狀態會同步更新

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HelloVue</title>
    <!-- 開發環境版本,包含了有幫助的命令列警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        window.onload = function(){
            var app = new Vue({
                el: '#app',
                data: {
                    isShow:false
                }, 
                methods:{
                   changeIsShow:function(){
                       this.isShow = !this.isShow;
                   }
                }      
            })
        }
    </script>
</head>
<body>
    <div id="app" >
        <button  @click="changeIsShow">切換</button>
        <img src="image/草莓.png" v-show="isShow">
    </div>
</body>
</html>
4.2 v-if指令

作用

根據表示式的真假切換元素的顯示狀態

本質

通過操縱dom元素來切換顯示狀態

表示式的值為true則元素存在於dom樹中,為false則從dom樹中移除

頻繁的切換建議使用v-show,切換消耗小。反之使用v-if

<div id="app" >
   <button  @click="changeIsShow">切換</button>
   <img src="image/草莓.png" v-if="isShow">
</div>
4.3 v-else-if,v-else 指令
<div id="app">
    <h2 v-if="score >= 90">優秀</h2>
    <h2 v-else-if="score >= 60">良好</h2>
    <h2 v-else>不及格</h2>
</div>

<script>
    const app = new Vue({
        el: '#app',
        data: {
            score:40
        }
    })  
</script>
4.4 案例 - 點選切換

引入vue中key屬性的使用

實現點選按鈕切換input框的效果

<div id="app">
    <span v-if="isUser">
        使用者賬號: <input type="text" placeholder="使用者賬號">
    </span>
    <span v-else>
        使用者郵箱: <input type="text" placeholder="使用者密碼">
    </span>
    <button @click="isUser = !isUser">切換型別</button>
</div>

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

發現問題

如果我們有輸入內容的情況下切換了型別,我們會發現文字依然顯示之前輸入的內容。但是按道理講我們應該切換到另一個input元素中了,而在另一個input元素中我們並沒有輸入內容,為什麼會出現這個問題呢?

解答

這是因為Vue在進行DOM渲染時出於效能考慮,會盡可能的複用已經存在的元素,而不是重新建立新的元素。在上面的案例中,Vue內部發現原來的input元素不再使用就直接用來作為else中的input來使用了。

如果我們不希望如此呢?

我們可以給對應的input新增key屬性且保證key屬性的不同,則不同key屬性值的兩個元素是不會複用的。

5. 屬性繫結

5.1 v-bind指令

作用

為元素繫結屬性

使用

完整寫法是 v-bind:屬性名

簡寫的話可以直接省略 v-bind,只保留 :屬性名

需要動態的增刪 class選擇器 建議使用物件的方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HelloVue</title>
    <!-- 開發環境版本,包含了有幫助的命令列警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        window.onload = function(){
            var app = new Vue({
                el: '#app',
                data: {
                    imgSrc:"image/冷飲.jpg",
                    imgTitle:"冷飲",
                    isActive:false
                }, 
                methods:{
                   toggleActive:function(){
                       this.isActive = !this.isActive;
                   }
                }      
            })
        }
    </script>
    <style>
        .active{
            border:2px solid red;
        }
    </style>
</head>
<body>
    <div id="app" >
        <!-- <img v-bind:src="imgSrc"> -->
        <img :src="imgSrc" :title="imgTitle + '!'" 
            :class="isActive?'active':''" @click="toggleActive">
            
        <!-- :class中使用物件的形式:active這個類名是否生效取決於isActive的值-->
        <img :src="imgSrc" :title="imgTitle + '!'" 
            :class="{active:isActive}" @click="toggleActive">
            
         <!-- 和普通的類選擇器同時存在並不衝突。
             可以傳入多個值,可以同時生效 -->
        <img class="gg" :class="{active:isActive,line:isLine}" 
            @click="toggleActive">  
            
        <!-- 可以放陣列的形式 -->
        <img :class="['active','line']"> 
        <img :class="[active,line]"> 
       
        <!-- 如果過於複雜,可以放在一個methods或computed中 -->
        <img :class="classes">
        
        <!-- 注意:50px必須加單引號,否則會被當成物件,之後解析後會去掉的
                   font-size和fontSize都可以被識別 -->
        <h2 :style="{fontSize: '50px'}">{{message}}</h2>
    </div>
</body>
</html>
5.2 案例:圖片切換

列表資料使用陣列儲存

v-bind 指令可以設定元素屬性,比如src

v-showv-if 都可以切換元素的顯示狀態,頻繁切換用 v-show

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HelloVue</title>
    <!-- 開發環境版本,包含了有幫助的命令列警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        window.onload = function(){
            var app = new Vue({
                el: '#app',
                data: {
                    imgArr:["image/bar1.jpg","image/bar2.jpg",
                            "image/bar3.jpg","image/bar4.jpg"],
                    index:0
                }, 
                methods:{
                    prev:function(){
                        this.index--;
                    },
                    next:function(){
                        this.index++;
                    }
                }      
            })
        }
    </script>
    <style>
        .bar{
            margin-top: 80px;
            margin-left: 150px;
            position: relative;
            width: 1200px;
            height: 600px;
            border:4px solid gray;
        }
        a{
            cursor: pointer;
            position:absolute;  
            top:270px;
            display: block;
            width:65px;
            height: 40px;
            line-height: 30px;
            border: 1px solid white;
            text-align: center;
            font-size: 30px;
            
        }
        .leftA{left: 0px;}
        .rightA{right: 0px;}
        img{
            width: 1200px;
            height: 600px;
        }
    </style>
</head>
<body>
    <div id="app" >
        <div class="bar">
            <a class="leftA" @click="prev" v-show="index!=0">