第三節:Vue3向下兼容2(v-for、數組方法、v-model、計算屬性、監聽器)


一. 基本指令

 1. v-for

數據准備

    data() {
                    return {
                        userInfo: { name: 'ypf', age: 18, school: '北大' },
                        movies: ["星際穿越", "盜夢空間", "大話西游", "教父", ],
                        userList: [
                            { name: 'ypf1', age: 18, school: '北大1' },
                            { name: 'ypf2', age: 19, school: '北大2' },
                            { name: 'ypf3', age: 20, school: '北大3' }
                        ]
                    }
             }

(1). 遍歷對象

格式:

            <h4>1.遍歷對象</h4>
            <ul>
                <li v-for="(value,key,index) in userInfo" :key='index'>
                    {{index}}-{{key}}--{{value}}
                </li>
            </ul>

(2). 遍歷數字

格式: item in 數字

            <h4>2.遍歷數字</h4>
            <ul>
                <li v-for="value in 5">
                    {{value}}
                </li>
            </ul>

(3). 遍歷數組【重點】

格式:item in 數組

           (item, index) in 數組

A. 普通數組

            <h5>3.1 普通數組</h5>
            <ul>
                <li v-for="(item,index) in movies" :key='index'>{{index}}-{{item}}</li>
            </ul>

B. 數組對象

            <h5>3.2 數組對象</h5>
            <ul>
                <li v-for="(item,index) in userList" :key='index'>
                    {{index}}-{{item.name}}-{{item.age}}-{{item.school}}
                </li>
            </ul>

補充:

  我們發現,每個v-for,我們都賦值了一個key屬性,key屬性里的內容建議用唯一值,這里涉及到diff算法,提高效率,后面章節重點剖析。

2. 數組方法

(1).變異方法:

  背景:在 Vue 中,直接修改對象屬性的值無法觸發響應式。當你直接修改了對象屬性的值,你會發現,只有數據改了,但是頁面內容並沒有改變。所以:Vue中引入變異數組方法,即保持數組方法原有功能不變的前提下對其進行功能拓展,使其支持響應式。

常用方法:

  a. push: 往數組最后面添加一個元素,成功返回當前數組的長度。

  b. pop: 刪除數組的最后一個元素,成功返回刪除元素的值

  c. shift: 刪除數組的第一個元素,成功返回刪除元素的值

  d. unshift: 往數組最前面添加一個元素,成功返回當前數組的長度

  e. splice:  刪除,有三個參數,第一個要刪除元素的下標(必選),第二個要刪除元素的個數(必選),第三個刪除后想在原位置替換的值

  f. sort: 將數組按照字符編碼從小到大排序,成功返回排序后的數組

  g. reverse: 將數組倒序排列,並返回倒敘后的數組

(2).替換數組

  含義: 不會影響原始的數組數據,而是形成一個新的數組.

常用方法:

  a. filter: 創建一個新的數組,新數組中的元素是通過檢查指定數組中符合條件的所有元素。

  b. concat: 用於連接兩個或多個數組,該方法不會改變現有的數組。

  c. slice: 從已有的數組中返回選定的元素。該方法並不會修改數組,而是返回一個子數組

  eg:從第0個開始,獲取兩個元素 this.list = this.list.slice(0, 2);

案例參考:

  https://www.cnblogs.com/yaopengfei/p/12315704.html  底部的圖書管理代碼。 

 

二. v-model

1. 基本使用和原理

 v-model指令可以在表單 input、textarea以及select元素上創建雙向數據綁定;它會根據控件類型自動選取正確的方法來更新元素;盡管有些神奇,但 v-model 本質上不過是語法糖,它負責監聽用戶的輸入事件來更新數據,並在某種極端場景下進行一些特殊處理;

<body>
        <div id="app"></div>
        <template id="myApp">
            <div>
                <input v-model="msg" />
                <h5>等價於</h5>
                <!-- 等價於 -->
                <input :value="msg" @input="change1">
            </div>
        </template>

        <script src="../js/vue3.js" ></script>
        <script>
            Vue.createApp({
                template: '#myApp',
                data() {
                    return {
                        msg: 'Hello Vue3!'
                    }
                },
                methods:{
                    change1(event){
                        this.msg=event.target.value;
                    }
                }
            }).mount('#app');
        </script>
    </body>

剖析本質:v-model的原理其實是背后有兩個操作:

     (1). v-bind綁定value屬性的值;

     (2). v-on綁定input事件監聽到函數中,函數會獲取最新的值賦值到綁定的屬性中;

2. 綁定常用標簽

 v-model還可以綁定:textarea、checkbox、radio、select。

代碼分享:

    <body>
        <div id="app"></div>
        <template id="myApp">
            <!-- 1.綁定textarea -->
            <label for="intro">
                自我介紹
                <textarea name="intro" id="intro" cols="30" rows="10" v-model="intro"></textarea>
            </label>
            <h2>intro: {{intro}}</h2>

            <!-- 2.checkbox -->
            <!-- 2.1.單選框 -->
            <label for="agree">
                <input id="agree" type="checkbox" v-model="isAgree"> 同意協議
            </label>
            <h2>isAgree: {{isAgree}}</h2>

            <!-- 2.2.多選框 -->
            <span>你的愛好: </span>
            <label for="basketball">
                <input id="basketball" type="checkbox" v-model="hobbies" value="basketball"> 籃球
            </label>
            <label for="football">
                <input id="football" type="checkbox" v-model="hobbies" value="football"> 足球
            </label>
            <label for="tennis">
                <input id="tennis" type="checkbox" v-model="hobbies" value="tennis"> 網 球
            </label>
            <h2>hobbies: {{hobbies}}</h2>

            <!-- 3.radio -->
            <span>你的愛好: </span>
            <label for="male">
                <input id="male" type="radio" v-model="gender" value="male"></label>
            <label for="female">
                <input id="female" type="radio" v-model="gender" value="female"></label>
            <h2>gender: {{gender}}</h2>

            <!-- 4.select -->
            <span>喜歡的水果: </span>
            <select v-model="fruit" multiple size="2">
                <option value="apple">蘋果</option>
                <option value="orange">橘子</option>
                <option value="banana">香蕉</option>
            </select>
            <h2>fruit: {{fruit}}</h2>
        </template>

        <script src="../js/vue3.js"></script>
        <script>
            Vue.createApp({
                template: '#myApp',
                data() {
                    return {
                        intro: "Hello World",
                        isAgree: false,
                        hobbies: ["basketball", "football"],
                        gender: "",
                        fruit: "orange"
                    }
                }
            }).mount('#app');
        </script>
    </body>
View Code

3. 修飾符

 

lazy修飾符的作用:

 默認情況下,v-model在進行雙向綁定時,綁定的是input事件,那么會在每次內容輸入后就將最新的值和綁定的屬性進行同步;

 如果我們在v-model后跟上lazy修飾符,那么會將綁定的事件切換為 change 事件,只有在提交時(比如回車)才會觸發

number修飾符

代碼分享:

<body>
        <div id="app"></div>
        <template id="myApp">
            <!-- 1.lazy修飾符 敲擊回車才有效-->
            <input type="text" v-model.lazy="message">
            <br>
            <!-- 2.number修飾符 -->
            <input type="text" v-model.number="message">
            <h2>{{message}}</h2>
            <button @click="showType">查看類型</button>

            <!-- 3.trim修飾符 -->
            <input type="text" v-model.trim="message">
            <button @click="showResult">查看結果</button>
        </template>

        <script src="../js/vue3.js"></script>
        <script>
            Vue.createApp({
                template: '#myApp',
                data() {
                    return {
                        message: "Hello World"
                    }
                },
                methods: {
                    showType() {
                        console.log(this.message, typeof this.message);
                    },
                    showResult() {
                        console.log(this.message);
                    }
                }
            }).mount('#app');
        </script>
    </body>

 

 

三. 計算屬性computed

1. 什么時候用計算屬性?

 對於任何包含響應式數據的復雜邏輯,你都應該使用計算屬性;

 計算屬性看起來像是一個函數,但是我們在使用的時候不需要加(),這個后面講setter和getter時會講到;

2. 基本用法

<body>
        <div id="app"></div>
        <template id="myApp">
            <div> {{fullName}} </div>
            <div> {{finalResult}} </div>
        </template>
        <script src="../js/vue3.js"></script>
        <script>
            Vue.createApp({
                template: '#myApp',
                data() {
                    return {
                        firstName: 'BBB',
                        lastName: 'AAA',
                        message: "Hello Vue3"
                    }
                },
                computed: {
                    fullName() {
                        return this.lastName + ' ' + this.firstName;
                    },
                    finalResult() {
                        return this.message.split(' ').reverse().join(' ');
                    }
                }
            }).mount('#app');
        </script>
    </body>

3. get 和 set方法

 計算屬性在大多數情況下,只需要一個get方法即可,所以我們會將計算屬性直接寫成一個函數

    但是,如果我們確實想設置計算屬性的值呢?這個時候我們也可以給計算屬性設置一個set的方法

    <body>
        <div id="app"></div>
        <template id="myApp">
            <div> {{fullName1}} </div>
            <div> {{fullName2}} </div>
        </template>
        <script src="../js/vue3.js"></script>
        <script>
            Vue.createApp({
                template: '#myApp',
                data() {
                    return {
                        firstName: 'BBB',
                        lastName: 'AAA',
                    }
                },
                computed: {
                    // 相當於get方法
                    fullName1() {
                        return this.lastName + ' ' + this.firstName;
                    },
                    fullName2: {
                        get() {
                            return this.lastName + ' ' + this.firstName;
                        },
                        set(newValue) {
                            this.firstName = newValue + this.firstName;
                        }
                    }
                }
            }).mount('#app');
            
        </script>
    </body>
View Code

4. 計算屬性的緩存

 計算屬性computed是有緩存的,計算屬性會基於它們的依賴關系進行緩存;

 在數據不發生變化時,計算屬性是不需要重新計算的;但是如果依賴的數據發生變化,在使用時,計算屬性依然會重新進行計算

PS. 與method的本質區別:method每次調用都需要重新計算,沒有緩存。

代碼分享:

<body>
        <div id="app"></div>
        <template id="myApp">
            <!-- 1. 計算屬性調用-->
            <div>{{getFullName1()}}</div>
            <div>{{getFullName1()}}</div>
            <div>{{getFullName1()}}</div>
            <!-- 2. 方法調用 -->
            <div>{{getFullName2}}</div>
            <div>{{getFullName2}}</div>
            <div>{{getFullName2}}</div>
            <!-- 3.修改數據內容 -->
            <input type="text" v-model='firstName' />
        </template>

        <script src="../js/vue3.js"></script>
        <script>
            Vue.createApp({
                template: '#myApp',
                data() {
                    return {
                        firstName: 'BBB',
                        lastName: 'AAA'
                    }
                },
                methods: {
                    getFullName1() {
                        console.log('我是方法調用');
                        return this.lastName + ' ' + this.firstName;
                    }
                },
                computed:{
                    getFullName2(){
                        console.log('我是計算屬性調用');
                        return this.lastName + ' ' + this.firstName;
                    }
                }

            }).mount('#app');
        </script>
    </body>

運行結果:

 計算屬性只調用了1次,方法調用了三次。

 

   修改數據值,計算屬性再次被調用了1次,方法調用了3次。

 

 5. 擴展get和set的源碼

  詳見章節:https://www.cnblogs.com/yaopengfei/p/15251328.html

 

四. 監聽器

1. 什么是監聽器(偵聽器)?

 

 PS: 可以監聽data和computed中的數據。

2.  普通用法

    <body>
        <div id="app"></div>
        <template id="myApp">
            <h3>{{userInfo1.userName}}</h3>
            <div><button @click="Edit1">修改對象</button></div>
            <div><button @click="Edit2">修改userInfo1.userName</button></div>
        </template>
        <script src="../js/vue3.js"></script>
        <script>
            Vue.createApp({
                template: '#myApp',
                data() {
                    return {
                        userInfo1: { userName: 'test1', age: 20, },
                    }
                },
                watch: {
                    // 普通監聽
                    // 默認情況下我們的偵聽器只會針對監聽的數據本身的改變(內部發生的改變是不能偵聽)
                    userInfo1(newValue, oldValue) {
                        console.log(oldValue, newValue);
                    },
                },
                methods: {
                    Edit1() {
                        this.userInfo1 = { userName: 'test2' };
                    },
                    Edit2() {
                        this.userInfo1.userName = 'test2';
                    }
            }).mount('#app');
        </script>
    </body>

剖析:

 Edit1方法中直接修改了對象,則普通用法中能監聽到,但像Edit2中的修改對象中的內容,是監聽不到的!!!

3.  深度監聽 和 立即執行

(1). 深度監聽

 采用另一種寫法,並且需要配置 deep: true ,就可以監聽到對象內任何一個屬性的修改了。 

<body>
        <div id="app"></div>
        <template id="myApp">
            <h3>{{userInfo2.userName}}</h3>
            <div><button @click="Edit3">修改對象</button></div>
            <div><button @click="Edit4">修改userInfo2.userName</button></div>
            <div><button @click="Edit5">修改userInfo2.childInfo.cName</button></div>
        </template>

        <script src="../js/vue3.js"></script>
        <script>
            Vue.createApp({
                template: '#myApp',
                data() {
                    return {
                        userInfo2: { userName: 'test1', age: 20, childInfo: { cName: 'ypf' } },
                    }
                },
                watch: {// 深度監聽
                    // 內部發生的改變也偵聽到
                    // 發現一問題:新對象和舊對象中的userName值是相同的,這是因為引用類型賦值的問題,都是指向同一個內存地址(詳見后面的知識補充)
                    userInfo2: {
                        handler(newValue, oldValue) {
                            console.log(oldValue, newValue);
                        },
                        deep: true
                    },             
                },
                methods: {
                    Edit3() {
                        this.userInfo2 = { userName: 'test2' };
                    },
                    Edit4() {
                        this.userInfo2.userName = 'test2';
                    },
                    Edit5() {
                        this.userInfo2.childInfo.cName = 'lmr';
                    }

                }

            }).mount('#app');
        </script>
    </body>

剖析:

  無論是修改  userInfo2.userName 還是  userInfo2.childInfo.cName ,都可以監聽到。

發現一問題:

  新對象和舊對象中的userName值是相同的,這是因為引用類型賦值的問題,都是指向同一個內存地址(詳見后面的知識補充)

(2). 立即執行

  通過設置參數immediate: true,即不發生變化前,默認執行一次。

4.  其它寫法

(1). 直接監聽對象中某個屬性值

    watch: {
                    // 特殊的監聽方式
                    // 直接監聽userName的值
            'userInfo2.userName'(newValue, oldValue) {
                console.log(oldValue, newValue);
            }
    },

(2).  在created生命周期中進行監聽

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鵬飛)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 聲     明1 : 如有錯誤,歡迎討論,請勿謾罵^_^。
  • 聲     明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM