vue3知识点3vue的生命周期和钩子函数、计算属性、侦听器
前言
本节知识点主要是生命周期那几个函数,计算属性和侦听器。
Vm
我们要搞清楚vue的实例对象是谁,vue3中创建vue实例时这个vm就是。然后再连接上视图层,vm.mount("#app")。
const vm = Vue.createApp({
data() {
return data
},
})
vm.mount('#app')
而不是连写的,这样写这个vm不是实例对象。
const vm = Vue.createApp({}).mount('#app')
当把data绑定到vm实例对象上之后,也就是创建了vue实例之后,data的数据也就属于vm对象的了,vm也可以调用data里面的属性。Vm.msg=data.msg
console.log(vm.msg,"----vm")
console.log(data.msg,"----data")
注意:vm.msg在钩子函数里报错的话,改this,data 在哪用都可以。
this用于在vue实例里面调用data的数据 this.msg=data.msg
vue的函数中this指向的是vue实例,也就是vm,所以根据上述,this就可以调用data。
视图层
<h4>{{hello}}</h4>
数据层
data={
msg:'hello'
}
vm实例
const vm=Vue.createApp({})
vm.mount('#app')
console.log(vm.$data,"---$data")
生命周期钩子函数
在我们创建完vue实例对象后,会执行这几个函数。它们的位置和data平级。
生命周期定义:
浅显说法:data里的变量在什么情况下开始存在,在什么情况下会被从内存删除,失效。
或者做项目时data不是写死的,而是从服务器传过来的。
如果需要从服务器端(数据库)得到数据返回msg的值给前端,所以需要知道什么时候从服务器获取数据:
比如:要在程序刚运行的时候就要获取数据,其实是从Vue框架刚刚建立的时候需要获取数据,即create vue的时候,要写在created里面。
初始化函数created 和mounted
都是在vue框架的实例对象刚刚初始化的时候就执行 ,在实例创建完成之后立即调用。
created
数据层(data)已经和vue实例对象绑定,与视图层并没有绑定, this.$el =null .
也就是这一步:
const app={
data(){
return data;
},
methods:{}
...
...
}
const vm=Vue.createApp(app)
从服务器获取数据的时候要在created中完成。
mounted
vue实例对象已经与视图层绑定 this.$el 返回绑定的是标签。
也就是这一步:
vm.mount("#app")
视图层已经渲染完了,不能在这里从服务器获取数据,会出现数据的延迟渲染。
$el: 判断视图层有没有和vm绑定上
el是属于vue实例对象的属性,vm.el能够得到视图层的根结点,vm.$el.getelementby… ,可以判断数据层是不是与视图层绑定上了,有则返回你所绑定视图层的标签 ,没有返回null
console.log(vm.$el,"---$el")
那el有什么用呢?,vue框架,所以我们不用得到dom标签就可以得到值,但有的时候也需要得到标签做一些事情,那就可以用el获得标签。
created(){
console.log("created里要做的事")
console.log(this.$el,"---$el")
const get_msg="后端获取的"
this.msg=get_msg
},
mounted(){
console.log("mounted------")
console.log(this.$el,"---$el")
console.log(this.$el.getAttribute("id"))
},
updated
updated的特点:只要数据层的任意一个数据有发生变化 就会执行。不常用,因为有专门侦听指定的数据的变化的方法。
假如所有值都有变化,只侦听数据a的变化,怎么办呢?
只侦听某一个数据发生变化的话,那么就创建侦听器watch.
解绑数据层和视图层unmounted
调用vm实例对象中一个解绑数据层和视图层
解绑 :数据层和视图层 和vue实例对象脱离关系了
vue3 unmounted
vue2里是 destroy
一般项目里是不会解绑的,非要解绑可能是需要做一些数据清理工作。
const vm = Vue.createApp({
data() {
return data
},
created(){
},
mounted(){
},
updated(){
console.log("update------")
},
unmounted(){
console.log("解绑")
},
})
vm.mount('#app')
计算属性:
用法:用于简单的操作,定义的时候写在computed里,和函数一样的定义方法,最后一定要有一个返回值。渲染的时候computed里的方法名当成data的属性用{{func}},不用加()。
意思是,可以把computed里的方法,当成data里的属性用。
实际操作:
视图层: <div>{{fun1}}</div>
computed:{
func1(){
//是和数据层的哪几个属性有关系的
return this.mgs1+this.msg2
//或者:
const str=this.books.join("-")
return str
}
}
通过函数也能实现同样的功能:方法调用的时候要加上()
当它绑定事件的时候就不用加()了。
<div>{{fun2()}}</div>
<input type="text" @click="func2">
methods:{
fun2(){
const str=this.books.join("-")
return str
}
}
那既然函数也可以实现同样的功能,那还要计算属性干嘛呢?
计算属性和函数的区别
1.渲染的时候:
2.多次渲染相同的数据时:
多次渲染相同的计算属性时 ,第一次的计算属性返回的结果会缓存下来 第二次再渲染相同的计算属性的话 如果和上一次相同的话 就直接从缓存中读取数据了 不会再次执行计算属性的过程。只有当计算属性渲染的值发生变化时才会重新计算。
可以看出 计算属性不管调用多少次,只执行一次,计算属性有缓存功能,函数每次都会重新进入函数。
所以计算属性的效率更高。
3.计算属性的Get和set:赋值和读值
Get:返回给视图的时候是进行操作后把操作后的两个一起返回,和计算属性一样,即读值一样。
Set:在调用的时候需要对data的这两个数据进行赋值,即需要分开操作。
使用场景:所以如果只需要对两个数据一起操作后返回一个值,直接用计算属性。
如果还需要对这两个数据操作完分别赋值,那么用set,get.
侦听器 watch
某一个数据变化时侦听数据的变化,数据一旦变化了,要做什么事情。
我这个图这里olddata和newdata写反了。
当msg发生变化时,参数 新数据和旧数据,下面再写逻辑,执行哪个函数。changebooks是我methods里的一个方法。
侦听器和计算属性的区别:
计算属性的使用场合:
计算属性是依赖于缓存,数据变化时才重新计算,避免大量重复性调用。
如果数据层中的多个数据(多个商品)影响了其中一个数据(总价格)的话,可以使用计算属性 (缓存数据)
例如每个商品价格的变化会影响总价格。 计算属性都是同步操作。
侦听器的使用场合:
主要用于一个数据影响了多个数据的情况 ,因为它侦听的是一个数据,如果一个数据发生了变化需要做 异步操作,例如 计时器间隔, 数据从server端获取。
例子:
fullName=firstname+lastname,这个案例如果用侦听器做的话需要侦听两个值firstname,lastname,所以需要创建两个函数,一个firstname(),一个lastname,且两个函数里写的内容是一样的,所以不如用计算属性,只用写一次。
侦听器,不要滥用 ,它会对每个侦听的数据 专门开辟一个接口, 性能降低 。 仍然是计算属性最优.
本节操作全部代码(可直接复制):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="js/vue.global.js"></script>
</head>
<body id="app">
<h4>{{msg}}</h4>
<button @click='myclick()'>点击我</button><br>
<h4>{{func1}}</h4><br>
<!-- 计算属性和函数渲染的区别:属性不用加括号 ,函数有返回值的时候要加()-->
<!-- 执行的时候计算属性调用多次只进一次方法
函数调用一次进一次。 -->
<h4>{{func2}}</h4><br>
<h4>{{func2}}</h4><br>
<h4>{{func2}}</h4><br>
<h4>{{func3()}}</h4><br>
<h4>{{func3()}}</h4><br>
<h4>{{func3()}}</h4><br>
</body>
<script type="text/javascript">
const data = {
msg:"hello",
books:['vue1','vue2','vue3']
}
const vm = Vue.createApp({
data() {
return data
},
// 2.生命周期钩子函数:
created(){
console.log("create------")
console.log(this.$el,"---$el")//null
//这里需要从服务器端获取数据,再把数据赋给data
const get_msg="后端获取的"
this.msg=get_msg
},
mounted(){
console.log("mounted------")
console.log(this.$el,"---$el")//<h4>...</h4>
},
updated(){
// 只要数据层的数据有发生变化就会调用
// 点击按钮,数据层的数据发生变化,进入updated
console.log("update------")
},
unmounted(){
//解绑之后,做一些清理工作,把全局定义的变量 null
console.log("解绑了")
},
// 计算属性
computed:{
func1(){
return this.books.length>0?"yes":"no"
},
func2(){
const str=this.books.join("-")
console.log("计算属性只一次")
return str
}
},
// 观察者:侦听数据的变化:
// 点击按钮侦听msg,如果msg的长度>5的时候调用changebooks方法
watch:{
msg(newdata,olddata){
console.log("变化了,watch进了")
console.log("旧",olddata,"新",newdata)
console.log("长度",newdata.toString().length)
if(newdata.toString().length>4){
this.changebooks()
}
}
},
methods:{
myclick(){
//this---执行时所属的对象
this.msg=Math.random()
},
func3(){
const str=this.books.join("-")
console.log("函数运行一次执行一次")
return str
},
changebooks(){
this.books.push("vue444")
console.log("---我是增加books",this.books)
}
}
})
// vm才是vue的实例对象
// 这里一定要分着写
vm.mount('#app')
// 1.vm.msg=data.msg
console.log(vm.msg,"----vm")//hello
console.log(data.msg,"----data")//hello
// vm.$data:等同于data
console.log(vm.$data,"---$data")//{msg: "hello"}
// $el:你所绑定的根结点的dom元素
console.log(vm.$el,"---$el")//<h4>{{hello}}</h4>
</script>
</html>