Vue学习笔记02 数据代理-计算属性-key的作用和原理-Vue的监视原理-过滤器

Vue学习笔记02

vm的data数据发生变化就会重新解析模板

数据代理

什么是数据代理?
通过一个对象代理另一个对象中属性的操作(间接的操作)

//代理模式
let obj ={x:100}
let obj2 ={y:200}
Object.defineProperty(obj2,'x',{
	get(){
		return obj.x;
	},
	set(value){
		obj.x = value;
	}
})

在浏览器控制台查看的时候会显示…,点击只会才可以看见

在这里插入图片描述

Vue中的数据代理

我们发现vue的实例上,我们写在name里面的变量也是这样的

const vm=new Vue({
       el:'#root',
       data:{
          name:'指令语法',
       }
});

在这里插入图片描述

Vue中的数据代理
通过vm对象来代理data对象中属性的操作

data中所有的属性,最后都出现在vm身上

通过vm读name读的是data中的name,也就是修改的vm._data.name
通过vm改name改的是data中的name,也就是修改的vm._data.name

vm身上所有的属性及Vue原型上的所有属性,在Vue模板中都能使用

所以通过数据代理,更加方便地操作data中的数据,直接使用{{name}}而不用使用{{_data.name}}

基本原理
通过Object.defineProperty()把data对象中所有属性添加到vm上。
为每一个添加到vm上的属性,都指定一个getter/setter。
在getter/setter内部去操作data中对应的属性。

vm.data===date
在这里插入图片描述

事件处理

语法:v-on:事件=“函数名”
可以简写为@事件=“函数名”

使用@事件=“函数名(传参)"传参时,可以使用$event传递事件对象
使用@事件=“函数名"`不传参时,默认第一个参数就是事件对象

事件的回调需要配置在methods对象中,methods里的函数最终会在vm上

<button v-on:click="showInfo1">不传参</button>
<button @click="showInfo2(这里可以传参)">传参</button>

//js
const vm=new Vue({
       el:'#root',
       methonds:{
		showInfo(event){//this指向vm
      	 }
		}
});

事件修饰符

@事件.prevent 阻止该默认事件
@事件.stop阻止该事件冒泡
@事件.once事件只触发一次
@事件.capture使用事件的捕获模式,在捕获阶段处理事件(一般是在冒泡阶段处理事件)
@事件.self只有event,target是当前操作的元素时才触发事件
@事件.passive事件的默认行为立即执行,无需等待事件回调结束

wheel 鼠标滚轮滚动触发 scroll 滚动条滚动触发

按键别名

键盘事件
@keydown 按下键盘触发
@keyup 按键抬起来触发(常用)

Vue常用的按键别名
回车 => enter
删除 => delete 捕获“删除”和“退格”键
退出 => esc
空格 => space
换行 => tab tab键按下之后焦点会立即边走,所以配合keydown使用
上 => up
下 => down
左 => left
右 => right

案例
@keyup.enter 回车键抬起来的时候触发

每个按键都有一个名字和编码
回车 e.key:Enter e.keycode:13

而上面的vue别名只是方便我们写,所以说@keyup.Enter也可以实现上述案例

注意由多个单词组成的如CapsLock在标签在中要使用@key.caps-lock

js相关用驼峰,css相关用-写法

系统修饰键:ctrl、alt、shift、meta(home)

1.配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
2.配合keydown使用:正常触发

.支持链式调用
比如:@click.prevent.stop先阻止默认行为,再阻止冒泡
比如ctrl + y触发@keydown.ctrl.Y

简写整理

全程简写
v-model:value只用于表单的value属性 v-modal
v-bind:属性名:属性名
v-on:事件@事件

计算属性与监视

data中的数据一旦发生变化,Vue模板会重新解析一遍,如果此时插值语法里面有函数一定会重新调用一遍,这样效率非常的低。

计算属性computed

对于Vue来说,data里的数据就是属性
计算属性:根据已有的属性生成新的属性

计算属性的调用时机
1.初始化时调用
2.计算所依赖的数据发生变化

说明
1.计算属性函数是通过函数将结果作为计算属性的值,把该计算属性挂在vm上,在模板中不能直接调用函数
2.初次读取计算属性和依赖的数据发生变化时计算属性会重新计算,其他时候使用缓存

new Vue({
   el:'#root',
   data:{
       firstName:'ran',
       lastName:'an'
    },
    computed:{//类似代理,通过firstName和lastName修改fullName
    	fullName:{ 
			get(){//读取fullName时调用
				return this,firstName + this.lastName
			},
			set(val){
				this.firstName = ;
				this.lastName = ;
			}//fullName修改时调用
		}
    }
});

计算属性的简写,前提只读不改
fullName函数是通过此函数将结果作为fullName属性的值挂在vm上,所以在模板中不能直接调用该函数

new Vue({
   el:'#root',
   data:{
       firstName:'ran',
       lastName:'an'
    },
    computed:{
    	fullName(){//fullName函数是通过此函数将结果作为fullName属性的值挂在vm上,所以在模板中不能直接调用该函数
				return this,firstName + this.lastName
			}
		}
    }
});

监视属性watch

1.当监视的属性发生变化时,handler(newVal,oldVal)函数调用,初始化时不调用
2.可以监视data和computed里的属性

写法1:创建实例时已经知道了监视的属性

new Vue({
   el:'#root',
   data:{
       firstName:'ran',
       lastName:'an'
    },
    watch:{
 		isHot:{//固定配置
 		    immediate:false; //默认false,初始化时调用handler函数
 			//当监视的属性发生变化时,handler调用
			handler(newVal,oldVal){}
			}
		}
    
});

写法2

vm.$watch('isHot',{配置信息})

监视属性得简写,前提只有handler函数

watch:{
	isHot(newVal,oldVal){}
}
vm.$watch('isHot',function(newVal,oldVal){//handler函数})
深度监视

Vue中的watch默认不监测对象内部值的改变(一层)
配置deep:true可以检测对象内部值得改变(多层)

需求:监视numbers对象里的a属性

new Vue({
   el:'#root',
   data:{
      numbers:{
		a:1,
		b:1
		}
    },
    watch:{
 		//numbers.a:{这样报错因为属性都是字符串形式,只是我们平时没写字符串,但是会自动转换成字符串
 		'numbers.a'{
			handler(newVal,oldVal){}
			}
		}
});

需求:监视numbers对象里的a和b属性

//监控的是numbers这个对象,也就是地址的变化,a,b的变化不会触发
numbers:{
	handler(newVal,oldVal){}
}
//正确写法
numbers:{
	deep:true,
	handler(newVal,oldVal){}
}
监视属性和计算属性的区别

computed能完成的,watch都可以完成

computedwatch
1.初始化时调用
2.计算所依赖的数据发生变化
默认是监视的属性发生变化时调用,可以通过设置immediate让初始化时调用
不可以进行异步操作可以进行异步操作

class与style绑定

动态绑定class类

<!--解析之后会汇总类 class='正常的类 需要动态改变的'-->
<div class='正常的类' :class=’需要动态改变的‘>

给class绑定的变量
字符串:样式的类名不确定,需要动态指定
数组:绑定样式的个数不确定,名字也不确定
对象:个数确定名字确定,需要动态确定是否使用

data:{
	classArr:['style1','style2'],
	classObj:{
		style1:false,//false代表不使用
		style2:false
	}
}

style绑定

<div :style="styleObj">
//js
data:{
	styleObj:{
		fontSize:'40px' 
	}
}

v-if和v-show

v-if的原理
根据判断条件来动态的进行增删DOM元素
v-show的原理
根据判断条件来动态的进行显示和隐藏元素

指令描述区别适用场景
v-if直接删除,在文档中看不见为真时才生成节点渲染到页面,为假时销毁。切换成本高1.适用于不频繁切换的
2.适用于多种条件场景
v-showdisplay=none,在文档中还是看得见初始渲染时渲染,通过切换css实现显示和隐藏初始化成本高,适用于频繁切换的

注意
1.v-if,v-else-if,v-else 三个标签需要挨着写,中间不能插入其余标签
2.template 标签可以和v-if指令配合,不能和·v-show·配合

<template>标签在渲染时不会被渲染
好处:使用该标签不会破环结构

列表渲染

v-for

语法:v-for="(item,index) in 数组"
根据数组的元素个数循环生成标签。item对应的是数组中的一个元素,index对应数组的下标。

语法:v-for="(val,key) in 对象"

<ul id="root">
        <li v-for="(person,index) in persons" :key='index'>{{person.name}}-{{person.age}}</li>
</ul>

<script>
new Vue({
   el:'#root',
   data:{
       persons:[
          {id:'001',name:'张山',age:18},
          {id:'002',name:'李山',age:19},
          {id:'003',name:'刘山',age:20}
               ]},
});

key的作用和原理 ★

作用:减少不必要的DOM操作,提高更新效率

使用index作为key时,如果对数据进行操作破坏了顺序
1.效率低,导致已有的虚拟DOM不能复用
2.如果有输入类DOM,错误DOM更新,界面有问题
在这里插入图片描述

原因在这里插入图片描述

vue中的key有什么作用

虚拟DOM中的key的作用

  1. key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据[新数据]生成[新的虚拟DOM]
  2. 随后Vue进行[新虚拟DOM]与[旧虚拟DOM]的差异比较,比较规则
    • [旧虚拟DOM]中找与[新虚拟DOM]相同的key
      如果[虚拟DOM]中内容没变,直接使用之前的[真实DOM]
      如果[虚拟DOM]中内容变了,则生成新的真实DOM,随后替换掉页面中之前的[真实DOM]
    • 如果没找到,创建新的真实DOM,随后渲染到页面

如何选择key
1.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key没有问题
2.最好使用唯一标识
3.如果不显示设置,默认使用index作为key

列表过滤

/*html*/
<ul id="root">
        <input type="text" placeholder="请输入名字" v-model="keyWord">
        <li v-for="(person,index) of persons" :key='person.id'>{{person.name}}-{{person.age}}</li>
    </ul>
</body>
//js
 new Vue({
     el:'#root',
     data:{
       keyWord:'',
       persons:[
           {id:'001',name:'马冬梅',age:18},
           {id:'002',name:'周冬雨',age:19},
           {id:'003',name:'周杰伦',age:20}
       ]
}

在这里插入图片描述

思考过程
当用户输入的关键词发生变化时,就需要过滤。
怎么观察到关键词变化?watch和computed

watch实现

<li v-for="(person,index) of filPersons" :key='person.id'>{{person.name}}-{{person.age}}</li>
    
new Vue({
    el:'#root',
        data:{
            keyWord:'',
            persons:[
                {id:'001',name:'马冬梅',age:18},
                {id:'002',name:'周冬雨',age:19},
                 {id:'003',name:'周杰伦',age:20}
            ],
            filPersons:[]//用于存放过滤之后的数组,不能直接修改原数组,不然数据减少了就恢复不回来了
             },
             watch:{
                keyWord:{
                    immediate:true,//初始化时就调用handler,这样原始的filPersons就有值了
                    handler(newVal){
                    this.filPersons = this.persons.filter(item =>
                         item.name.indexOf(newVal)!== -1
                    )}
             }
            }
});

computed实现

计算属性的调用时机
1.初始化时调用
2.计算所依赖的数据发生变化

data:{
     keyWord:'',
     persons:[
         {id:'001',name:'马冬梅',age:18},
         {id:'002',name:'周冬雨',age:19},
         {id:'003',name:'周杰伦',age:20}
     ]
}computed:{
	filPersons(){
		return  this.filPersons = this.persons.filter(item =>
                           item.name.indexOf(this.keyWord)!== -1
                    )
	}
}
表单的注意事项

1.复选框 Vue默认读取的是checked属性,需要指定value值,且绑定的值要是数组。
如果只有一个选择框,对于我们来说只需要是否选中,所以可以不用指定value,也不用绑定数组。
2.v-model的三个修饰符
number 输入的数据是数字类型
lazy 失去焦点的瞬间收集
trim 去除开头的空格

列表排序

需求
列表的排序是针对过滤之后的元素进行排序。

<ul id="root">
        <h1>人员列表</h1>
        <input type="text" placeholder="请输入名字" v-model="keyWord">
        <button @click="sortType=2">年龄升序</button>
        <button @click="sortType=1">年龄降序</button>
        <button @click="sortType=0">年龄原顺序</button>
        <li v-for="(person,index) of filPersons" :key='person.id'>{{person.name}}-{{person.age}}</li>
</ul>

new Vue({
     el:'#root',
     data:{
           sortType:0,//0代表原顺序 1 降序 2 升序
           keyWord:'',
           persons:[
               {id:'001',name:'马冬梅',age:18},
               {id:'002',name:'周冬雨',age:19},
               {id:'003',name:'周杰伦',age:22},
               ]
           },        
          computed:{
              filPersons(){
                    //过滤
                  const arr=this.persons.filter(item => item.name.indexOf(this.keyWord)!== -1)
                    //判断是否需要排序
                  if(this.sortType){
                       arr.sort((a,b)=> this.sortType===1?b.age-a.age:a.age-b.age)
                    }
                    return arr;
                }}
   });

Vue监测数据改变的原理

Vue默认的监视是监视数据data改变,更新模板
watch配置是给程序员用的

更新时存在的问题

数据改变了,Vue也会监测到数据改变,模板会更新
数组中的元素是对象,对象里面的属性有getter和setter

//起作用了
this.persons[0].name='马老师';
this.persons[0].age= 50;

这种写法数据改变了,但是Vue没有监测到改变了,所以模板不会被更新。不能通过索引直接改变数组

this.persons[0]={id:'001',name:'马老师',age:50}
Vue监测对象改变的原理

data里面的name被修改 -> 调用vm._date里的setter->重新解析模板->生成新的虚拟DOM->新旧DOM对比->更新页面

vm.data===date
在这里插入图片描述

对data中的对象数据进行加工
加工的目的:响应式

//简单写法
//创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data); //obs复制了data的属性,并添加了get、set方法
//准备一个vm实例对象
let vm ={};

//赋值从右往左
vm._data = data= obs;

//Observer构造函数
function Observer(obj){
	//1.汇总对象中的所有属性
	const.keys = Object.keys(obj);
	keys.forEach((k)=>{
		Object.defineProperty(this,k,{
			get(){
			  return obj[k];
			}
			set(val){
				//这里更新页面等操作
				obj[k]=val
			}
		})
	})
}
Vue.set()/vm.$set()

Vue.set(target,key,val)/vm.$set(target,key,val)

向响应式对象(数组)中添加一个没有的property,并确保整个新的property也是响应式(也用于setter,getter)的,且触发视图更新。
给data中的对象(数组)添加属性

局限:不能给data追加属性
target不能是vm或者vm._data

Vue监测数组改变的原理

数组没有set与get方法,所以直接修改索引值不能被Vue监测到 --> 不能通过索引值修改数组

修改原数组的方法
push,pop,shift, unshift ,splice,sort,reverse

使用以上7种会修改原数组的方法,Vue才承认修改了数组
这7个方法Vue进行了重写
1.调用push
2.重新解析模板。重新生成虚拟DOM ->新旧DOM对比->更新页面

总结 ★

如果监测对象中的属性修改?
通过setter实现监视,且要在new Vue时就传入要监测的数据。

1.对象中后追加的属性,Vue默认不做响应式处理,不会渲染到页面
2.使用Vue.set(target,key,val)/vm.$set(target,key,val)可以给后添加的属性做响应式

target不能是vm或者vm._data

如何监测数组中的元素修改?
通过包裹数组更新元素的方法实现,本质是做了两件事
1.调用原生对应的方法对数组进行了修改
2.重新解析模板,进而更新界面

过滤器(Vue3.0移除)

作用:给数据进行加工

模板中使用
{{数据|过滤器名字}} //相当于把数据作为参数传给过滤器
{{数据|过滤器名字(传参)}}//这个参数作为函数的第二个参数
{{数据|过滤器名字|过滤器2}} //管道符可连续传递

//过滤器的本质就是函数
new Vue({
	filters:{
	 timeFormater(value){
			return
		},
	  过滤器2
	}
})

//全局过滤器1
Vue.filter(过滤器名,function);
//全局过滤器2
Vue.filter(过滤器名,function);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值