2.功能
2.0.生命同期 及 钩子函数
2.0.1.生命周期
Vue 2.x 版本中,组件的生命周期主要包括以下各个阶段及对应的钩子函数:
2.0.1.1.创建阶段 (Creation)
-
beforeCreate
- 在实例初始化之后,数据观测 (
data observer
) 和事件配置 (event/watcher
) 之前调用。 - 此时,实例的挂载元素
$el
和相关数据观测都还未初始化。
- 在实例初始化之后,数据观测 (
-
created
- 在实例创建完成后调用,此时仅完成了数据观察的设置,但真实 DOM 尚未生成,
$el
还不存在。 - 可以在这里进行一些异步数据请求,因为实例已经可以访问到
data
、methods
、computed
等属性。
- 在实例创建完成后调用,此时仅完成了数据观察的设置,但真实 DOM 尚未生成,
2.0.1.2.挂载阶段 (Mounting)
-
beforeMount
- 在挂载开始之前调用,相关的 render 函数首次执行,但真实的 DOM 节点还没有插入到文档流中。
- 此时可以通过
this.$el
获取到即将要渲染的虚拟 DOM 节点。
-
mounted
- 在实例被挂载到DOM树上之后调用,此时组件的DOM已经渲染出来,可以进行DOM操作或者与第三方库进行交互。
- 此钩子函数在整个生命周期中只执行一次。
2.0.1.3.更新阶段 (Updating)
-
beforeUpdate
- 当数据发生变化,Vue实例即将重新渲染和打补丁之前调用。
- 在这一步,可以获取到更新前的数据状态,但无法阻止默认的更新行为。
-
updated
- 数据更新后,DOM已经完成重新渲染,可以在此时访问到更新后的DOM节点。
- 注意避免在此处进行过多的DOM操作,以防频繁触发重渲染。
2.0.1.4.销毁阶段 (Destroying)
-
beforeDestroy
- 在实例销毁之前调用,此时实例仍然完全可用,可以在这一步解绑事件监听器和清理定时器等资源。
-
destroyed
- 在实例销毁后调用,所有指令解绑,所有数据观测、watcher停止,所有子实例也都已被销毁。
- 在此阶段,Vue实例的所有东西都已经解绑,不再可用。
这些生命周期钩子提供了对Vue组件不同阶段的控制点,帮助开发者更好地管理组件的状态变化和资源分配。
2.0.2.测试
<div id="app">
{{msg}}
</div>
var vm = new Vue({
el : "#app",
data : {
msg : "hi vue",
},
//在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
beforeCreate:function(){
console.log('beforeCreate');
},
/* 在实例创建完成后被立即调用。
在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。
然而,挂载阶段还没开始,$el 属性目前不可见。 */
created(){
console.log('created');
},
//在挂载开始之前被调用:相关的渲染函数首次被调用
beforeMount : function(){
console.log('beforeMount');
},
//el 被新创建的 vm.$el 替换, 挂在成功
mounted : function(){
console.log('mounted');
},
//数据更新时调用
beforeUpdate : function(){
console.log('beforeUpdate');
},
//组件 DOM 已经更新, 组件更新完毕
updated : function(){
console.log('updated');
}
});
setTimeout(function(){
vm.msg = "change ......";
}, 3000);
2.1.computed 变量计算
直接在computed里面定义变量 , 根据已定义的属性值通过计算获取的值 , 可以直接使用
当定义的属性值 发生变化时 computed定义的变量随之变化
2.1.1.get方法
案例中, totalPrice 就是 根据 data中定义的 count , price 结果得来的
<div id="app">
数量 : <input type="number" v-model="count" /><br>
单价 : <input type="number" v-model="price" /><br>
总价 : {{ totalPrice }}<br>
</div>
在 computed, 通过 变量的 get 方法返回 计算的值 , 当 count , price 变化时 , totalPrice 的值也变化
new Vue({
el: '#app',
data: {
count : 10,
price : 20,
},
computed: {
totalPrice: {
// 关联属性变化也变化
get: function () {
return this.count * this.price
}
}
}
})
2.1.2.set方法
修改 模板, 增加 totalPrice 的双向绑定
<div id="app">
数量 : <input type="number" v-model="count" /><br>
单价 : <input type="number" v-model="price" /><br>
总价 : {{ totalPrice }}<br>
总价 : <input type="number" v-model="totalPrice" /><br>
</div>
在 computed 中 增加 totalPrice 的 set 方法, 根据set方法, 修改 totalPrice 的值, count/price 也可能变化
totalPrice: {
get: function () {
return this.count * this.price
},
// 设置值时, 调用
set: function (newValue) {
this.price = newValue / this.count
}
}
2.1.3.简单写法
如果 computed 计算的变量 只是为了取值 , 没有设置值, 则可以直接定义为函数
totalPrice() {
return this.count * this.price
},
2.1.4.补充
2.1.4.1.也可以根据computed 变量计算
增加新的计算变量 , 它是根据 totalPrice 变量值的变化而计算出来的
profit() {
return this.totalPrice * 0.2
}
2.1.4.2.不根据任何定义的变量
根据 时间得到 , 不是通过对 已定义的变量计算来的
getTime() {
return new Date().toLocaleString()
}
2.1.5.computed 与 methods
效果上两个都是一样的,
但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。
而使用 methods ,在重新渲染的时候,函数总会重新调用执行。
<div id="app">
<p>原始字符串: {{ message }}</p>
<p>计算后反转字符串: {{ computedReversed }}</p>
<p>使用方法后反转字符串: {{ reversedMessage() }}</p>
</div>
var app = new Vue({
el:"#app",
data: {
message: 'hello vue!'
},
// 效果上两个都是一样的,
// 但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。
// 而使用 methods ,在重新渲染的时候,函数总会重新调用执行。
computed: {
// 计算属性的 getter
computedReversed() {
// `this` 指向 app 实例
return this.message.split('').reverse().join('')
}
},
methods: {
reversedMessage() {
return this.message.split('').reverse().join('')
}
}
})
2.2.watch 变量监听器
watch 监听函数( 侦听函数 ) 用于观察和响应数据的变化。当被观察的数据发生变化时,我们定义的相应处理函数会被自动调用。
它监控的变量当然必须在data里面声明才可以,它可以监控一个变量,也可以是一个对象
2.2.1.基本代码
定义一个数值框, 并双向绑定
<div id="app">
<input type="number" v-model="num" />{{msg}}
</div>
定义的num每次改变 , 都会触发 watch定义的函数
var app = new Vue({
el:"#app",
data:{
num:1,
msg:''
},
watch:{
// 监听器
num(newVal, oldVal){
console.log(newVal,oldVal)
if(newVal>=3){
this.msg="数量不能大于3"
this.num=3
}else{
this.msg=""
}
}
}
})
2.2.2.监听属性
2.2.2.1.监听对象属性
data中定义对象变量,
data: {
msg: "",
stu: {
name: '王小二',
age: 18
}
},
同时 在模板中显示
<p>{{stu.name}} : {{stu.age}} : {{ msg }}</p>
<input type="text" v-model="stu.name"/>
<input type="number" v-model="stu.age"/>
为 stu的 age属性添加 监听属性, 定义时 用 单引号 包裹 'stu.age'
watch: {
'stu.age'(val, oldVal){
this.msg = `stu.age的值从${oldVal} 变化为${val}`
}
},
2.2.2.2.深度监听
修改为监听对象stu , 显然是不好使了, 因为 stu的引用指向不变 是不会触发 监听的
watch: {
stu(val, oldVal){
this.msg = `stu.age的值从${oldVal} 变化为${val}`
}
}
再修改 监听, 改为 使用对象格式, 增加 deep属性, 设置为true, 这样对象的属性发生变化, 也会触发监听
watch: {
stu: {
handler: function (val, oldVal) {
this.msg = `stu.age的值从${oldVal.age} 变化为${val.age}`
},
deep: true
},
}
这里注意
- 处理函数属性为 : handler
- 函数的两个参数取值是相同的值 ( 这应该是个错误 )
2.2.3. $watch 写法
也可以使用 $watch 对象的方式
vm.$watch('stu',{
handler: function (val, oldVal) {
this.msg = `stu.age的值从${oldVal.age} 变化为${val.age}`
},
deep: true
} )
2.3.Filter 过滤器
对要显示的数据进行特定格式化后再显示
使用 |
运算符 前面是信息 后面是过滤后结果( 过滤器名 )
并没有改变原本的数据, 是产生新的对应的数据
多个过滤器也可以串联
<div id="app">
<ul>
<li v-for=" num in nums">{{num}} {{ num | nFilter }}</li>
</ul>
<hr/>
<ul>
<li v-for=" num in nums">{{num}} {{ num | aFilter }}</li>
</ul>
<hr/>
<h3>
多个过滤器也可以串联: 对第一个过滤器的结果 再加工
</h3>
<ul>
<li v-for=" num in nums">{{num}} {{ num | aFilter | a2Filter }}</li>
</ul>
</div>
// 全局过滤器, 判断 是否大于 20 返回字符串
Vue.filter("aFilter", function(val){
if(val>20){
return "大于20"
}else{
return "不大于20"
}
})
// 全局过滤器, 对字符串 进行截取
Vue.filter("a2Filter", function(val){
return val.substring(0,1)
})
new Vue({
el: '#app',
data:{
nums:[ 1, 23, 22, 51, 13, 42]
},
filters:{
// 内置过滤器
nFilter(val){
if(val%2==0){
return "偶数"
}else{
return "奇数"
}
}
}
})