Vue.js入門 - 3

by vivid 12. 六月 2019 09:52

.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號:N190620801
出刊日期: 2019/6/12

在本站《Vue.js入門 - 1》、《Vue.js入門 - 2》系列文章中,介紹了Vue.js開發環境安裝與設定,以及基本的資料繫結語法、如何設計單一元件檔以達共用,本文將延續前文的介紹,說明計算屬性(Computed property)與條件式生成標籤的「v-if」指示詞用法。

 

什麼是計算屬性(Computed property)?

在樣板(Template)之中的運算式(Expression)通常不建議放太多、太複雜的計算邏輯,如此將會讓樣板變的過於複雜化,難以維護與管理。計算屬性(Computed property)便因應此問題而產生。那麼什麼時後要設計成資料(data)什麼時候要設計成計算屬性呢? 基本上有幾個簡單的原則可以判別,若要存放常數值,那麼應該設計成資料(data);若想儲存的值相依於其它值,會根據其它的資料而變動,那麼應該設計成計算屬性(Computed property)。若需要一些額外的運算才能得到值,那麼也應該設計成計算屬性(Computed property

參考以下範例程式碼,我們想要把使用者的姓氏(lastName)和名稱(firstName)串接成字串,以逗號做區隔來顯示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title> Document </title>
</head>
<body>
    <div id="divMsg">
        <h1> First Name : {{ firstName }} </h1>
        <h1> Last Name : {{ lastName }} </h1>
        <h1> Full Name : {{ lastName + ' , ' + firstName }} </h1>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>

    <script>
        var vm = new Vue({
            el: '#divMsg',
            data: {
                firstName: 'Mary',
                lastName: 'Lee'
            }
        });
    </script>
</body>
</html>

 

樣板之中,不僅包含標籤,還包含了計算的邏輯,當程式碼愈來愈複雜,樣板的程式碼就會更加複雜,這個範例程式的執行結果請參考下圖所示:

clip_image002

圖 1:測試範例執行結果。

我們將此範例改寫成改用計算屬性的方式來做串接動作,參考以下範例程式碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title> Document< /title>
</head>
<body>
    <div id="divMsg">
        <h1> First Name : {{ firstName }} </h1>
        <h1> Last Name : {{ lastName }} </h1>
        <h1> Full Name : {{ fullName }} </h1>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>

    <script>
        var vm = new Vue({
            el: '#divMsg',
            data: {
                firstName: 'Mary',
                lastName: 'Lee'
            },
            computed: {
                fullName: function () {
                    return this.firstName + ', ' + this.lastName;
                }

            }
        });
    </script>
</body>
</html>

我們在「computed」區塊中,宣告一個計算屬性:(fullName),計算屬性是一個函式,我們利用這個屬性來做串接字串的動作。和上面的範例相比之下,使用計算屬性的話,設計則樣板中的程式碼就會顯得比較簡潔一些。若我們開啟瀏覽器除錯視窗,直接修改「firstName」或「lastName」變數的值,那麼「fullName」計算屬性便會直接反應顯示最新的字串串接結果,「fullName」計算屬性的值永遠會與「firstName」、「lastName」的值相依,這個範例程式的執行結果參考如下:

clip_image004

圖 2:計算屬性(Computed property)範例執行結果。

計算屬性(Computed property)的Getter與Setter函式

若想要手動修改或讀取計算屬性的值,Vue可以讓你為計算屬性設計「Getter」與「Setter」函式來讀取、寫入它的值。參考以下範例程式碼:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title> Document </title>
</head>

<body>
    <div id="divMsg">
        <h1> First Name : {{ firstName }} </h1>
        <h1> Last Name : {{ lastName }} </h1>
        <h1> Full Name : {{ fullName }} </h1>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>

    <script>
        var vm = new Vue({
            el: '#divMsg',
            data: {
                firstName: 'Mary',
                lastName: 'Lee'
            },
            computed: {
                fullName: {
                    get: function () {
                        return this.firstName + ' , ' + this.lastName;
                    },
                    set: function (newvalue) {
                        this.firstName = newvalue.split(',')[0].trim();
                        this.lastName = newvalue.split(',')[1].trim();
                    }
                }
            }
        });
        console.log(vm.fullName);  //Mary, Lee
        vm.fullName = 'Lora, Chung';
        console.log(vm.fullName); //Lora,  Chung
        console.log(vm.firstName); //Lora
        console.log(vm.lastName); //Chung
    </script>
</body>

</html>

 

「Getter」是一個名稱為「get」的函式,負責處理字串串接邏輯;「Setter」是一個名稱為「set」的函式,負責處理將按逗號串接的字串拆解出來。當你的程式中使用到「vm.fullName」這個屬性時,便會叫用「Getter」函式做名稱字串串接動作;當你使用到「vm.fullName = 'Lora, Chung'」程式碼時,便叫用「Setter」函式修改「firstName」與「lastName」變數的值。這個範例程式的執行結果請參考下圖所示:

clip_image006

圖 3:計算屬性範例執行結果。

計算屬性(Computed property)與資料繫結

計算屬性也支援雙向資料繫結,只要透過「v-model」關聯到計算屬性即可,例如參考以下範例程式碼,文字方塊關聯到了「fullName」計算屬性:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title> Document </title>
</head>

<body>
    <div id="divMsg">
        <h1> First Name : {{ firstName }} </h1>
        <h1> Last Name : {{ lastName }} </h1>
        <input type="text" v-model="fullName" />
        <h1> Full Name : {{ fullName }} </h1>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>

    <script>
        var vm = new Vue({
            el: '#divMsg',
            data: {
                firstName: 'Mary',
                lastName: 'Lee'
            },
            computed: {
                fullName: {
                    get: function () {
                        return this.firstName + ' , ' + this.lastName;
                    },
                    set: function (newvalue) {
                        this.firstName = newvalue.split(',')[0].trim();
                        this.lastName = newvalue.split(',')[1].trim();
                    }
                }
            }
        });
        console.log(vm.fullName);  //Mary, Lee
        vm.fullName = 'Lora, Chung';
        console.log(vm.fullName); //Lora,  Chung
        console.log(vm.firstName); //Lora
        console.log(vm.lastName); //Chung
    </script>
</body>

</html>

只要文字方塊中名稱有變動時,都會自動更新顯示最新的姓氏與名稱,這個範例程式的執行結果參考如下:

clip_image008

圖 4:計算屬性之雙向繫結執行結果。

監看(Watcher)選項

大部分的情況下,使用計算屬性就可以滿足需求,若要搭配一些更為複雜的運算,或是做非同步處理來更新要顯示的資料,那麼監看(Watcher)選項則是更好的選擇。參考以下範例程式碼,在「watch」區段中定義一個「email」屬性,而此屬性透過「v-model」關聯到文字方塊:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title> Document </title>
</head>

<body>
    <div id="divMsg">
        <h1> Email : </h1>
      <input type="text" name="email" id="email"  v-model='email'>
      <h1> {{ info }} </h1>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>

    <script>
        var vm = new Vue({
            el: '#divMsg',
            data: {
                email: '',
                info: ''
            },
            watch: {
                email: function (value) {
                    if (this.validate(value)) {
                        this.info ='Email is valid ';
                     }else{
                        this.info ='Email is invalid ';  
                     }
                }
            },
            methods:{
                validate : function (value) {
                    return /^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/.test(value);
                }
            }
        });
     
    </script>
</body>

</html>

當使用者在文字方塊填寫電子郵件資料時,我們可以立即回報使用者輸入的資料是否符合正確的電子郵件格式。因為文字方塊繫結到了「email」,若文字方塊的內容變動,「email」的值也會馬上變更,我們便利用「validate」函式搭配規則運算式,來檢查使用者輸入的資料是否符合正確的電子郵件格式,當資料格式錯誤,便顯示錯誤訊息,請參考下圖所示:

clip_image010

圖 5:使用Wather監看資料執行結果。

若文字方塊中輸入的資料符合電子郵件格式,將顯示以下訊息:

clip_image012

圖 6:使用Wather監看資料執行結果。

使用「v-if」指示詞

樣板裏頭可以使用許多Vue.js內建的指示詞(Directive)根據特殊情況來產生標籤,例如,「v-if」指示詞可以在某個條件成立的情況下,動態產生HTML項目,並插入DOM物件之中,以根據特定狀況動態決定使用者可以檢視的內容。Vue.js還內建一個跟「v-if」指示詞很類似的「v-show」指示詞,兩者的最大差別是,「v-show」指示詞會產生所有HTML項目,並將之插入DOM,再利用CSS的「display」屬性來顯示、隱藏項目。我們來看一下這些指示詞的用法,第一個要介紹的指示詞便是「v-if」。

「v-if」指示詞會在條件式運算的結果為「true」的情況下,顯示HTML項目(Element);在條件式運算的結果為「false」的情況下,不產生HTML項目(Element),參考以下範例程式碼:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title> Document </title>
</head>

<body>
    <div id="divMsg">
        <h1 v-if="hour<12"> 早安 </h1>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>

    <script>
        var vm = new Vue({
            el: '#divMsg',
            data: {
                hour: (new Date()).getHours()
            }
        });

    </script>
</body>

</html>

 

「v-if」指示詞後的條件式可以搭配運算式、計算屬性或函式來使用。這個範例程式的執行結果請參考下圖所示,若條件成立,將顯示「早安」訊息,我們從瀏覽器除錯工具檢視DOM物件,可以看到<h1> 項目:

clip_image014

圖 7:「v-if」指示詞範例執行結果。

若條件不成立,則不產生<h1>項目,請參考下圖所示:

clip_image016

圖 8:「v-if」指示詞範例執行結果。

使用「v-show」指示詞

我們將上述範例的「v-if」指示詞的範例改成「v-show」指示詞試看看執行的結果,參考以下範例程式碼:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title> Document </title>
</head>

<body>
    <div id="divMsg">
        <h1 v-show="hour<12"> 早安 </h1>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>

    <script>
        var vm = new Vue({
            el: '#divMsg',
            data: {
                hour: (new Date()).getHours()
            }
        });

    </script>
</body>

</html>

 

這個範例程式的執行結果請參考下圖所示,若條件不成立,將不會顯示「早安」訊息,我們從瀏覽器除錯工具檢視DOM物件,可以看到<h1> 項目被加上「display : none」樣式:

clip_image018

圖 9:「v-show」指示詞範例執行結果。

使用「v-else」指示詞

若條件成立要產生HTML項目可以使用「v-if」,若條件不成立要產生HTML項目,可以在「v-if」指示詞之後搭配「v-else」指示詞。參考以下範例程式碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title> Document </title>
</head>
<body>
    <div id="divMsg">
        <h1 v-if="hour<12"> 早安 </h1>
        <h1 v-else> 午安 </h1>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#divMsg',
            data: {
                hour: (new Date()).getHours()
            }
        });
    </script>
</body>
</html>

 

和「v-if」指示詞相同的是,在「v-if」條件成立時,「v-else」不會產生對應的HTML項目;在「v-if」條件不成立時,「v-else」才會產生對應的HTML項目。

「v-else」指示詞通常不會單獨使用,要搭配「v-if」指示詞使用,並且在定義時要緊接著「v-if」指示詞之後出現。若樣板中「v-else」要使用多個HTML項目,則可以使用容器標籤如<div>或<template>打包在一起參考以下範例程式碼:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title> Document </title>
</head>

<body>
    <div id="divMsg">
        <h1 v-if="hour<10"> 早安 </h1>
        <div v-else>
               <h1> 午安 </h1>
               <small>目前時間為: {{hour}} </small>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#divMsg',
            data: {
                hour: (new Date()).getHours()
            }
        });
    </script>
</body>

</html>

 

這個範例程式的執行結果參考如下圖:

clip_image020

圖 10:使用「v-else」指示詞。

再者要注意的是,「v-show」指示詞和「v-else」指示詞不能夠搭配在一起使用,若將上述範例變更如下,則運作的結果將會不如預期:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title> Document </title>
</head>
<body>
    <div id="divMsg">
        <h1 v-show="hour<12"> 早安 </h1>
        <h1 v-else> 午安 </h1>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#divMsg',
            data: {
                hour: (new Date()).getHours()
            }
        });
    </script>
</body>
</html>

Tags:

.NET Magazine國際中文電子雜誌 | JavaScript | 許薰尹Vivid Hsu

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List