第一节、计算属性 (computed)
场景:tempalte中的{{}}尽量不要写复杂的业务逻辑,原因有2:
1 分层不好看
2 vue维护成本高(性能问题)
解决:计算属性
位置:和data、methods等并列
语法
<template>
能够使用自定义计算属性名
{{ }} 、指令,用法同data
</template>
export default {
computed:{
语法1:简单版(大部分情况)
自定义计算属性名(){
return 值
}
语法2:完整版
自定义计算属性名:{
get(){
return
},
set(val){
//val就是更新后的值
}
}
}
}
注意
1 计算属性字面意思-通过计算而得到属性
2 计算属性一般会依赖原始的数据(data)
3 计算属性也是属性,所以用法和data一致,也就意味着计算属性的取名不能和data冲突
4 计算属性依赖的数据发生改变后,则会重写计算—》重写渲染
5 计算属性首次访问时会自动执行一次(前置要求是该计算属性已经被用来渲染)
6 如果使用简单版语法,则修改计算属性的值,则会报错Computed property “xx” was assigned to but it has no setter.提醒你如果要更新计算属性的值,你应该用完整版语法,但是并不能真正的修改,只能·获取到更新后的值去做其他业务,换句话说,计算属性绝大部分都是用来渲染的,而不是让你直接来该值
7 自带缓存(第一次计算后会把结果放入缓存中,以后再次渲染相同的计算属性,则程序会直接把缓存中结果渲染到页面,也就不会重复执行计算属性里面业务),以后如果计算的数据海量并且会重复渲染,可以考虑使用计算属性
场景
根据条件进行渲染----》(比如购物车的总价,条件筛选)
Demo:
<template>
<div>
<!-- {{n1+n2}} -->
<!-- {{arr.filter(item=>item.age>=20).map(item=>item.name)}}
{{sum}}
{{newarr}}
<button @click="f">按钮</button>
</div>
</template>
<script>
export default {
data(){
return{
n1:1,
n2:2,
arr:[
{id:1,name:"斩杀",age:13},
{id:2,name:"万物",age:23},
{id:3,name:"李思",age:24},
],
}
},
computed:{
// sum:{
// get(){
// return this.n1+this.n2
// },
// set(val){
// console.log(val);
// }
// },
sum(){
console.log("执行了sum");
return this.n1+this.n2
},
newarr(){
return this.arr.filter(item=>item.age>=20).map(item=>item.name);
},
},
methods:{
f(){
this.n1=11
// this.sum=11
}
}
}
</script>
<style>
</style>
计算属性computed和方法methods的区别
1 计算属性是当成属性来使用,后面没有括号,而方法需要当成方法来使用,后面有括号
2 计算属性自带缓存,而方法没有缓存
第二节、双向绑定
最终目的:
更新视图----》达到自动更新数据的效果
更新数据----》达到更新视图的效果
自己来实现原理:
利用 input事件/change事件 + value
MVVM设计思想
- 来自于三个单词M-V-VM
- m:model—>模型—》数据
- v:view—>视图(页面)
- vm:viewModel—>视图模型引擎,该引擎能够监听到数据的变化,自动更新视图,也能够监听到视图的变化,从而更新数据(实现了双向绑定)
vue中可以通过v-model指令来实现(利用的MVVM思想)
v-model
- v-model是vue提供的一个用于双向绑定的思想,本质就是input/change事件+value的语法糖
注意:以后只要是表单元素100%会给一个v-model
1 文本框
注意:对于文本框/密码框而言,我们不能在标签上添加value属性
<template>
<div>
账号 <input type="text" v-model="user.username" ><br>
密码 <input type="password" v-model="user.password">
</div>
</template>
<script>
export default {
data(){
return{
user:{
username:"123",
password:""
}
}
},
}
</script>
<style>
</style>
2 单选框
<template>
<div>
账号 <input type="text" v-model="user.username" ><br>
密码 <input type="password" v-model="user.password"> <br>
性别
<input type="radio" v-model="user.gender" :value="1"> 男
<input type="radio" v-model="user.gender" :value="0"> 女
</div>
</template>
<script>
export default {
data(){
return{
user:{
username:"aaa",
password:"111",
gender:0
}
}
},
}
</script>
<style>
</style>
3 复选框
3.1 想要获取值 :绑定类型是数组
<input type="checkbox" v-model="user.hobby" value="吃饭"> 吃饭
<input type="checkbox" v-model="user.hobby" value="睡觉"> 睡觉
<input type="checkbox" v-model="user.hobby" value="打豆豆"> 打豆豆
user:{
username:"aaa",
password:"111",
gender:0,
hobby:[]
}
3.2 是否被勾选:绑定类型是boolean
<input type="checkbox" v-model="flag1" >
<input type="checkbox" v-model="flag2" >
<input type="checkbox" v-model="flag3" >
export default {
data(){
return{
flag1:false,
flag2:true,
flag3:false
}
4 下拉列表
<select v-model="user.clas">
<option value="a1">1班</option>
<option value="a2">2班</option>
<option value="a3">3班</option>
</select>
data(){
return{
user:{
username:"aaa",
password:"111",
gender:0,
hobby:["睡觉","打豆豆"],
clas:"a2"
},
}
},
v-model的修饰符
以下三个都是针对文本框/密码框
1 lazy
积极变消极,失焦时才会触发
<input type="text" v-model.lazy="user.username" >
2 number
能够帮你转成数字
<input type="text" v-model.number="user.username" >
3 trim
截取字符串两端的空格
第三节、扩展数api之reduce
功能之一:用来求和
语法:
数组.reduce((累加值,每个元素)=>{return ...},初始值)
//例子:求数组每个元素的累加和
let arr=[1,2,3,4]
let xx=arr.reduce((sum,item)=>{
return sum+item
},0)
console.log(xx);
let sum=0;
arr.forEach(item=>{
sum+=item
})
console.log(sum);
第四节、侦听器 watch
vue提供了侦听器来监听属性的变化,一旦侦听后,并且属性发生了变化,则会触发对应的函数,我们就能够在该函数中实现自己的业务
属性:data定义的属性,computed定义的计算属性等
语法1:只能监听基本类型
watch:{
被监听的属性(val){
//val就是更新之后的值
}
}
语法2:能够监听引用类型(包含了基本类型)---推荐
watch:{
被监听的属性:{
handler(val){
},
//深度监听(默认是false)
deep:true,
//立即侦听(页面加载完之后会立刻触发一次,默认是false)
immediate:true
}
}
Demo1: 监听name的改变
<template>
<div>
{{name}}
</div>
</template>
<script>
export default {
data(){
return{
name:"张三"
}
},
watch:{
name(val){
console.log("更新后的值:"+val);
}
}
}
</script>
demo2:监听对象的某个属性的改变(前置,该属性是基本类型)
<template>
<div>
{{user}}
</div>
</template>
<script>
export default {
data(){
return{
user:{
username:"aaa"
}
}
},
watch:{
'user.username'(val){
console.log("更新后的user值:"+val);
}
}
}
</script>
demo3:侦听整个对象
export default {
data(){
return{
user:{
username:"aaa"
}
}
},
watch:{
user:{
handler(val){
console.log(val);
},
deep:true,
immediate:true
}
watch和computed的区别
1 computed侧重点是渲染 ,watch侧重点是实现非渲染的其他业务
2 computed能做的,一般情况watch都能做,反之不一定
比如:watch中是支持异步请求,而computed一般是不支持异步
3 有时候选好技术后,实现功能特别简单
vue数据检测
vue自身又有套响应式系统(检测数据的改变,自动渲染页面),
在以下情况,数据发生改变后,vue是检测不到-----》页面并不会重新渲染
情况1 对象属性的添加、删除
<template>
<div>
{{user}}
<button @click="addAttr">添加属性</button>
<button @click="delAttr">删除属性</button>
</div>
</template>
<script>
export default {
data(){
return{
user:{
name:"张三"
}
}
},
methods:{
addAttr(){
this.user.age=19
},
delAttr(){
delete this.user.name
}
}
}
</script>
情况2 数组的下标操作以及长度操作
<template>
<div>
{{arr}}
<button @click="handlerArrayIndex">操作数组下标</button>
<button @click="handlerArrayLen">操作数组长度</button>
</div>
</template>
<script>
export default {
data(){
return{
arr:['a','b','c']
}
},
methods:{
handlerArrayIndex(){
this.arr[0]='AAAA'
},
handlerArrayLen(){
this.arr.length=0
}
}
}
</script>
解决方案
1 $set(对象/数组,“属性”/下标,值)-----核心
2 $delete(对象,‘属性’)
methods:{
addAttr(){
// this.user.age=19
this.$set(this.user,'age',19)
},
delAttr(){
// delete this.user.name
this.$delete(this.user,'name')
},
handlerArrayIndex(){
// this.arr[0]='AAAA'
this.$set(this.arr,0,'AAAA')
},
handlerArrayLen(){
this.arr.length=0
}
}
我们自己做项目,可以选择用官方推荐$set,也可以自己用方法
第五节、生命周期函数
人生活中,生命周期指的就是从出生到死亡整个过程,伴随着整个生命周期,人会有出生、少年、中年、老年、死亡阶段,这些阶段都是不可逆,并且每个阶段应该有必须要做的事情
vue程序中,生命周期指的是组件从创建到销毁的整个过程,伴随着整个生命周期,vue组件有4个阶段,分别是:
- 1 创建阶段
- 2 挂载阶段
- 3 更新阶段
- 4 销毁阶段
注意:以上四个阶段也是按照顺序执行的,其中,组件的创建、挂载是访问时必须要执行,而更新和销毁看情况
以上每个阶段拥有对应函数(2个),由于这些函数是按照顺序一个接着执行的,我们喜欢称之为生命周期钩子函数
生命周期函数
位置:和data等并列,注意:不是放在methods(在methods定义的函数(自定义函数)需要手动或者以事件来执行),而钩子函数是自动执行
beforeCreate(){
//此时此刻,正在初始化data、methods等,因此无法使用this.属性/方法
console.log("创建前");
console.log(this.name);//undefined
},
created(){
//所有的东东都已经初始化完毕,可以使用this.属性/方法,一般用于发送异步请求,类似于onload
console.log("创建后");
console.log(this.name);
},
beforeMount(){
//正在渲染页面
console.log("挂载前");
console.log(document.getElementById("p"));//null
},
mounted(){
//整个页面已经渲染完毕了 ,一般用于操作页面的节点以及发送异步请求
console.log("挂载后");
console.log(document.getElementById("p"));
},
beforeUpdate(){
console.log("更新前");
},
updated(){
console.log("更新后");
},
beforeDestroy(){
//组件正在销毁
console.log("销毁前");
},
destroyed(){
//组件已销毁,一般用于扫尾工作,销毁某些不用的变量数据,来达到节约内存的目的
//一般情况下,随着组件的销毁,组件会自动清空当前组件数据,但是有的东东组件不会自动销毁的,比如定时器
console.log("销毁后");
}
总结:我们以后真正用的多的是:
created、 创建完毕,初始化、异步请求
mounted、 渲染完毕,操作节点、异步请求
destroyed 清除数据
问:生命周期函数在父子组件中的执行顺序是什么?
父-创建前
父-创建后
父-挂载前
儿-创建前
儿-创建后
儿-挂载前
儿-挂载后
父-挂载后