天天看點

《分布式微服務電商》專題(十一)-電商項目前端Vue進階

文章目錄

  • ​​1.計算屬性computed​​
  • ​​2.監聽watch​​
  • ​​3.過濾器filter​​
  • ​​4.表單、複選框​​
  • ​​4.1. 多選checkbox​​
  • ​​4.2. 單選radio​​
  • ​​4.3.下拉select​​
  • ​​5.修飾符​​
  • ​​6.元件化​​
  • ​​7.生命周期鈎子函數​​

1.計算屬性computed

什麼是計算屬性:屬性不是具體值,而是通過一個函數計算出來的,随時變化

<!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="app">
        <p>原始字元串: {{ message }}</p>
        <p>計算後反轉字元串: {{ reversedMessage }}</p>
        <p>計算後反轉字元串: {{ reversedMessage2() }}</p>
    </div>

    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                message: 'Runoob!'
            },
            computed: {
                // 計算屬性的 getter
                reversedMessage: function () {
                    // `this` 指向 vm 執行個體
                    return this.message.split('').reverse().join('')
                }
            },
            methods: {
                reversedMessage2: function () {
                    return this.message.split('').reverse().join('')
                }
            }
        })
    </script>

</body>

</html>      

這裡可以比較一下計算和method之間的差別

<!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="div">
        <p>{{message}}</p>
        <button id="btn" v-on:click="change">點選翻譯成中文</button>
    </div>

    <script src="./node_modules/vue/dist/vue.js"></script>

    <!--引入vue js 外部檔案-->
    <script> //vue js 代碼寫在這裡

        var a = new Vue({
            el: "#div",
            data: { message: "good good study" },
            methods: {
                change: function () {
                    alert("測試");
                    this.message = "天天向上"
                }
            }
        });

    </script>

</body>

</html>      
<!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="div">
        <input v-model="firstName">
        <input v-model="lastName">
        <br />
        <p>{{fullName}}</p>
    </div>

    <body>
        <script src="./node_modules/vue/dist/vue.js"></script>
        <script>
            var vm = new Vue({
                el: '#div',
                data: {
                    firstName: 'zheng',
                    lastName: 'zeling'
                },
                computed: {
                    fullName: function () {
                        return this.firstName + ' ' + this.lastName
                    }
                }
            })
        </script>

</html>      

因為 input 框使用了 v-model 雙向綁定了 firstName 這個資料值,是以當修改輸入框内容時,firstName 也跟随變化;而又因為 computed 計算屬性 fullName 的傳回值依賴于 firstName,是以一旦 firstName 發生變化,fullName 馬上被觸發

computed (計算屬性) 和 methods (方法) 的差別:

我們可以将同一函數定義為一個方法而不是一個計算屬性。兩種方式的最終結果确實是完全相同的。然而,不同的是計算屬性是基于它們的依賴進行緩存的。隻在相關依賴發生改變時它們才會重新求值。這就意味着隻要 message 還沒有發生改變,多次通路 reversedMessage 計算屬性會立即傳回之前的計算結果,而不必再次執行函數。

也就是說:

函數執行需要 資料屬性裡面的 message 值作為參數。

● 如果使用 methods 執行函數,vue 每次都要重新執行一次函數,不管message 的值是否有變化;

● 如果使用computed 執行函數,隻有當message 這個最初的資料發生變化時,函數才會被執行。(依賴-監測資料變化)

2.監聽watch

監聽屬性 watch,我們可以通過 watch 來響應資料的變化。

以下執行個體通過使用 watch 實作計數器:

<!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="app">
        <p style="font-size:25px;">計數器: {{ counter }}</p>
        <button @click="counter++" style="font-size:25px;">點我</button>
    </div>
    
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el: '#app',
            data: {
                counter: 1
            }
        });
        vm.$watch('counter', function (nval, oval) { // new old
            alert('計數器值的變化 :' + oval + ' 變為 ' + nval + '!');
        });
    </script>
</body>
</html>      
<!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="app">
        <!-- 某些結果是基于之前資料實時計算出來的,我們可以利用計算屬性。來完成 -->
        <ul>
            <li>西遊記; 價格:{{xyjPrice}},數量:<input type="number" v-model="xyjNum"> </li>
            <li>水浒傳; 價格:{{shzPrice}},數量:<input type="number" v-model="shzNum"> </li>
            <li>總價:{{totalPrice}}</li>
            {{msg}}
        </ul>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>

    <script>
        //watch可以讓我們監控一個值的變化。進而做出相應的反應。
        new Vue({
            el: "#app",
            data: {
                xyjPrice: 99.98,
                shzPrice: 98.00,
                xyjNum: 1,
                shzNum: 1,
                msg: ""
            },
            computed: {
                totalPrice(){
                    return this.xyjPrice*this.xyjNum + this.shzPrice*this.shzNum
                }
            },
            watch: {
                xyjNum: function(newVal,oldVal){
                    if(newVal>=3){
                        this.msg = "庫存超出限制";
                        this.xyjNum = 3
                    }else{
                        this.msg = "";
                    }
                }
            },
        })
    </script>

</body>
</html>      

3.過濾器filter

定義filter元件後,管道符後面跟具體過濾器{{​

​user.gender​

​​ | ​

​gFilter​

​}}

<!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>
    <!-- 過濾器常用來處理文本格式化的操作。過濾器可以用在兩個地方:雙花括号插值和 v-bind 表達式 -->
    <div id="app">
        <ul>
            <li v-for="user in userList">
                {{user.id}} ==> {{user.name}} ==> {{user.gender == 1?"男":"女"}} ==>
                {{user.gender | genderFilter}} ==> {{user.gender | gFilter}}
            </li>
        </ul>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>

    <script>

        // 全局過濾器
        Vue.filter("gFilter", function (val) {
            if (val == 1) {
                return "男~~~";
            } else {
                return "女~~~";
            }
        })

        let vm = new Vue({
            el: "#app",
            data: {
                userList: [
                    { id: 1, name: 'jacky', gender: 1 },
                    { id: 2, name: 'peter', gender: 0 }
                ]
            },
            filters: { // 局部過濾器,隻可以在目前vue執行個體中使用
                genderFilter(val) {
                    if (val == 1) {
                        return "男";
                    } else {
                        return "女";
                    }
                }
            }
        })
    </script>
</body>

</html>      

4.表單、複選框

​​https://www.runoob.com/vue2/vue-forms.html​​

4.1. 多選checkbox

雖然v-model指定了同個值,但是會收內建數組。示範:​​https://www.runoob.com/try/try.php?filename=vue2-form2​​

<!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="app">
            <p>單個複選框:</p>
            <input type="checkbox" id="checkbox" v-model="checked">
            <label for="checkbox">{{ checked }}</label>

            <p>多個複選框:</p>
            <input type="checkbox" id="runoob" value="Runoob" v-model="checkedNames">
            <label for="runoob">Runoob</label>
            <input type="checkbox" id="google" value="Google" v-model="checkedNames">
            <label for="google">Google</label>
            <input type="checkbox" id="taobao" value="Taobao" v-model="checkedNames">
            <label for="taobao">taobao</label>
            <br>
            <span>選擇的值為: {{ checkedNames }}</span>
        </div>
        <script src="./node_modules/vue/dist/vue.js"></script>
        <script>
            new Vue({
                el: '#app',
                data: {
                    checked : false,
                    checkedNames: []
                }
            })
        </script>
    </body>
</html>      

4.2. 單選radio

<!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="app">
        <input type="radio" id="runoob" value="Runoob" v-model="picked">
        <label for="runoob">Runoob</label>
        <br>
        <input type="radio" id="google" value="Google" v-model="picked">
        <label for="google">Google</label>
        <br>
        <span>選中值為: {{ picked }}</span>
    </div>
    
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                picked: 'Runoob'
            }
        })
    </script>

</body>

</html>      

4.3.下拉select

<!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="app">
        <select v-model="selected" name="fruit">
            <option value="">選擇一個網站</option>
            <option value="www.runoob.com">Runoob</option>
            <option value="www.google.com">Google</option>
        </select>
    
        <div id="output">
            選擇的網站是: {{selected}}
        </div>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                selected: '' 
            }
        })
    </script>    
</body>
</html>      

5.修飾符

.lazy

在預設情況下, v-model 在 input 事件中同步輸入框的值與資料,但你可以添加一個修飾符 lazy ,進而轉變為在 change 事件中同步:

<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg" >      

.number

如果想自動将使用者的輸入值轉為 Number 類型(如果原值的轉換結果為 NaN 則傳回原值),可以添加一個修飾符 number 給 v-model 來處理輸入值:

<input v-model.number="age" type="number">      

這通常很有用,因為在 type=“number” 時 HTML 中輸入的值也總是會傳回字元串類型。

.trim

如果要自動過濾使用者輸入的首尾空格,可以添加 trim 修飾符到 v-model 上過濾輸入:

<input v-model.trim="msg">      
<!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=app>
        <!-- 在 "change" 而不是 "input" 事件中更新 -->
        <input v-model.lazy="msg">
        {{msg}}


        <input v-model="age" type="number">
        {{age}}

        <input v-model.trim="msg">

        {{msg}}

    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
        let vm=new Vue({
            el: "#app",
            data: {
                age: 100,
                msg: "hello"
            }
        });
    </script>
</body>

</html>      

6.元件化

在大型應用開發的時候,頁面可以劃分成很多部分。往往不同的頁面,也會有相同的部分。例如可能會有相同的頭部導航。

但是如果每個頁面都自開發,這無疑增加了我們開發的成本。是以我們會把頁面的不同分拆分成立的元件,然後在不同頁面就可以共享這些元件,避免重複開發。

在vue裡,所有的vue執行個體都是元件

  • 元件其實也是一個vue執行個體,是以它在定義時也會接收:data、methods、生命周期函數等
  • 不同的是元件不會與頁面的元素綁定(是以不寫el),否則就無法複用了,是以沒有el屬性。
  • 但是元件渲染需要html模闆,是以增加了template屬性,值就是HTML模闆
  • data必須是一個函數,不再是一個對象。
  • 全局元件定義完畢,任何vue執行個體都可以直接在HTML中通過元件名稱來使用元件了

下面的html内容是在說:

  • ​<div id="app">​

    ​​這個塊跟下面的​

    ​new Vue​

    ​對象綁定
  • vue對象裡指定了​

    ​components​

    ​​屬性,是指:标簽裡有子标簽,’​

    ​button-counter​

    ​​’:​

    ​buttonCounter​

    ​​代表有個元件叫​

    ​buttonCounter​

    ​​,可以填充标簽​

    ​<button-counter>​

Vue元件的使用

參考:

​​​https://cn.vuejs.org/v2/guide/components.html​​​​https://www.runoob.com/vue2/vue-component.html​​

  1. 全局元件

    參考:​​​https://cn.vuejs.org/v2/guide/components-registration.html​​

<!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="app">
        <button v-on:click="count++">我被點選了 {{count}} 次</button>
        <counter></counter>
        <counter></counter>
        <counter></counter>
        <counter></counter>
        <counter></counter>
        <hr/>
        
    </div>

    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
        // 定義一個名為 button-counter 的新元件
        //1、全局聲明注冊一個元件
        Vue.component('counter', {
            data: function () { // data是函數
                return {
                    count: 0
                }
            },
            template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>' // 渲染的模闆
        });


        new Vue({
            el: "#app",
            data: {
                count: 1
            }
        });
    </script>

</body>

</html>      

局注冊的元件可以用在其被注冊之後的任何 (通過 ​

​new Vue​

​​) 新建立的 ​

​Vue​

​ 根執行個體,也包括其元件樹中的所有子元件的模闆中。

這裡還應該注解的是data那個屬性,在元件中需要以函數的方式寫\
<!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="app">
        <button v-on:click="count++">我被點選了 {{count}} 次</button>
        <counter></counter>
        <counter></counter>
        <counter></counter>
        <counter></counter>
        <counter></counter>
        <hr/>

        <button-counter></button-counter>
        
    </div>

    

    

    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
        // 定義一個名為 button-counter 的新元件
        //1、全局聲明注冊一個元件
        Vue.component('counter', {
            data: function () { // data是函數
                return {
                    count: 0
                }
            },
            template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>' // 渲染的模闆
        });

        //2、局部聲明一個元件
        const buttonCounter = {
            template: `<button v-on:click="count++">我被點選了 {{count}} 次~~~</button>`,
            data() {
                return {
                    count: 1
                }
            }
        };

        new Vue({
            el: "#app",
            data: {
                count: 1
            },components: {
                'button-counter': buttonCounter
            }
        });
    </script>

</body>

</html>      

7.生命周期鈎子函數

<!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="app">
        <span id="num">{{num}}</span>
        <button @click="num++">贊!</button>
        <h2>{{name}},有{{num}}個人點贊</h2>
    </div>

    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>
        let app = new Vue({
            el: "#app",
            data: {
                name: "張三",
                num: 100
            },
            methods: {
                show() {
                    return this.name;
                },
                add() {
                    this.num++;
                }
            },
            beforeCreate() {
                console.log("=========beforeCreate=============");
                console.log("資料模型未加載:" + this.name, this.num);
                console.log("方法未加載:" + this.show());
                console.log("html模闆未加載:" + document.getElementById("num"));
            },
            created: function () {
                console.log("=========created=============");
                console.log("資料模型已加載:" + this.name, this.num);
                console.log("方法已加載:" + this.show());
                console.log("html模闆已加載:" + document.getElementById("num"));
                console.log("html模闆未渲染:" + document.getElementById("num").innerText);
            },
            beforeMount() {
                console.log("=========beforeMount=============");
                console.log("html模闆未渲染:" + document.getElementById("num").innerText);
            },
            mounted() {
                console.log("=========mounted=============");
                console.log("html模闆已渲染:" + document.getElementById("num").innerText);
            },
            beforeUpdate() {
                console.log("=========beforeUpdate=============");
                console.log("資料模型已更新:" + this.num);
                console.log("html模闆未更新:" + document.getElementById("num").innerText);
            },
            updated() {
                console.log("=========updated=============");
                console.log("資料模型已更新:" + this.num);
                console.log("html模闆已更新:" + document.getElementById("num").innerText);
            }
        });
    </script>
</body>

</html>