文章目录

  • 第一部分:vue核心
    • 一、Vue简介
      • 1.官网
      • 2.大纲
    • 二、初识vue
    • 三、模板语法
      • 1.语法说明
        • 1.1 插值语法(双大括号表达式)
        • 1.2 指令(以 v-开头)
      • 2.数据绑定
        • 2.1 单项数据绑定
        • 2.2 双向数据绑定
      • 3.el与data的两种写法
        • 3.1 el
        • 3.2 data
        • 3.3 一个重要的原则
      • 4.MVVM模型
      • 5.数据代理
        • 5.1 Object.defineProperty
        • 5.2 何为数据代理
        • 5.3 Vue中的数据代理
      • 6.事件处理
        • 6.1 事件基本使用
        • 6.2 绑定监听
        • 6.3 事件修饰符
        • 6.4 按键修饰符
      • 7.计算属性与监视
        • 7.1 计算属性-computed
        • 7.2 监视-watch
        • 7.3 computed和watch之间的区别
      • 8.绑定样式
      • 9.条件渲染
        • 9.1 v-if
        • 9.2 v-show
        • 9.3 备注:
      • 10.列表渲染
        • 10.1 v-for指令
        • 10.2 key的原理
          • 1.虚拟DOM中key的作用
          • 2.对比规则:
          • 3.用index作为key可能会引发的问题:
          • 4.开发中如何选择key?:
        • 10.3 列表过滤
        • 10.4 列表排序
        • 10.5 Vue监视数据的原理
      • 11.收集表单数据
      • 12.过滤器
      • 13.内置指令与自定义指令
        • 13.1 常用内置指令
        • 13.2 自定义指令
          • 13.2.1 全局指令
          • 13.2.2 局部指令
      • 14.生命周期
        • 14.1 概览
        • 14.2 8个钩子函数
        • 14.3 常用的生命周期方法

第一部分:vue核心

一、Vue简介

1.官网

  • 英文官网
  • 中文官网

2.大纲

  • vue基础
  • vue-cli
  • vue-router
  • vuex
  • element-ui
  • vue3

二、初识vue

  1. 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象;

  2. root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法;

  3. root容器里的代码被称为【Vue模板】;

  4. Vue实例和容器是一一对应的;

  5. 真实开发中只有一个Vue实例,并且会配合着组件一起使用;

  6. {{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性;

  7. 一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新;

    注意区分:js表达式 和 js代码(语句)

    • 表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方:
      (1). a
      (2). a+b
      (3). demo(1)
      (4). x === y ? ‘a’ : ‘b’
    • js代码(语句)
      (1). if(){}
      (2). for(){}

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>初识Vue</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器 -->
		<div id="demo">
			<h1>Hello,{{name.toUpperCase()}},{{address}}</h1>
		</div>

		<script type="text/javascript" >
			Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

			//创建Vue实例
			new Vue({
				el:'#demo', //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串。
				data:{ //data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象。
					name:'alvis',
					address:'北京'
				}
			})
		</script>
	</body>
</html>

三、模板语法

1.语法说明

html 中包含了一些 JS 语法代码,语法分为两种,分别为:

1.1 插值语法(双大括号表达式)

  • 功能: 用于解析标签体内容
  • 语法: {{xxx}} ,xxxx 会作为 js 表达式解析

1.2 指令(以 v-开头)

  • 功能: 解析标签属性、解析标签体内容、绑定事件
  • 举例:v-bind:href = ‘xxxx’ ,xxxx 会作为 js 表达式被解析 ,v-bind:可以简写成:
  • 说明:Vue 中有有很多的指令,此处只是用 v-bind 举个例子

2.数据绑定

2.1 单项数据绑定

  • 语法:v-bind:href =“xxx” 或简写为 :href =“xxx”
  • 特点:数据只能从 data 流向页面

2.2 双向数据绑定

  • 语法:v-mode:value=“xxx” 或简写为 v-model=“xxx”
  • 特点:数据不仅能从 data 流向页面,还能从页面流向 data
  • v-model只能应用在表单类元素(输入类元素)上

3.el与data的两种写法

3.1 el

  • new Vue时候配置el属性

  • 先创建Vue实例,随后再通过vm.$mount(’#root’)指定el的值。

    //el的两种写法
    /* const v = new Vue({
    //el:'#root', //第一种写法
    	data:{
    		name:'alvis'
    	}
    })
    console.log(v)
    v.$mount('#root') //第二种写法 */
    

3.2 data

  • 对象式

  • 函数式

    • 如何选择:目前哪种写法都可以,以后学习到组件时,data必须使用函数式,否则会报错。
    //data的两种写法
    new Vue({
        el:'#root',
        //data的第一种写法:对象式
        /* data:{
        	name:'alvis'
        } */
    
        //data的第二种写法:函数式
        data(){
            console.log('@@@',this) //此处的this是Vue实例对象
            return{
            	name:'alvis'
            }
        }
    })
    

3.3 一个重要的原则

由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。

4.MVVM模型

M:模型(Model) :对应 data 中的数据

V:视图(View) :模板

VM:视图模型(ViewModel) : Vue 实例对象

5.数据代理

5.1 Object.defineProperty

<script type="text/javascript" >
    let number = 18
    let person = {
        name:'张三',
        sex:'男',
    }

    Object.defineProperty(person,'age',{
        // value:18,
        // enumerable:true, //控制属性是否可以枚举,默认值是false
        // writable:true, //控制属性是否可以被修改,默认值是false
        // configurable:true //控制属性是否可以被删除,默认值是false

        //当有人读取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(Object.keys(person))

    console.log(person)
</script>

5.2 何为数据代理

数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)

<script type="text/javascript" >
    let obj = {x:100}
    let obj2 = {y:200}

    Object.defineProperty(obj2,'x',{
        get(){
            return obj.x
        },
        set(value){
            obj.x = value
        }
    })
</script>

5.3 Vue中的数据代理

  • 实现:通过vm对象来代理data对象中属性的操作(读/写)
  • 好处:更加方便的操作data中的数据
  • 基本原理:
    • 通过Object.defineProperty()把data对象中所有属性添加到vm上。
    • 为每一个添加到vm上的属性,都指定一个getter/setter。
    • 在getter/setter内部去操作(读/写)data中对应的属性。

6.事件处理

6.1 事件基本使用

  1. 使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名;
  2. 事件的回调需要配置在methods对象中,最终会在vm上;
  3. methods中配置的函数,不要用箭头函数!否则this就不是vm了;
  4. methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象;
  5. @click=“demo” 和 @click=“demo($event)” 效果一致,但后者可以传参;
<!-- 准备好一个容器-->
<div id="root">
    <h2>欢迎来到{{name}}学习</h2>
    <!-- <button v-on:click="showInfo">点我提示信息</button> -->
    <button @click="showInfo1">点我提示信息1(不传参)</button>
    <button @click="showInfo2($event,66)">点我提示信息2(传参)</button>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

    const vm = new Vue({
        el:'#root',
        data:{
            name:'alvis',
        },
        methods:{
            showInfo1(event){
                // console.log(event.target.innerText)
                // console.log(this) //此处的this是vm
                alert('同学你好!')
            },
            showInfo2(event,number){
                console.log(event,number)
                // console.log(event.target.innerText)
                // console.log(this) //此处的this是vm
                alert('同学你好!!')
            }
        }
    })
</script>

6.2 绑定监听

  1. v-on:xxx=“fun”
  2. @xxx=“fun”
  3. @xxx=“fun(参数)”
  4. 默认事件形参: event
  5. 隐含属性对象: $event

6.3 事件修饰符

  • prevent : 阻止事件的默认行为 event.preventDefault()
  • stop : 停止事件冒泡 event.stopPropagation()
  • once:事件只触发一次(常用)
  • capture:使用事件的捕获模式
  • self:只有event.target是当前操作的元素时才触发事件
  • passive:事件的默认行为立即执行,无需等待事件回调执行完毕;
<!-- 准备好一个容器-->
<div id="root">
    <h2>欢迎来到{{name}}学习</h2>
    <!-- 阻止默认事件(常用) -->
    <a href="http://www.atguigu" @click.prevent="showInfo">点我提示信息</a>

    <!-- 阻止事件冒泡(常用) -->
    <div class="demo1" @click="showInfo">
        <button @click.stop="showInfo">点我提示信息</button>
        <!-- 修饰符可以连续写 -->
        <a href="http://www.baidu" @click.prevent.stop="showInfo">点我提示信息</a>
    </div>

    <!-- 事件只触发一次(常用) -->
    <button @click.once="showInfo">点我提示信息</button>

    <!-- 使用事件的捕获模式 -->
    <div class="box1" @click.capture="showMsg(1)">
        div1
        <div class="box2" @click="showMsg(2)">
            div2
        </div>
    </div>

    <!-- 只有event.target是当前操作的元素时才触发事件; -->
    <div class="demo1" @click.self="showInfo">
        <button @click="showInfo">点我提示信息</button>
    </div>

    <!-- 事件的默认行为立即执行,无需等待事件回调执行完毕; -->
    <ul @wheel.passive="demo" class="list">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>

</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

    new Vue({
        el:'#root',
        data:{
            name:'alvis'
        },
        methods:{
            showInfo(e){
                alert('同学你好!')
                // console.log(e.target)
            },
            showMsg(msg){
                console.log(msg)
            },
            demo(){
                for (let i = 0; i < 100000; i++) {
                    console.log('#')
                }
                console.log('累坏了')
            }
        }
    })
</script>

修饰符可以连续写

6.4 按键修饰符

  • keycode : 操作的是某个 keycode 值的键
  • keyName : 操作的某个按键名的键(少部分)
  1. Vue中常用的按键别名:
    回车 => enter
    删除 => delete (捕获“删除”和“退格”键)
    退出 => esc
    空格 => space
    换行 => tab (特殊,必须配合keydown去使用)
    上 => up
    下 => down
    左 => left
    右 => right
  2. Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)
  3. 系统修饰键(用法特殊):ctrl、alt、shift、meta
    • 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
    • 配合keydown使用:正常触发事件。
  4. 也可以使用keyCode去指定具体的按键(不推荐)
  5. Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名
<!-- 准备好一个容器-->
<div id="root">
    <h2>欢迎来到{{name}}学习</h2>
    <input type="text" placeholder="按下回车提示输入" @keydown.huiche="showInfo">
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
    Vue.config.keyCodes.huiche = 13 //定义了一个别名按键

    new Vue({
        el:'#root',
        data:{
            name:'alvis'
        },
        methods: {
            showInfo(e){
                // console.log(e.key,e.keyCode)
                console.log(e.target.value)
            }
        },
    })
</script>

7.计算属性与监视

7.1 计算属性-computed

  • 定义:要显示的数据不存在,要通过计算得来。

  • 操作:

    • 在 computed 对象中定义计算属性。
    • 在页面中使用{{方法名}}来显示计算的结果。
  • 原理:底层借助了Objcet.defineproperty方法提供的getter和setter。

  • get函数什么时候执行?

    • 初次读取时会执行一次。
    • 当依赖的数据发生改变时会被再次调用。
  • 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。

  • 备注:

    • 计算属性最终会出现在vm上,直接读取使用即可
    • 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
<script type="text/javascript">
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

    const vm = new Vue({
        el:'#root',
        data:{
            firstName:'张',
            lastName:'三',
            x:'你好'
        },
        methods: {
            demo(){

            }
        },
        computed:{
            fullName:{
                //get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
                //get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
                get(){
                    console.log('get被调用了')
                    // console.log(this) //此处的this是vm
                    return this.firstName + '-' + this.lastName
                },
                //set什么时候调用? 当fullName被修改时。
                set(value){
                    console.log('set',value)
                    const arr = value.split('-')
                    this.firstName = arr[0]
                    this.lastName = arr[1]
                }
            }
        }
    })
</script>
  • 简写
<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		const vm = new Vue({
			el:'#root',
			data:{
				firstName:'张',
				lastName:'三',
			},
			computed:{
				//完整写法
				/* fullName:{
					get(){
						console.log('get被调用了')
						return this.firstName + '-' + this.lastName
					},
					set(value){
						console.log('set',value)
						const arr = value.split('-')
						this.firstName = arr[0]
						this.lastName = arr[1]
					}
				} */
				//简写
				fullName () {
					console.log('get被调用了')
					return this.firstName + '-' + this.lastName
				}
			}
		})
</script>

7.2 监视-watch

通过 vm 对象的$watch()或 watch 配置来监视指定的属性

当属性变化时, 回调函数自动调用, 在函数内部进行计算

  • 监视属性
<script type="text/javascript">
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

    const vm = new Vue({
        el:'#root',
        data:{
            isHot:true,
        },
        computed:{
            info(){
                return this.isHot ? '炎热' : '凉爽'
            }
        },
        methods: {
            changeWeather(){
                this.isHot = !this.isHot
            }
        },
        /* watch:{
				isHot:{
					immediate:true, //初始化时让handler调用一下
					//handler什么时候调用?当isHot发生改变时。
					handler(newValue,oldValue){
						console.log('isHot被修改了',newValue,oldValue)
					}
				}
			} */
    })

    vm.$watch('isHot',{
        immediate:true, //初始化时让handler调用一下
        //handler什么时候调用?当isHot发生改变时。
        handler(newValue,oldValue){
            console.log('isHot被修改了',newValue,oldValue)
        }
    })
</script>
  • 深度监视

    • Vue中的watch默认不监测对象内部值的改变(一层)

    • 配置deep:true可以监测对象内部值改变(多层)

    • 备注:

      (1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!

      (2).使用watch时根据数据的具体结构,决定是否采用深度监视。

<script type="text/javascript">
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

    const vm = new Vue({
        el:'#root',
        data:{
            isHot:true,
            numbers:{
                a:1,
                b:1,
                c:{
                    d:{
                        e:100
                    }
                }
            }
        },
        computed:{
            info(){
                return this.isHot ? '炎热' : '凉爽'
            }
        },
        methods: {
            changeWeather(){
                this.isHot = !this.isHot
            }
        },
        watch:{
            isHot:{
                // immediate:true, //初始化时让handler调用一下
                //handler什么时候调用?当isHot发生改变时。
                handler(newValue,oldValue){
                    console.log('isHot被修改了',newValue,oldValue)
                }
            },
            //监视多级结构中某个属性的变化
            /* 'numbers.a':{
					handler(){
						console.log('a被改变了')
					}
				} */
            //监视多级结构中所有属性的变化
            numbers:{
                deep:true,
                handler(){
                    console.log('numbers改变了')
                }
            }
        }
    })

</script>
  • 简写
watch:{
        //正常写法
        /* isHot:{
        // immediate:true, //初始化时让handler调用一下
        // deep:true,//深度监视
        handler(newValue,oldValue){
        	console.log('isHot被修改了',newValue,oldValue)
    	}
    }, */
    //简写
    /* isHot(newValue,oldValue){
    	console.log('isHot被修改了',newValue,oldValue,this)
    } */
}

/*****************************************************/

//正常写法
/* vm.$watch('isHot',{
        immediate:true, //初始化时让handler调用一下
        deep:true,//深度监视
        handler(newValue,oldValue){
        	console.log('isHot被修改了',newValue,oldValue)
    	}
}) */

//简写
/* vm.$watch('isHot',(newValue,oldValue)=>{
	console.log('isHot被修改了',newValue,oldValue,this)
}) */

7.3 computed和watch之间的区别

  1. computed能完成的功能,watch都可以完成。
  2. watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。

两个重要的小原则:

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

8.绑定样式

  1. class样式

    • 写法:class=“xxx” xxx可以是字符串、对象、数组

      • 字符串写法适用于:类名不确定,要动态获取。

      • 对象写法适用于:要绑定多个样式,个数不确定,名字也不确定

      • 数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。

  2. style样式

    • :style="{fontSize: xxx}"其中xxx是动态值。
    • :style="[a,b]"其中a、b是样式对象。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>绑定样式</title>
		<style>
			.basic{
				width: 400px;
				height: 100px;
				border: 1px solid black;
			}
			
			.happy{
				border: 4px solid red;;
				background-color: rgba(255, 255, 0, 0.644);
				background: linear-gradient(30deg,yellow,pink,orange,yellow);
			}
			.sad{
				border: 4px dashed rgb(2, 197, 2);
				background-color: gray;
			}
			.normal{
				background-color: skyblue;
			}
		</style>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
			<div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/><br/>

			<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
			<div class="basic" :class="classArr">{{name}}</div> <br/><br/>

			<!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
			<div class="basic" :class="classObj">{{name}}</div> <br/><br/>

			<!-- 绑定style样式--对象写法 -->
			<div class="basic" :style="styleObj">{{name}}</div> <br/><br/>
			<!-- 绑定style样式--数组写法 -->
			<div class="basic" :style="styleArr">{{name}}</div>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false
		
		const vm = new Vue({
			el:'#root',
			data:{
				name:'alvis',
				mood:'normal',
				classArr:['basic','happy','sad'],
				classObj:{
					basic:false,
					happy:false,
				},
				styleObj:{
					fontSize: '40px',
					color:'red',
				},
				styleObj2:{
					backgroundColor:'orange'
				},
				styleArr:[
					{
						fontSize: '40px',
						color:'blue',
					},
					{
						backgroundColor:'gray'
					}
				]
			},
			methods: {
				changeMood(){
					const arr = ['happy','sad','normal']
					const index = Math.floor(Math.random()*3)
					this.mood = arr[index]
				}
			},
		})
	</script>
	
</html>

9.条件渲染

9.1 v-if

写法:

(1).v-if=“表达式”

(2).v-else-if=“表达式”

(3).v-else=“表达式”

适用于:切换频率较低的场景。

特点:不展示的DOM元素直接被移除。

注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”。

9.2 v-show

写法:v-show=“表达式”

适用于:切换频率较高的场景。

特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉

9.3 备注:

使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。

<div id="root">
    <h2>当前的n值是:{{n}}</h2>
    <button @click="n++">点我n+1</button>
    <!-- 使用v-show做条件渲染 -->
    <!-- <h2 v-show="false">欢迎来到{{name}}</h2> -->
    <!-- <h2 v-show="1 === 1">欢迎来到{{name}}</h2> -->

    <!-- 使用v-if做条件渲染 -->
    <!-- <h2 v-if="false">欢迎来到{{name}}</h2> -->
    <!-- <h2 v-if="1 === 1">欢迎来到{{name}}</h2> -->

    <!-- v-else和v-else-if -->
    <!-- <div v-if="n === 1">Angular</div>
    <div v-else-if="n === 2">React</div>
    <div v-else-if="n === 3">Vue</div>
    <div v-else>哈哈</div> -->

    <!-- v-if与template的配合使用 -->
    <template v-if="n === 1">
        <h2>你好</h2>
        <h2>alvis</h2>
        <h2>北京</h2>
    </template>

</div>

10.列表渲染

10.1 v-for指令

  1. 用于展示列表数据
  2. 语法:v-for="(item, index) in xxx" :key=“yyy”
  3. 可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <!-- 遍历数组 -->
        <h2>人员列表(遍历数组)</h2>
        <ul>
            <li v-for="(p,index) of persons" :key="index">
                {{p.name}}-{{p.age}}
            </li>
        </ul>

        <!-- 遍历对象 -->
        <h2>汽车信息(遍历对象)</h2>
        <ul>
            <li v-for="(value,k) of car" :key="k">
                {{k}}-{{value}}
            </li>
        </ul>

        <!-- 遍历字符串 -->
        <h2>测试遍历字符串(用得少)</h2>
        <ul>
            <li v-for="(char,index) of str" :key="index">
                {{char}}-{{index}}
            </li>
        </ul>

        <!-- 遍历指定次数 -->
        <h2>测试遍历指定次数(用得少)</h2>
        <ul>
            <li v-for="(number,index) of 5" :key="index">
                {{index}}-{{number}}
            </li>
        </ul>
    </div>

    <script type="text/javascript">
        Vue.config.productionTip = false

        new Vue({
            el:'#root',
            data:{
                persons:[
                    {id:'001',name:'张三',age:18},
                    {id:'002',name:'李四',age:19},
                    {id:'003',name:'王五',age:20}
                ],
                car:{
                    name:'奥迪A8',
                    price:'70万',
                    color:'黑色'
                },
                str:'hello'
            }
        })
    </script>

10.2 key的原理

面试题:react、vue中的key有什么作用?(key的内部原理)

1.虚拟DOM中key的作用

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

2.对比规则:
  • 旧虚拟DOM中找到了与新虚拟DOM相同的key:

    ①若虚拟DOM中内容没变, 直接使用之前的真实DOM!

    ②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。

  • 旧虚拟DOM中未找到与新虚拟DOM相同的key

    创建新的真实DOM,随后渲染到到页面。

3.用index作为key可能会引发的问题:
  • 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
  • 如果结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题。
4.开发中如何选择key?:
  • 最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。

  • 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。

10.3 列表过滤

<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>人员列表</h2>
			<input type="text" placeholder="请输入名字" v-model="keyWord">
			<ul>
				<li v-for="(p,index) of filPerons" :key="index">
					{{p.name}}-{{p.age}}-{{p.sex}}
				</li>
			</ul>
		</div>

		<script type="text/javascript">
			Vue.config.productionTip = false
			
			//用watch实现
			//#region 
			/* new Vue({
				el:'#root',
				data:{
					keyWord:'',
					persons:[
						{id:'001',name:'马冬梅',age:19,sex:'女'},
						{id:'002',name:'周冬雨',age:20,sex:'女'},
						{id:'003',name:'周杰伦',age:21,sex:'男'},
						{id:'004',name:'温兆伦',age:22,sex:'男'}
					],
					filPerons:[]
				},
				watch:{
					keyWord:{
						immediate:true,
						handler(val){
							this.filPerons = this.persons.filter((p)=>{
								return p.name.indexOf(val) !== -1
							})
						}
					}
				}
			}) */
			//#endregion
			
			//用computed实现
			new Vue({
				el:'#root',
				data:{
					keyWord:'',
					persons:[
						{id:'001',name:'马冬梅',age:19,sex:'女'},
						{id:'002',name:'周冬雨',age:20,sex:'女'},
						{id:'003',name:'周杰伦',age:21,sex:'男'},
						{id:'004',name:'温兆伦',age:22,sex:'男'}
					]
				},
				computed:{
					filPerons(){
						return this.persons.filter((p)=>{
							return p.name.indexOf(this.keyWord) !== -1
						})
					}
				}
			}) 
		</script>

10.4 列表排序

<!-- 准备好一个容器-->
<div id="root">
    <h2>人员列表</h2>
    <input type="text" placeholder="请输入名字" v-model="keyWord">
    <button @click="sortType = 2">年龄升序</button>
    <button @click="sortType = 1">年龄降序</button>
    <button @click="sortType = 0">原顺序</button>
    <ul>
        <li v-for="(p,index) of filPerons" :key="p.id">
            {{p.name}}-{{p.age}}-{{p.sex}}
            <input type="text">
        </li>
    </ul>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false

    new Vue({
        el:'#root',
        data:{
            keyWord:'',
            sortType:0, //0原顺序 1降序 2升序
            persons:[
                {id:'001',name:'马冬梅',age:30,sex:'女'},
                {id:'002',name:'周冬雨',age:31,sex:'女'},
                {id:'003',name:'周杰伦',age:18,sex:'男'},
                {id:'004',name:'温兆伦',age:19,sex:'男'}
            ]
        },
        computed:{
            filPerons(){
                const arr = this.persons.filter((p)=>{
                    return p.name.indexOf(this.keyWord) !== -1
                })
                //判断一下是否需要排序
                if(this.sortType){
                    arr.sort((p1,p2)=>{
                        return this.sortType === 1 ? p2.age-p1.age : p1.age-p2.age
                    })
                }
                return arr
            }
        }
    }) 

</script>

10.5 Vue监视数据的原理

  1. vue会监视data中所有层次的数据。

  2. 如何监测对象中的数据?

    • 通过setter实现监视,且要在new Vue时就传入要监测的数据。

      (1).对象中后追加的属性,Vue默认不做响应式处理

      (2).如需给后添加的属性做响应式,请使用如下API:

      Vue.set(target,propertyName/index,value) 或 vm.$set(target,propertyName/index,value)

  3. 如何监测数组中的数据?

    • 通过包裹数组更新元素的方法实现,本质就是做了两件事:

      (1).调用原生对应的方法对数组进行更新。

      (2).重新解析模板,进而更新页面。

  4. 在Vue修改数组中的某个元素一定要用如下方法:

​ 1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()

​ 2.Vue.set() 或 vm.$set()

  1. 特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!

11.收集表单数据

  • 若:,则v-model收集的是value值,用户输入的就是value值。

  • 若:,则v-model收集的是value值,且要给标签配置value值。

  • 若:

    • 1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
    • 2.配置input的value属性:
      • (1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
      • (2)v-model的初始值是数组,那么收集的的就是value组成的数组
  • 备注:v-model的三个修饰符:

    • lazy:失去焦点再收集数据
    • number:输入字符串转为有效的数字
    • trim:输入首尾空格过滤
<div id="root">
    <form @submit.prevent="demo">
        账号:<input type="text" v-model.trim="userInfo.account"> <br/><br/>
        密码:<input type="password" v-model="userInfo.password"> <br/><br/>
        年龄:<input type="number" v-model.number="userInfo.age"> <br/><br/>
        性别:
        男<input type="radio" name="sex" v-model="userInfo.sex" value="male">
        女<input type="radio" name="sex" v-model="userInfo.sex" value="female"> <br/><br/>
        爱好:
        学习<input type="checkbox" v-model="userInfo.hobby" value="study">
        打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
        吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
        <br/><br/>
        所属校区
        <select v-model="userInfo.city">
            <option value="">请选择校区</option>
            <option value="beijing">北京</option>
            <option value="shanghai">上海</option>
            <option value="shenzhen">深圳</option>
            <option value="wuhan">武汉</option>
        </select>
        <br/><br/>
        其他信息:
        <textarea v-model.lazy="userInfo.other"></textarea> <br/><br/>
        <input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://www.baidu">《用户协议》</a>
        <button>提交</button>
    </form>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false

    new Vue({
        el:'#root',
        data:{
            userInfo:{
                account:'',
                password:'',
                age:18,
                sex:'female',
                hobby:[],
                city:'beijing',
                other:'',
                agree:''
            }
        },
        methods: {
            demo(){
                console.log(JSON.stringify(this.userInfo))
            }
        }
    })
</script>

12.过滤器

功能: 对要显示的数据进行特定格式化后再显示 (适用于一些简单逻辑的处理)

注意: 并没有改变原本的数据, 是产生新的对应的数据

语法:

​ 1.注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}

​ 2.使用过滤器:{{ xxx | 过滤器名}} 或 v-bind:属性 = “xxx | 过滤器名”

备注:

​ 1.过滤器也可以接收额外参数、多个过滤器也可以串联

​ 2.并没有改变原本的数据, 是产生新的对应的数据

<div id="root">
    <h2>显示格式化后的时间</h2>
    <!-- 计算属性实现 -->
    <h3>现在是:{{fmtTime}}</h3>
    <!-- methods实现 -->
    <h3>现在是:{{getFmtTime()}}</h3>
    <!-- 过滤器实现 -->
    <h3>现在是:{{time | timeFormater}}</h3>
    <!-- 过滤器实现(传参) -->
    <h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>
    <h3 :x="msg | mySlice">尚硅谷</h3>
</div>

<div id="root2">
    <h2>{{msg | mySlice}}</h2>
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    //全局过滤器
    Vue.filter('mySlice',function(value){
        return value.slice(0,4)
    })

    new Vue({
        el:'#root',
        data:{
            time:1621561377603, //时间戳
            msg:'你好,alvis'
        },
        computed: {
            fmtTime(){
                return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
            }
        },
        methods: {
            getFmtTime(){
                return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
            }
        },
        //局部过滤器
        filters:{
            timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
                // console.log('@',value)
                return dayjs(value).format(str)
            }
        }
    })

    new Vue({
        el:'#root2',
        data:{
            msg:'hello,alvis!'
        }
    })
</script>

13.内置指令与自定义指令

13.1 常用内置指令

  1. v-text : 更新元素的 textContent

    作用:向其所在的节点中渲染文本内容。

    与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。

  2. v-html : 更新元素的 innerHTML

    作用:向指定节点中渲染包含html结构的内容。

    与插值语法的区别:

    ​ (1).v-html会替换掉节点中所有的内容,{{xx}}则不会。

    ​ (2).v-html可以识别html结构。

    严重注意:v-html有安全性问题!!!!

    ​ (1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。

    ​ (2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!

  3. v-if : 如果为 true, 当前标签才会输出到页面

  4. v-else: 如果为 false, 当前标签才会输出到页面

  5. v-show : 通过控制 display 样式来控制显示/隐藏

  6. v-for : 遍历数组/对象

  7. v-on : 绑定事件监听, 一般简写为@

  8. v-bind : 绑定解析表达式, 可以省略 v-bind

  9. v-model : 双向数据绑定

  10. v-cloak : 防止闪现, 与 css 配合: [v-cloak] { display: none }

  11. v-once:

    1.v-once所在节点在初次动态渲染后,就视为静态内容了。

    2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。

  12. v-pre指令:

    1.跳过其所在节点的编译过程。

    2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。

cookie中字段加httponly,限制读取权限

13.2 自定义指令

13.2.1 全局指令
Vue.directive(指令名,配置对象)  或   Vue.directive(指令名,回调函数)
13.2.2 局部指令
new Vue({															
	directives:{指令名:配置对象
})

或

new Vue({	
	directives{指令名:回调函数
})
<div id="root">
    <h2>{{name}}</h2>
    <h2>当前的n值是:<span v-text="n"></span> </h2>
    <!-- <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2> -->
    <h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
    <button @click="n++">点我n+1</button>
    <hr/>
    <input type="text" v-fbind:value="n">
</div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false

    //定义全局指令
    /* Vue.directive('fbind',{
			//指令与元素成功绑定时(一上来)
			bind(element,binding){
				element.value = binding.value
			},
			//指令所在元素被插入页面时
			inserted(element,binding){
				element.focus()
			},
			//指令所在的模板被重新解析时
			update(element,binding){
				element.value = binding.value
			}
		}) */

    new Vue({
        el:'#root',
        data:{
            name:'尚硅谷',
            n:1
        },
        directives:{
            //big函数何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。
            /* 'big-number'(element,binding){
					// console.log('big')
					element.innerText = binding.value * 10
				}, */
            big(element,binding){
                console.log('big',this) //注意此处的this是window
                // console.log('big')
                element.innerText = binding.value * 10
            },
            fbind:{
                //指令与元素成功绑定时(一上来)
                bind(element,binding){
                    element.value = binding.value
                },
                //指令所在元素被插入页面时
                inserted(element,binding){
                    element.focus()
                },
                //指令所在的模板被重新解析时
                update(element,binding){
                    element.value = binding.value
                }
            }
        }
    })

</script>

注意点:

  1. 自定义指令若出现多个单词,用-分隔,定义时加引号

    <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2>
    
    'big-number'(element,binding){
        element.innerText = binding.value * 10
    }
    
  2. 指令里面的this是window

  3. 指令定义时不加v-,但使用时要加v-

14.生命周期

14.1 概览

  • 又名:生命周期回调函数、生命周期函数、生命周期钩子。
  • 是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
  • 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
  • 生命周期函数中的this指向是vm 或 组件实例对象。

14.2 8个钩子函数

初始化显示

  • beforeCreate() :将要创建数据监测、数据代理
  • created() :创建完毕
  • beforeMount() :将要挂载
  • mounted() :挂载完毕(重要的钩子)

更新状态: this.xxx = value

  • beforeUpdate() :将要更新
  • updated():更新完毕

销毁vue 实例: vm.$destory()

  • beforeDestory() :将要销毁(重要的钩子)

  • destoryed():销毁完毕

    销毁后借助Vue开发者工具看不到任何信息。

    销毁后自定义事件会失效,但原生DOM事件依然有效。

    一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。

14.3 常用的生命周期方法

  1. mounted(): 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
  2. beforeDestory(): 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。

更多推荐

Vue学习(一)—— vue核心