Vue学习笔记(Vue2)

目录

一、vue核心

1、vue简介

1.1、vue是什么

一套用于构建用户界面的渐进式JavaScript框架。

渐进式:vue可以自底向上逐层应用;简单应用:只需一个轻量小巧的核心库;复杂应用:可以引入各式各样的的vue插件。

1.2、谁开发的

华人 尤雨溪;
vue2(攻壳机动队) vue3(海贼王)
在这里插入图片描述

1.3、vue的特点
  • 采用组件化模式,提高代码复用率、且让代码更好的维护
    在这里插入图片描述
  • 声明式编码(原生js为命令式编码),使无需直接操作DOM,提高开发效率
  • 使用虚拟DOM+优秀的Diff算法,尽量复用DOM节点
    在这里插入图片描述
1.4、vue官网

vue官网:.https://cn.vuejs.org/v2/guide/
在这里插入图片描述

1.5、搭建vue开发环境
  • 引入vue.js文件
  • 安装浏览器vue插件:vue.js devyools
  • Vue.config.productionTip = false;//设置为 false 以阻止 vue 在启动时生成生产提示。

2、初识Vue:

2.1、第一个Vue程序:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script type="text/javascript" src="vue.js"></script>
</head>

<body>
    <!-- 准备一个容器 -->
    <!-- 插值 -->
    <div id="root">hello {
  {name}}</div>
    <script>
        Vue.config.productionTip = false; //设置为 false 以阻止 vue 在启动时生成生产提示。

        // 创建Vue实例
        const x = new Vue({
     
            el: '#root', //el:挂载点,相当于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串
            data: {
      //data用于存储数据,数据供el所指定的容器去使用。值我们暂时先写成一个对象
                name: 'vue',
                age: 8
            }
        });
    </script>
</body>

</html>
2.2、初识Vue总结:
  • 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象
  • root容器的代码依然符合html规范,只不过混入了一些特殊的Vue语法
  • root容器里的代码被称为Vue模板
  • 容器和vue实例必须一一对应,不能一对多,也不能多对一
  • 真实开发中只有一个Vue实例,并且会配合组件一起使用
  • { {xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有数据
  • 一旦data中的数据发生改变,那么模板中用到的地方也会自动更新

3、模板语法

3.1、插值语法

写法:{ {js表达式}}
功能:用于解析标签体内容

<div id="root">hello {
  {name}}</div>
new Vue({
   
            el: '#root',
            data: {
   
                name: 'vue'
            }
        });
3.2、指令语法

写法:v-bind:href="xxx"或简写为 :href=“xxx”
功能:用于解析标签(包括标签属性、标签体内容、绑定事件…)

<div id="root">
        <a v-bind:href="url">百度一下</a>
    </div>
new Vue({
   
            el: '#root',
            data: {
    
                url: 'http://www.baidu.com'
            }
        });

4、数据绑定

4.1、单向数据绑定

单向数据绑定(v-bind,简写 :):数据只能从data流向页面

<div id="root">
        单向数据绑定: <input type="text" v-bind:value="name">
    </div>
  Vue.config.productionTip = false; //设置为 false 以阻止 vue 在启动时生成生产提示。
        new Vue({
   
            el: "#root",
            data: {
   
                name: 'zhangsan'
            }
        })
4.2、双向数据绑定

双向数据绑定(v-model):数据不仅可以从data流向页面,还可以从页面流向data

双向绑定一般都应用在表单类元素上(如input、select等)

v-model:value 可以简写为 v-model,因为v-model默认手机就是value值

<div id="root">
         双向数据绑定: <input type="text" v-model:value="name">
    </div>
  Vue.config.productionTip = false; //设置为 false 以阻止 vue 在启动时生成生产提示。
        new Vue({
   
            el: "#root",
            data: {
   
                name: 'zhangsan'
            }
        })

穿插:el和data的两种写法

1、el的两种写法

(1)new Vue的时候配置el属性
(2)先创建Vue实例,随后再通过vm.$mount(’#root’)指定el值

2、data的两种写法

(1)对象式

data:{
   }

(2)函数式

data:function(){
   
	return {
   
		
	}
}

以后学组件的时候,data必须使用函数式,否则会报错
一个重要原则:由Vue管理的函数,一定不要写箭头函数,写了箭头函数,this指向就不再是Vue实例了

5、MVVM模型

5.1、MVVM模型

M:模型(Model),对应data中的数据
V:视图(View):对应模板
VM:视图模型(ViewModel):对应Vue实例对象
在这里插入图片描述
data(M)中多有属性最后都出现在了vm身上
vm身上所有属性及Vue原型上所有属性,在vue模板(V)中都可以直接使用

5.2、Object.defineProperty方法

功能:给对象添加属性
语法:

Object.defineProperty(对象名,新属性名,{
   value:新属性值[,其他配置]})

其他配置项例如:

let person = {
   
            name: 'zhangsan',
            sex: 'nan'
        }
        Object.defineProperty(person, 'age', {
   
             value: 18,
             enumerable: true, //控制属性是否可以枚举,默认值是false
             writable: true, //控制属性是否可以被修改,默认值是false
             configurable: true //控制属性是否可以被删除,默认值是false
        })
        console.log(person);

借助Object.defineProperty方法让对象和数据产生关联:

let number = 14;
        let person = {
   
            name: 'zhangsan',
            sex: 'nan'
        }
        Object.defineProperty(person, 'age', {
   
            //当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
            get() {
   
                console.log('有人读取age属性了');
                return number;
            },

            //当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
            set(value) {
   
                console.log('有人修改了age属性,且值为' + value);
                number = value;
            }
        })
        console.log(person);
5.3、理解数据代理

什么是数据代理:通过一个对象代理对另一个对象中属性的操作(读写)
例如一个简单的数据代理:

 let obj1 = {
   
            x: 100
        }
        let obj2 = {
   
            y: 200
        }
        Object.defineProperty(obj2, 'x', {
   
            get() {
   
                return obj1.x;
            },
            set(value) {
   
                obj1.x = value
            }
        })

这样obj2就可以读写obj1的x属性,这就是简单的数据代理
在这里插入图片描述

5.4、vue中的数据代理

在vue中,通过vm对象来代理data对象中的属性的操作(读写)
模板中直接写属性名就可以读写操作,这就用到了数据代理,如下有:

 <div id="root">
        <h2>学校:{
  {name}}</h2>
        <h2>地址:{
  {address}}</h2>
    </div>
Vue.config.productionTip = false; //设置为 false 以阻止 vue 在启动时生成生产提示。
        const vm = new Vue({
   
            el: "#root",
            data: {
   
                name: 'beida',
                address: 'beijing'
            }
        })

模板中用的是name,而不是_data.name(即data.name),这里就用到了数据代理,vue对象代理了_data对象;通过vm.name就可以读写_data中的name。
在这里插入图片描述
这里vm.name和vm._data.name的值相同,修改vm.name的值,vm._data.name也会改变。
在这里插入图片描述
基本原理:
就是上一小节讲到的数据代理,通过Object.defineProperty()方法把data对象中所有属性添加到vm,为每一个添加到vm上的属性,都指定一个getter/setter,getter/setter内部去操作(读写)data中对应的数据

vue中数据代理的好处:
更加方便的操作data中的数据

6、事件处理

6.1、事件处理的基本使用
  • 使用v-on:xxx@xxx绑定事件,其中xxx是事件名
  • 事件的回调需要配置在methods对象中,最终会在vm上;
  • methods中配置的函数不要用箭头函数,否则this指向就不是vm了
  • methods中配置的函数,都被Vue所管理的函数,this的指向是vm 或组件实例对象
  • @click="demo"@click="demo($event)"效果一样,但后者可以传参
 <div id="root">
        <h3>欢迎来到{
  {name}}学习</h3>
        <br>
        <button v-on:click="showInfo1">点我提示信息1</button>
        <button v-on:click="showInfo2(666,$event)">点我提示信息2</button>
    </div>
 Vue.config.productionTip = false; //设置为 false 以阻止 vue 在启动时生成生产提示。
        const vm = new Vue({
   
            el: "#root",
            data: {
   
                name: 'atshanggui'
            },
            methods: {
   
                showInfo1(event) {
   
                    console.log(event.target);
                    console.log(this);
                    alert('同学你好')
                },
                showInfo2(a, event) {
   
                    console.log(event.target);
                    console.log(this);
                    alert(a + '同学你好')
                }
            }
        })
6.2、事件修饰符

之前可以通过e.preventDefault();阻止标签的默认行为,如下:

	<div id="root">
        <a href="http://www.baidu.com" @click="showInfo">百度一下</a>
    </div>
Vue.config.productionTip = false; //设置为 false 以阻止 vue 在启动时生成生产提示。
        const vm = new Vue({
   
            el: "#root",
            data: {
   
            },
            methods: {
   
                showInfo(e) {
   
                    e.preventDefault(); //阻止事件默认行为,这里阻止a标签的默认跳转
                    alert("百度一下你就知道")
                }
            }
        })

在vue中可以通过事件修饰符来阻止默认行为:

	<div id="root">
        <a href="http://www.baidu.com" @click.prevent="showInfo">百度一下</a>
    </div>

js代码部分的e.preventDefault()就可以去掉,也可以阻止默认行为。这就是事件修饰符的作用之一。


Vue中的事件修饰符有六个,前三个比较常用:

  • (1)prevent:阻止默认事件
    上面已讲
  • (2)stop:阻止事件冒泡

事件冒泡:

<style>
        .demo1 {
     
            height: 100px;
            background-color: pink;
        }
    </style>
 	<div id="root">
        <div class="demo1" @click="showInfo1">
            <button @click="showInfo1">点我提示信息</button>
        </div>
    </div>
 Vue.config.productionTip = false; //设置为 false 以阻止 vue 在启动时生成生产提示。
        const vm = new Vue({
   
            el: "#root",
            data: {
   
            },
            methods: {
   
                showInfo1(e) {
   
                    alert("你好同学")
                }
            }
        })

这样点击button就会弹框两次,这就是事件冒泡,可以通过e.stopPropagation()阻止,也可以用事件修饰符stop(加在内嵌容器上)

 	<div id="root">
        <div class="demo1" @click="showInfo1">
            <button @click.stop="showInfo1">点我提示信息</button>
        </div>

    </div>
  • (3)once:事件只触发一次

事件只触发一次:

 <div id="root">
        <button @click.once="showInfo1">点我提示信息</button>
    </div>
  • (4)capture:使用事件的捕获模式

使用事件的捕获模式:
事件先捕获后冒泡,页面一般在冒泡阶段处理事件,比如下面这段代码点击div2就是先打印2,再打印1:

<style>
 .box1 {
     
            padding: 5px;
            background-color: pink;
        }
        .box2 {
     
            padding: 5px;
            height: 50px;
            background-color: red;
        }
</style>
	<div id="root">
 		<div class="box1" @click="show(1)">
            div1
            <div class="box2" @click="show(2)">div2</div>
        </div>
    </div>
 const vm = new Vue({
   
            el: "#root",
            methods: {
   
                show(x) {
   
                    console.log(x);
                }
            }
        })

在这里插入图片描述
在这里插入图片描述
这时就可以用capture使用事件的捕获模式,先打印1,再打印2(加在外层容器上):

	<div id="root">
 		<div class="box1" @click.capture="show(1)">
            div1
            <div class="box2" @click="show(2)">div2</div>
        </div>
    </div>

在这里插入图片描述

  • (5)self:只有event.target是当前操作的元素时才触发事件
  • (6)passive:事件的默认行为立即执行,无需等待事件回调执行完毕

(5)和(6)用的少,就不细说了
再就是事件修饰符可以连续写,例如:

@click.stop.prevent="xxx"

就是先阻止冒泡事件,再阻止默认行为。

6.3、键盘事件

(1)常用的两个键盘触发事件:

  • keydown:按下按键不用抬起来就触发事件
  • keyup:按下按键抬起来才触发事件(常用)

(2)Vue中按键别名

 <div id="root">
        <input type="text" placeholder="按下回车提示输入" @keyup.enter="showInfo">
    </div>
    <script>
        Vue.config.productionTip = false; //设置为 false 以阻止 vue 在启动时生成生产提示。
        const vm = new Vue({
     
            el: "#root",
            methods: {
     
                showInfo(e) {
     
                    console.log(e.target.value);
                }
            }
        })
    </script>

上面代码中通过Enter键按下后抬起触发事件,enter为vue中Enter的别名

常用的按键别名有:

  • 回车=>enter
  • 删除=>delete(捕获“删除”和“退格”键)
  • 退出=>esc
  • 空格=>space
  • 换行=>tab(特殊,必须配合keydown使用)
  • 上=>up
  • 下=>down
  • 左=>left
  • 右=>right

Vue未提供别名的按键,可以使用按键原始的key值去绑定,但要注意驼峰命名法的原始key值要转化为短横线命名,例如大小写转换键KebabCase就要写成kebab-case。

系统修饰键(用法特殊):ctrl、alt、shift、meta,用法如下:

  • 配合keyup使用:按下修饰键的同时再按下其他键,随着释放其他键,事件才被触发
  • 配合kedown使用:正常触发事件
  • 如果只想要修饰键+一个其他键 才能触发事件可以连续写,例如下面这行代码就是只有按下ctrl+y才能触发事件:
@keyup.ctrl.y="xxx"

Vue.config.keyCodes.自定义键名 =键码,可以自定义按键别名。

在事件触发函数中获取键名和键码:

showInfo(e) {
   
    console.log(e.key, e.keyCode);
}

7、计算属性与监视

7.1、计算属性

(1)定义:要用的属性不存在,要通过已有属性计算出来
(2)原理:底层借助了Object.defineproperty方法提供的getterr和setter
(3)get函数什么时候执行?
     ①初次读取时会执行一次
     ②当依赖的数据发生改变时会被再次调用
(4)优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试更方便
(5)备注:
     ①计算属性最终会出现在vm上,直接调用即可
     ②如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生变化

例如:

 <div id="root">
        姓:<input type="text" v-model="firstName"><br><br>
        名:<input type="text" v-model="lastName"><br><br>
        全名:{
  {fullName}}
    </div>
 Vue.config.productionTip = false; //设置为 false 以阻止 vue 在启动时生成生产提示。
        const vm = new Vue({
   
            el: "#root",
            data: {
   
                firstName: '张',
                lastName: '三'
            },
            //计算属性
            computed: {
   
                fullName: {
   
                    // get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
                    get() {
   
                        return this.firstName + '-' + this.lastName;
                    },
                    //多数情况只读不改,所以只读情况set就不用写
                    set(value) {
   
                        const arr = value.split('-');
                        this.firstName = arr[0];
                        this.lastName = arr[1];
                    }
                }
            }
        })

多数情况只读不改,所以只读情况set就不用写,就可以直接写一个函数:

 fullName() {
   
     return this.firstName + '-' + this.lastName;
}

这个函数的功能就是get函数的功能,最后还是会把fullName配置到vm对象下,所以模板中写的是fullName,而不是fullName(),写fullName()就相当于调用get(),是错误的。

7.2、监视属性

(1)监视属性(watch)可以监视数据的变化,data和computed中的数据都可以被监视。
例如:

    <div id="root">
        <h2>今天天气很{
  {info}}</h2>
        <button @click="changeWeather">切换天气</button>
    </div>
Vue.config.productionTip = false; //设置为 false 以阻止 vue 在启动时生成生产提示。
        const vm = new Vue({
   
            el: "#root",
            data: {
   
                isHot: true
            },
            methods: {
   
                changeWeather() {
   
                    this.isHot = !this.isHot;
                }
            },
            computed: {
   
                info() {
   
                    return this.isHot ? '炎热' : '凉爽';
                }
            },
            watch: {
   
                isHot: {
   
                	deep:true, //开启深度监测
                    immediate: true, //初始化时让handler调用一下
                    handler(newValue, oldValue) {
   
                        console.log('isHot被修改了', newValue, oldValue);
                    }
                }
            }
        })

在watch中监视isHot,第一个属性immediate默认false,设置为true就会初始化时让handler调用一下;第二个handler方法,当数据isHot发生改变时自动调用,里面的参数第一个是改变后的值,第二个是改变前的值。

监视属性(watch)即有:

  • 当被监视的属性变化时,回调函数自动调用,进行相关的操作
  • 监视的属性必须存在,才能进行监视
  • 监视的两种写法:除了上面的在new Vue时写入watch配置这种方法外,还有 通过vm.$watch,例如下面代码
	   vm.$watch("isHot", {
   
            immediate: true, //初始化时让handler调用一下
            handler(newValue, oldValue) {
   
                console.log('isHot被修改了', newValue, oldValue);
            }
        });

(2)深度监视
Vue中的监视属性watch默认不监视对象内部值的改变(只监视一层),比如:

 const vm = new Vue({
   
            el: "#root",
            data: {
   
                number: {
   
                    a: 1,
                    b: 2
                }
            }
        }),
        watch: {
   
                number: {
   
                    handler(newValue, oldValue) {
   
                        console.log('a被修改了', newValue, oldValue);
                    }
                }
            }

上面代码中,watch只能监视number的值的改变(该值是一个地址),里面的a或b发生改变了监视不到,watch改成:

 'number.a': {
   
                    handler(newValue, oldValue) {
   
                        console.log('a被修改了', newValue, oldValue);
                    }
}

就可以监视到里面的a的变化,但是如果要同时监视a和b,甚至有跟多的数时,这时就不能这么写了。

于是,配置deep:true可以检测对象内部值的变化(监视多层)

number: {
   
     deep: true,
     handler(newValue, oldValue) {
   
         console.log('bumber被修改了', newValue, oldValue);
     }
 }

注:

  • Vue自身可以监视对象内部值的改变,但Vue提供的watch默认不可以
  • 使用watch时根据数据的具体结构,决定是否采取深度监视

(3)监视属性的简写
前面学习计算属性computed的时候,只有get函数不写set函数时可以简写该属性;在这监视属性watch也一样,只写handler函数不写deep,immediate时也可以简写。
例如上面写过的如果只写hander就可以简写为:

	 watch: {
   
                // 简写:
                isHot(newValue, oldValue) {
   
                    console.log('isHot被修改了', newValue, oldValue);
                }
            }

当然还有通过vm.$watch来监视时也可以简写:

		vm.$watch("isHot", function(newValue, oldValue) {
   
            console.log('isHot被修改了', newValue, oldValue);
        });

同样为了不改变函数的this指向,也能写成箭头函数;即一般在Vue内管理的函数都不要写箭头函数。

7.3、计算属性和监视属性的区别

(1)computed能完成的功能,watch都可以完成
(2)watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作
(3)都能完成的尽量用computed,因为computed是声明式的,watch是命令式的

下面这个姓名案例两种属性都可以实现:

	<div id="root">
        姓:<input type="text" v-model="firstName"><br><br>
        <!--  -->
        名:<input type="text" v-model="lastName"><br><br>
        <!--  -->
        全名:{
  {fullName}}
    </div>

计算属性实现:

	Vue.config.productionTip = false; //设置为 false 以阻止 vue 在启动时生成生产提示。
        const vm = new Vue({
   
            el: "#root",
            data: {
   
                firstName: '张',
                lastName: '三'
            },
            computed: {
   
                fullName() {
   
                    return this.firstName + '-' + this.lastName;
                }
            }
        })

监视属性实现:

		const vm = new Vue({
   
            el: "#root",
            data: {
   
                firstName: '张',
                lastName: '三',
                fullName: "张三"
            },
            watch: {
   
                firstName(newValue, oldValue) {
   
                    this.fullName = newValue + '-' + this.lastName;
                },
                lastName(newValue, oldValue) {
   
                    this.fullName = this.firstName + '-' + newValue;
                }
            }
        })

但是异步任务用计算属性就很难实现,用监视属性就很好实现,比如加一个计时器,让全名的姓延迟一秒更新:

		const vm = new Vue({
   
            el: "#root",
            data: {
   
                firstName: '张',
                lastName: '三',
                fullName: "张三"
            },
            watch: {
   
                firstName(newValue, oldValue) {
   
                    setTimeout(() => {
   
                        this.fullName = newValue + '-' + this.lastName;
                    }, 1000)
                },
                lastName(newValue, oldValue) {
   
                    this.fullName = this.firstName + '-' + newValue;
                }
            }
        })

两个重要的小原则:

  • 所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
  • 所有不被Vue所管理的函数(如定时器的回调函数,ajax的回调函数等,Promise的回调函数),最好写成箭头函数,这样this的指向才是vm 或组件实例对象。

目标都一个,就是让this指向是vm。

8、class与style绑定

8.1、理解

(1)在应用界面中,某个(些)元素的样式是变化的
(2)class/style绑定就是专门用来实现动态样式效果的技术

8.2、绑定class

(1)绑定class样式–字符串写法,适用于:样式的类名不确定,需要动态指定
(2)绑定class样式–数组写法,适用于:要绑定的样式个数不确定、名字也不确定
(3)绑定class样式–对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用
例如:

<style>
        .basic {
     
            width: 300px;
            height: 60px;
            margin: 10px;
            border: 1px solid black;
        }
        .happy {
     
            background-color: pink;
            border: 1px solid black;
        } 
        .sad {
     
            background-color: rgb(70, 67, 68);
            border: 1px solid black;
        }
        .wu {
     
            background-color: rgb(236, 3, 42);
            border: 1px solid black;
        }
        .at1 {
     
            background-color: green;
            border: 4px solid black;
        }
        .at2 {
     
            background-color: green;
            border: 4px dashed black;
        }
        .at3 {
     
            background-color: green;
            border: 4px solid blue;
        }
    </style>
    <div id="root">
        <!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
        <div class="basic" :class="classStr">{
  {name}}</div>
        <!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
        <div class="basic" :class="classArr">{
  {name}}</div>
        <!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
        <div class="basic" :class="classObj">{
  {name}}</div>
    </div>
Vue.config.productionTip = false; //设置为 false 以阻止 vue 在启动时生成生产提示。
        const vm = new Vue({
   
            el: "#root",
            data: {
   
                name: "test",
                classStr: "happy",
                classArr: ['at1', 'at2', 'at3'],
                classObj: {
   
                    at1: true,
                    at2: false
                }
            }
        })
8.3、style绑定

(1)绑定style样式–对象写法 ,属性名改为小驼峰命名
(2)绑定style样式–数组写法(不常用),数组其中是对象
例如:

	<style>
        .basic {
     
            width: 300px;
            height: 60px;
            margin: 10px;
            border: 1px solid black;
        }
    </style>
    <div id="root">
        <!-- 绑定style样式--对象写法 -->
        <div class="basic" :style="styleObj">{
  {name}}</div>
        <!-- 绑定style样式--数组写法(不常用) -->
        <div class="basic" :style="styleArr">{
  {name}}</div>
    </div>
	const vm = new Vue({
   
            el: "#root",
            data: {
   
                name: "test",
                styleObj: {
   
                    fontSize: '40px',
                    color: "red",
                    backgroudColor: "yellow"
                },
                styleArr: [{
   
                        fontSize: '40px',
                        color: "red"
                    }, {
   
                        backgroudColor: "yellow"
                    }

                ]
            }
        })

9、条件渲染

(1)v-if

<h3 v-if="false">你好,{
  {name}}</h3>

写法:

  • v-if=“表达式”
  • v-else-if=“表达式”
  • v-else
    适用于:切换频率较低的场景
    特点:不展示的DOM元素直接被删除
    注意:v-if可以和v-else-if、v-else一起使用,但要求结构不能被打断

< template>配合v-if使用:

		<template v-if="true">
            <h3>你好,{
  {name}}</h3>
            <h3>你好,{
  {name}}</h3>
            <h3>你好,{
  {name}}</h3>
        </template>

在这里插入图片描述
< template>不会渲染到DOM结构中,且只有和v-if配合使用才可以起到整套删除整套显示的效果。

(2)v-show

<h3 v-show="false">你好,{
  {name}}</h3>

写法:v-show=“表达式”
适用于:切换频率较高的场景
特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉了

10、列表渲染

10.1、基本列表

v-for指令:

  • 用于展示列表数据
  • 语法:
v-for="(item,index) in xxx" :key="xxx"

key的原理和用法下面会说。

  • 可遍历数组、对象、字符串(用得少)、指定次数(用得少)

例如遍历数组:

	<div id="root">
        <ul>
            <li v-for="(p,index) in person" :key="">{
  {p.name}}-{
  {p.age}}</li>
        </ul>
    </div>
const vm = new Vue({
   
            el: "#root",
            data: {
   
                person: [{
   
                    id: 001,
                    name: "张三",
                    age: 18
                }, {
   
                    id: 002,
                    name: "李四",
                    age: 28
                }, {
   
                    id: 003,
                    name: "王五",
                    age: 13
                }, ]
            }
        })

在这里插入图片描述

p就是数组值,index就是索引

如果遍历的是对象,前者就是值,后者就是键

10.2、key的原理

我们在上面遍历数组的代码基础上,增加一个需求:点击一个按钮在张三的上面增加一行老刘的信息,并在每一行后面增加一个input框,用这个需求来分析key的原理:

	<div id="root">
        <button @click.once="add">添加</button>
        <ul>
            <li v-for="(p,index) in person" :key="index">{
  {p.name}}-{
  {p.age}}
                <input type="text">
            </li>
        </ul>
    </div>
 const vm = new Vue({
   
            el: "#root",
            data: {
   
                person: [{
   
                    id: 001,
                    name: "张三",
                    age: 18
                }, {
   
                    id: 002,
                    name: "李四",
                    age: 28
                }, {
   
                    id: 003,
                    name: "王五",
                    age: 13
                }, ]
            },
            methods: {
   
                add() {
   
                    const p = {
   
                        id: '004',
                        name: '老刘',
                        age: 40
                    }
                    //向数组前加元素
                    this.person.unshift(p)
                }
            }
        })

上面代码在没点击按钮前并在input中输入一些信息后为:
在这里插入图片描述
此时点击按钮后:
在这里插入图片描述
就出现了一个很严重的问题,input框信息错位

这里就是把key用index作为值出现的问题,另外还有一个隐蔽的问题就是效率太低。

出现这两个问题的原因就要分析key的原理和Vue的虚拟DOM的diff对比算法
下面几点都要重点了解,面试常问:

①虚拟DOM中key的作用:

  • key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】
  • 随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则 见下面②。

②对比规则:

  • 若 旧虚拟DOM中找到了与新虚拟DOM相同的key:若虚拟DOM中的内容没有变化,直接使用之前的真实DOM;若内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
  • 若 旧虚拟DOM中未找到与新虚拟DOM相同的key:创建新的真实DOM,随后渲染到页面

③用index作为key可能会出现的问题:

  • 若对数据进行 逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新==》界面效果没有问题,但效率低
  • 如果结构中还包含输入类的DOM(如上面的input):还会产生错误的DOM更新==》界面有问题

③开发中如何选择key?

  • 最好使用每条数据的唯一标识作为key值,比如id、手机号、身份证号、学号等唯一值
  • 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key值是没有问题的
10.3、列表过滤

下面用两个例子(分别是用监视和计算属性)来实现列表过滤:

例子一(监视):

    <div id="root">
        <input type="text" placeholder="请输入名字" v-model="keyword">
        <ul>
            <li v-for="p in person1" :key="p.id">{
  {p.name}}-{
  {p.age}}-{
  {p.sex}}</li>
        </ul>
    </div>
        const vm = new Vue({
   
            el: "#root",
            data: {
   
                keyword: "",
                person: [{
   
                    id
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东篱_Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值