• 第三节: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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    java实现httpclient 访问
    推荐博文
    Running With xpi
    1 Spring MVC 原理
    windows服务相关
    求职面试三部曲
    使用mvn插件执行工程单元测试OOM的解决办法
    maven-surefire插件问题
    小问题
    NFA到DFA实例
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/15247883.html
Copyright © 2020-2023  润新知