计算属性
- 定义:要用的属性不存在,要通过已经有的属性计算得来
- 原理:底层借助了Object.defineproperty方法提供的getter和setter。
get函数什么时候执行?
(1)、初次读取时会执行一次
(2)、当依赖的数据发生改变时会被再次调用。
- 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
备注:
(1)、计算属性最终会出现在vm上,直接读取即可。
(2)、如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
// 准备一个容器
<div id="root">
姓:<input type="text" v-model="firstName"> <br/>
名:<input type="text" v-model="lastName"> <br/>
姓名:<span>{{fullName}}</span>
</div>
computed:{
fullName:{
// get有什么用? 当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
// get什么时候调用? 1、初次读取fullName时,2、所依赖的数据发生变化时。
get(){
console.log('get被调用了')
// console.log(this) // 此处的this是vm
// 切记 get 不要写成箭头函数,否则this指向window 而不是 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]
}
}
}
计算属性的简写
前提:只考虑读取,不考虑修改的情况下,但是我们一般情况下都是读取。
computed:{
// 直接将属性变成一个方法,当成一个getter使用
fullName(){
console.log('get被调用了')
return this.firstName + '-' + this.lastName
}
}
监视属性
- 监视属性:new Vue时传入watch配置 或者使用 vm.$watch监视
- 当被监视的属性发生变化时,回调函数自动调用,进行相关操作
- 监视的属性必须存在,才能进行监视!!
<br/>
1、使用计算属性实现切换天气
// 准备一个容器
<div id="root">
<h2>今天天气很{{info}}</h2>
// 绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句
// <button @click="isHot = !isHot ">切换天气</button>
<button @click="changeWeather">切换天气</button>
</div>
data:{
isHot:true,
},
computed:{
info(){
return this.isHot ? '炎热' : '凉爽'
}
},
methods:{
changeWeather(){
this.isHot = !this.isHot
}
}
<br/>
2、使用监视属性
// 准备一个容器
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click="changeWeather">切换天气</button>
</div>
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实例在外部监视属性
vm.$watch('isHot'{
immediate:true, // 初始化时让handler调用一下
// handler什么时候调用? 当isHot发生变化时。
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
})
监视属性的简写
前提:不需要其他配置属性时,如deep、immediate,只使用handler()的功能
// 正常写法
watch:{
isHot:{
// deep:true,
immediate:true, // 初始化时让handler调用一下
// handler什么时候调用? 当isHot发生变化时。
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
}
}
// 简写方式
watch:{
isHot(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
}
vm.$watch的简写方式
//正常方式
vm.$watch('isHot'{
immediate:true, // 初始化时让handler调用一下
deep:true,
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
})
// 简写方式
// 注意function不能写成箭头函数,否则this的指向不是vm,而是window
vm.$watch('isHot',function(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
)
<br/>
深度监测
- Vue中的watch默认不监测对象内部值的改变(一层)
- 配置deep:true 可以监测对象内部值改变(多层)
- 备注:
(1)、Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
(2)、使用watch时根据数据的具体结构,决定是否采用深度监视。
// 准备一个容器
<div id="root">
<h2>a的值是:{{numbers.a}}</h2>
<button @click="numbers.a++">点我a+1</button>
<h2>b的值是:{{numbers.b}}</h2>
<button @click="numbers.b++">点我b+1</button>
</div>
data:{
numbers:{
a:1,
b:1
}
},
watch:{
//监测多级结构中某一个属性的变化
'numbers.a':{
handler(){
console.log('a被改变了')
}
},
//监测多级结构中所有属性的变化
numbers:{
deep:true,
handler(){
console.log('numberss被改变了')
}
}
}
<br/>
computed 与 watch 比较
computed 与 watch之间的区别:
- computed能完成的功能,watch都可以完成
- watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作
两个重要的小原则:
- 所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象
- 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、promise的回调函数),最好写成箭头函数,这样this的指向才是vm 或 组件实例对象。
<br/>
绑定样式
class样式
- 格式:【:class = "xxx"】 xxx可以是字符串、对象、数组
字符串写法适用于:类名不确定,需要动态获取。
- 对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
- 数组写法适用于:要绑定多个样式,个数确定,名字也确定,但是不确定用不用。
style样式
- 格式:【:style = "xxx"】 xxx可以是对象、数组
- 对象的写法:样式属性如果是单个词组则小写,多个词组使用驼峰式命名。如【:style=“{fontSize:xxx}”】。
- 数组的写法:数组里面是一个一个的对象。如【:style=“[a , b]”】,a:{fontSize:xxx},b:{color:red}。
1、绑定class样式
// 准备一个容器
<div id="root">
<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
<div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/>
<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
<div class="basic" :class="classArr" @click="changeMood">{{name}}</div> <br/>
<!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
<div class="basic" :class="classObj" @click="changeMood">{{name}}</div> <br/>
</div>
data:{
name: '样式绑定',
mood: 'normal', // 动态绑定的class名称
classArr: ['class1','class2','class3'], // 将多个class名称动态绑定在div上
classObj: {
class1: false, // 可以通过改变对象中的class的状态,决定该样式是否生效
class2: false
}
},
methods:{
changeMood(){
// 1、修改动态绑定的class,字符串方式
this.mood = 'happy'; // 将动态的class名称改为 happy
// -------------------------------------------------
// 2、修改动态绑定的class,随机方式
const arr = ['class1','class2','class3']
const index = Math.floor(Math.random()*3)
this.mood = arr[index]
}
}
<br/>
2、绑定style样式
<!-- 绑定style样式--对象写法 -->
<div class="basic" :style="styleObj" >{{name}}</div> <br/>
<!-- 绑定style样式--数组写法 -->
<div class="basic" :style="styleArr">{{name}}</div> <br/>
data:{
name: '样式绑定',
styleObj:{
fontSize: '40px',
color:'red',
},
styleArr:[
{
fontSize: '40px',
color:'red',
},
{
backgroundColor:'gray'
}
]
}
<br/>
条件渲染
- v-if
(1)、v-if=“表达式”
(2)、v-else-if=“表达式”
(3)、v-else=“表达式”
适用于:切换频率较低的场景
特点:将不展示的DOM元素直接移除
注意:v-if可以和v-else-if、v-else一起使用,但要求结构不能被“打断”。
<br/>
- v-show
写法:v-show=“表达式”
适用于:切换频率较高的场景
特点:将不展示的DOM元素使用样式来控制隐藏,不移除元素
<br/>
- 备注:1、使用v-if时,元素可能无法获取到,而使用v-show时一定可以获取到。
2、在vue中template可以和v-if配合使用,且不改变DOM的层级结构,但是template不能和v-show配合使用。
// 在使用v-if的时候可能出现以下这种情况,这种情况下当num满足num===1时还会继续执行下面的判断
<div v-if="num === 1">1</div>
<div v-if="num === 2">2</div>
<div v-if="num === 2">3</div>
// 建议使用以下方式,这种情况下当num满足num===1时就不会继续执行下面的判断了
<div v-if="num === 1">1</div>
<div v-else-if="num === 2">2</div>
<div v-else >3</div>
列表渲染
- v-for指令
(1)、用于展示列表数据
(2)、语法:v-for=“(item,index) in xxx” :key = "yyy"
(3)、可以遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
<div>
<!-- 在这里遍历的时候 可以用 【in】或者【of】 -->
<h2>人员列表(数组遍历)</h2>
<ul>
<li v-for="(p,index) of persons" :key="index">
{{p.name}}-{{p.age}}
</li>
</ul>
<!-- 遍历对象的时候,key就是【对象属性名称】,value就是【对象属性值】 -->
<h2>汽车信息(对象遍历)</h2>
<ul>
<li v-for="(value,key) of car" :key="key">
{{key}}-{{value}}
</li>
</ul>
<!-- 遍历字符串的时候,char就是【字符串的每个字符】,index就是【索引值】 -->
<h2>字符串测试(字符串遍历)</h2>
<ul>
<li v-for="(char,index) of str" :key="index">
{{char}}-{{index}}
</li>
</ul>
<!-- 遍历数字的时候,num就是【当前次数值,从1开始】,index就是【索引值】 -->
<h2>指定次数遍历</h2>
<ul>
<li v-for="(num,index) of 5" :key="index">
{{num}}-{{index}}
</li>
</ul>
</div>
data:{
persons:[
{name:'Bob',age:10},
{name:'Alice',age:11},
{name:'Jame',age:12}
],
car:{
name:'汽车名称',
price:'100W'
},
str:'hello',
}
key的作用
面试题:react、vue中的key有什么作用?(key的内部原理)
- 虚拟DOM中的作用:
key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
- 对比规则
(1)、旧虚拟DOM中找到了与新虚拟DOM相同的key:
1、若虚拟DOM中内容没变,直接使用之前的真实DOM;
2、若虚拟DOM内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
(2)、旧虚拟DOM中未找到与新虚拟DOM相同的key:创建新的真实DOM,随后渲染到页面。
用index作为key可能会引起的问题:
1、若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新 ==> 界面效果没有问题,但是效率低。
2、如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题。
- 开发中如何选择key?:
1、最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。
2、如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示。使用index作为key是没有问题的。
<br/>
<br/>