文章目录
Vue核心知识点(三)
前言
本博客是对以下视频教程做的一个笔记总结,这个笔记和视频不是一一对应的,但可作为参考,不喜勿喷。
本博客是Vue核心知识点的第三篇,第二篇在这儿:Vue核心(二) 。由于内容太多,分三篇来写。
如果对你有所帮助,欢迎点赞,评论,转发。
这篇博客的主要内容有:
v-for
(列表渲染)深入了解。Vue
数据监测原理分析。Vue
生命周期。
1、v-for(列表渲染)深入了解
这里主要是对v-for中,
key
的原理进行分析。
1.1 示例代码
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>key的原理</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<h3>遍历数组</h3>
<!--once: 只调用一次函数-->
<button @click.once="add">添加一个老王</button>
<ul>
<!--index作为key-->
<!--<li v-for="(p,index) of persons" :key="index">
{{p.name}}--{{p.age}}
<input type="text">
</li>-->
<!--id作为key(id是唯一的)-->
<li v-for="(p,index) in persons" :key="p.id">
{{p.name}}--{{p.age}}
<input type="text">
</li>
</ul>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; //关闭Vue的生产提示
const vm = new Vue({
data() {
return {
//每条数据的id是全局唯一的
persons: [
{id: '001', name: '张三', age: 18},
{id: '002', name: '李四', age: 19},
{id: '003', name: '王五', age: 20},
]
};
},
methods: {
add() {
console.log("add...");
let p = {id: '004', name: '老王', age: 22};
/*往数组头插入元素*/
this.persons.unshift(p);
}
}
});
/*挂载Vue实例到root容器上*/
vm.$mount('#root');
</script>
</html>
1.2 key原理分析
1、index作为key:
手动在后面的输入框中输入内容,如下:
往数组头添加一个老王之后:
很显然,出现了问题,元素的顺序出现了问题。
原理如下:
2、id作为key :
还是之前的数据,在数组头插入一个老王之后,如下图:
可以看到,下面的数据并没有发生混乱。
原理如下:
1.3 总结
面试题:React、Vue中的key有什么作用?(key的内部原理)
-
虚拟DOM中key的作用:
-
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
-
随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
-
对比规则:
-
旧虚拟DOM中找到了与新虚拟DOM相同的key:
-
①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
-
②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
-
-
旧虚拟DOM中未找到与新虚拟DOM相同的key:
- ①.创建新的真实DOM,随后渲染到到页面。
-
-
-
用index作为key可能会引发的问题:
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作,
- 会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
- 如果结构中还包含输入类的DOM:
- 会产生错误DOM更新 ==> 界面有问题。
-
开发中如何选择key?
- 最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
- 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
- 使用index作为key是没有问题的。
1.4 案例_过滤列表
输入名字,显示对应的人。
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>列表过滤</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<h2>人员列表</h2>
<!--输入名字进行人员查找-->
<input type="text" placeholder="请输入名字" v-model="keyWord"/>
<ul>
<li v-for="(p,index) of filPersons" :key="p.id">
{{p.name}}--{{p.age}}--{{p.sex}}
</li>
</ul>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; //关闭Vue的生产提示
/*方式一:watch实现*/
/*const vm = new Vue({
data() {
return {
keyWord: "",
persons: [
{id: '001', name: '胡歌', age: 19, sex: '男'},
{id: '002', name: '周冬雨', age: 20, sex: '女'},
{id: '003', name: '赵丽颖', age: 21, sex: '女'},
{id: '004', name: '杨幂', age: 22, sex: '女'}
],
filPersons: []
};
},
watch: {
keyWord: {
immediate: true, //初始化调用一次 handler
handler(newValue) {
this.filPersons = this.persons.filter((p) => {
//对name进行字符串匹配
let result = p.name.indexOf(newValue) !== -1;
console.log(result); //结果是布尔值(true or false)
return result;
});
},
}
}
});
/!*挂载Vue实例到root容器上*!/
vm.$mount('#root');*/
/*用computed实现*/
new Vue({
el: '#root',
data: {
keyWord: "",
persons: [
{id: '001', name: '胡歌', age: 19, sex: '男'},
{id: '002', name: '周冬雨', age: 20, sex: '女'},
{id: '003', name: '赵丽颖', age: 21, sex: '女'},
{id: '004', name: '杨幂', age: 22, sex: '女'}
],
},
//注意!!!!!巨坑!!!!computed是和data同级的!!!!
computed: {
/*普通写法*/
/*filPersons: {
get() {
return this.persons.filter((p) => {
return p.name.indexOf(this.keyWord) !== -1;
});
}
}*/
/*简写*/
filPersons() {
return this.persons.filter((p) => {
return p.name.indexOf(this.keyWord) !== -1;
});
}
}
});
</script>
</html>
1.5 案例_列表排序
对列表进行升序,降序排列,也可以恢复原顺序。
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>列表过滤</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<button @click="sortType=2">年龄升序</button>
<button @click="sortType=1">年龄降序</button>
<button @click="sortType=0">年龄原顺序</button>
<ul>
<li v-for="(p,index) of filPersons" :key="p.id">
{{p.name}}--{{p.age}}--{{p.sex}}
</li>
</ul>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; //关闭Vue的生产提示
const vm = new Vue({
data() {
return {
keyWord: '',
sortType: 0, //0原顺序 1降序 2升序
persons: [
{id: '003', name: '赵丽颖', age: 21, sex: '女'},
{id: '002', name: '周冬雨', age: 20, sex: '女'},
{id: '005', name: '王老胡', age: 23, sex: '男'},
{id: '004', name: '杨幂', age: 22, sex: '女'},
{id: '001', name: '胡歌', age: 19, sex: '男'},
],
};
},
//注意!!computed和data是同级的!!!
computed: {
filPersons() {
let arr = this.persons.filter((p) => {
return p.name.indexOf(this.keyWord) !== -1;
});
//判断一下是否需要排序(0表示不排序,不会进入处理逻辑)
if (this.sortType) {
arr.sort((p1, p2) => {
//p2.age - p1.age降序,p1.age - p2.age升序
return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age;
});
}
return arr;
}
}
});
/*挂载Vue实例到root容器上*/
vm.$mount('#root');
</script>
</html>
2、Vue数据监测原理分析
2.1 Vue数据更新的问题
点击按钮,更新胡歌的信息。
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Vue数据更新的问题</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<h2>人员列表</h2>
<button @click="updateUserInfo()">更新胡歌的信息</button>
<ul>
<li v-for="(p,index) of persons" :key="p.id">
{{p.name}}--{{p.age}}--{{p.sex}}
</li>
</ul>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; //关闭Vue的生产提示
const vm = new Vue({
data() {
return {
keyWord: "",
persons: [
{id: '001', name: '胡歌', age: 19, sex: '男'},
{id: '002', name: '周冬雨', age: 20, sex: '女'},
{id: '003', name: '赵丽颖', age: 21, sex: '女'},
{id: '004', name: '杨幂', age: 22, sex: '女'}
],
filPersons: []
};
},
methods: {
//更新用户信息
updateUserInfo() {
// this.persons[0].name = '景天'; //奏效(页面同步更新)
// this.persons[0].age = 30; //奏效(页面同步更新)
// this.persons[0].sex = '男'; //奏效(页面同步更新)
this.persons[0] = {id: '001', name: '飞蓬将军', age: 1200, sex: '男'}; //不奏效(页面没有同步更新)
console.log(this.persons[0]);
}
}
});
/*挂载Vue实例到root容器上*/
vm.$mount('#root');
</script>
</html>
结果如下:
出现了数据不一致的问题。那又该如何解决呢?
别急,下面我们就一起来探究一下Vue监测数据变化的原理。
2.2 Vue数据监测原理_对象
2.2.1 示例代码
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Vue监测数据变化的原理</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<h2>学校:{{school}}</h2>
<h2>地址:{{address}}</h2>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; //关闭Vue的生产提示
const vm = new Vue({
data() {
return {
school: '北京理工',
address: '北京',
//Vue内部会递归查找属性,如果发现是对象属性,则会继续递归查找,
//直到找到单一的属性,然后给这个单一属性分配一组getter和setter。
student: {
name: 'tom',
age: {
rAge: 30,
sAge: 18,
},
friends: [
{name: 'jerry', age: 29}
]
}
};
}
});
/*挂载Vue实例到root容器上*/
vm.$mount('#root');
</script>
</html>
总结
- Vue内部会递归查找属性,如果发现是对象属性,则会继续递归查找,
- 直到找到单一的属性为止。
- Vue会给data中的每一个自定义属性分配一组getter和setter。
2.2.2 原理分析
2.2.3 总结
Vue
为data
中的每一个自定义属性,都匹配了一组getter
和setter
。- 假如
data
中定义了一个school
属性,则当school
属性值发生改变的时候,对应的setter
就会被调用, - 然后
Vue
就会重新解析模板,接下来就会生成新的虚拟DOM
, - 然后
Vue
就会对比新旧的虚拟DOM
(diff算法), - 最后生成真实
DOM
,更新页面。
2.3 模拟一个数据监测
为了对Vue数据监测原理有更深的理解,我们来看看和模拟一下Vue中是怎么做的数据监测。
以监测对象数据为例。
2.3.1 示例代码
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>模拟一个数据监测</title>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
</div>
</body>
<script type="text/javascript">
//1、准备好数据,等一下要监测这里面数据的变化
let data = {
school: '北京理工',
address: '北京'
};
//2、定义一个构造函数,用于对data对象中的数据进行处理
function Observer(obj) {
//汇总对象中的所有属性,形成一个数组
// ['school','address']
const keys = Object.keys(obj);
//遍历
keys.forEach((k) => {
//this:为当前Observer的实例对象
//k:为每一个属性
Object.defineProperty(this, k, {
/*往Observer实例对象(this)中添加一个属性 k ,
当有人读取Observer实例对象上的属性 k 时,
就把传入对象obj的属性 k 对应的值返回*/
get() {
return obj[k];
},
set(newValue) {
//Vue会在这里触发一些解析模板的函数,重新解析模板。
console.log(`${k}被修改了,我要去解析模板,生成虚拟DOM,对比新旧虚拟DOM...要开始忙了~`);
obj[k] = newValue;
}
});
});
}
//3、创建一个监视的实例对象,用于监视data中数据的变化
const obs = new Observer(data);
//准备一个vm实例对象
let vm = {};
vm._data = data = obs;
</script>
</html>
对属性值进行修改,控制台输出如下:
2.4 Vue.set的使用
向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Vue.set的使用</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<button @click="addSex">添加一个性别属性,默认值是男</button>
<h2>学生信息</h2>
<h3>名字:{{student.name}}</h3>
<h3>年龄:{{student.age}}</h3>
<!--如果学生的性别有值就显示这个标签,无(undefined)则不显示-->
<h3 v-if="student.sex">性别:{{student.sex}}</h3>
<h3>朋友们:</h3>
<ul>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}}==={{f.age}}
</li>
</ul>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; //关闭Vue的生产提示
const vm = new Vue({
data() {
return {
student: {
name: '张三',
age: 20,
friends: [
{name: '李四', age: 18},
{name: '王五', age: 19},
]
}
};
},
methods: {
addSex() {
//注意!!!不能往data中直接添加属性,只能往data中的某个属性里,添加属性
//往vue实例,data中的student上添加一个sex属性,默认值为:男
// Vue.set(this.student, 'sex', '男');
this.$set(this.student, 'sex', '男');
}
}
});
/*挂载Vue实例到root容器上*/
vm.$mount('#root');
</script>
</html>
总结
Vue.set( target, propertyName/index, value )
vm.$set( target, propertyName/index, value )
【vm为Vue实例对象】- 向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。
- 参数:
{Object | Array} target
{string | number} propertyName/index
{any} value
- 返回值:设置的值。
2.5 Vue数据监测原理_数组
2.5.1 示例代码
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Vue监测数据变化的原理_数组</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<h3>名字:</h3>
<ul>
<li v-for="(name,index) in fullName" :key="index">
{{name}}
</li>
</ul>
<h3>爱好:</h3>
<ul>
<li v-for="(h,index) of hobby" :key="index">
{{h}}
</li>
</ul>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; //关闭Vue的生产提示
const vm = new Vue({
data() {
return {
fullName: {
firstName: '张',
lastName: '三'
},
hobby: ['抽烟', '喝酒', '烫头']
};
}
});
/*挂载Vue实例到root容器上*/
vm.$mount('#root');
let arr = [1, 3, 5];
</script>
</html>
2.5.2 原理分析
官网链接:Vue监测数组的更新改变
如下图,在控制台输出_data
发现,数组元素没有对应的getter
和setter
。
可见,数组里的每个元素不是靠getter和setter来实现数据劫持的,
也就是说,数组里的每个元素都没有对应的getter和setter,
当数组中的元素的值发生改变时,vue不会监测到这次改变,页面也就不会同步更新。
从下图中我们可以看到,JS中原生数组中调用的方法,在数组原型对象上可以找到,
也就是说,当我们调用数组上的方法时,实际上内部会去原型对象上找对应的方法,
调用的是数组原型对象上的方法。
从下面这张图中可以验证上面的结论,可以看出,原生数组上的方法就是数组原型对象上的方法,
但也可以发现,Vue实例管理的数组调用的方法,却不是原生数组的方法。
通过查阅资料发现,Vue实例上的数组调用的方法,实际上是Vue中的方法,
这些方法是被包装(加工)过的,所以和原生数组上的方法不一样,
Vue在其中做了两件事情(以push
方法为例):
- 第一步,还是调用一下
Array
原型上的方法(push
), - 第二步,调用方法,去解析模板和更新页面。
这也就解释了**【2.1 Vue数据更新的问题】**当中的这段代码不奏效的原因。
//更新用户信息
updateUserInfo() {
// this.persons[0].name = '景天'; //奏效(页面同步更新)
// this.persons[0].age = 30; //奏效(页面同步更新)
// this.persons[0].sex = '男'; //奏效(页面同步更新)
this.persons[0] = {id: '001', name: '飞蓬将军', age: 1200, sex: '男'}; //不奏效(页面没有同步更新)
console.log(this.persons[0]);
}
因为Vue
当中没有为数组中的每一个元素提供getter
和setter
方法,Vue
监测不到数组元素值的变化,
所以导致数组中元素值发生改变了,页面也没有同步更新,也就是操作不奏效,
只有调用对应改变数组的方法,页面才会同步更新。
Vue 将被侦听的数组的变更方法进行了包裹(包装,加工),所以它们也将会触发视图更新。
这些被包裹过的方法包括:
push()
:往数组最后位置新增一个元素。pop()
:删除数组中最后一个元素。shift()
:删除数组中的第一个元素。unshift()
:往数组第一个位置插入一个元素。splice()
:往数组中指定位置插入(或删除,或替换)某个元素。sort()
:对数组中的元素进行排序。reverse()
:反转数组。
原因弄明白之后,**【2.1 Vue数据更新的问题】**中遗留的问题也就解决了。如下:
//更新用户信息
updateUserInfo() {
// this.persons[0].name = '景天'; //奏效(页面同步更新)
// this.persons[0].age = 30; //奏效(页面同步更新)
// this.persons[0].sex = '男'; //奏效(页面同步更新)
//this.persons[0] = {id: '001', name: '飞蓬将军', age: 1200, sex: '男'}; //不奏效(页面没有同步更新)
/*splice(start,deleteCount,items)
* start: 要替换的元素位置,从0开始
* deleteCount: 替换(删除)的数量
* items: 新元素*/
this.persons.splice(0, 1, {id: '001', name: '飞蓬将军', age: 1200, sex: '男'}); //奏效(页面同步更新)
console.log(this.persons[0]);
}
也可以采用set
方式来解决,如下:
//参数一:要修改的元素,
//参数二:要修改的元素的位置,
//参数三:新元素
Vue.set(this.persons,0,{id: '001', name: '飞蓬将军', age: 1200, sex: '男'}); //奏效
vm.$set(this.persons,0,{id: '001', name: '飞蓬将军', age: 1200, sex: '男'}); //奏效
备注:使用过滤器,将过滤结果重新赋值给数组也会改变数组,触发Vue重新解析模板,更新页面。
2.6 总结Vue数据监测
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>总结Vue数据监测</title>
<style>
button {
margin-top: 10px;
}
</style>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>s
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<h1>学生信息</h1>
<button @click="student.age++">年龄+1岁</button>
<br/>
<button @click="addSex">添加性别属性,默认值:男</button>
<br/>
<button @click="student.sex = '未知' ">修改性别</button>
<br/>
<button @click="addFriend">在列表首位添加一个朋友</button>
<br/>
<button @click="updateFirstFriendName">修改第一个朋友的名字为:张三</button>
<br/>
<button @click="addHobby">添加一个爱好</button>
<br/>
<button @click="updateHobby">修改第一个爱好为:开车</button>
<br/>
<button @click="removeSmoke">过滤掉爱好中的抽烟</button>
<br/>
<h3>姓名:{{student.name}}</h3>
<h3>年龄:{{student.age}}</h3>
<h3 v-if="student.sex">性别:{{student.sex}}</h3>
<h3>爱好:</h3>
<ul>
<li v-for="(h,index) in student.hobby" :key="index">
{{h}}
</li>
</ul>
<h3>朋友们:</h3>
<ul>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}}--{{f.age}}
</li>
</ul>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el: '#root',
data: {
student: {
name: 'tom',
age: 18,
hobby: ['抽烟', '喝酒', '烫头'],
friends: [
{name: 'jerry', age: 20},
{name: 'tony', age: 21}
]
}
},
methods: {
addSex() {
// Vue.set(this.student,'sex','男')
this.$set(this.student, 'sex', '男')
},
addFriend() {
this.student.friends.unshift({name: 'jack', age: 70})
},
updateFirstFriendName() {
this.student.friends[0].name = '张三'
},
addHobby() {
this.student.hobby.push('学习')
},
updateHobby() {
// this.student.hobby.splice(0,1,'开车')
// Vue.set(this.student.hobby,0,'开车')
this.$set(this.student.hobby, 0, '开车')
},
removeSmoke() {
//过滤结果重新赋值给数组也会改变数组,触发Vue重新解析模板,更新页面
this.student.hobby = this.student.hobby.filter((h) => {
return h !== '抽烟'
})
}
}
})
</script>
</html>
总结
Vue监视数据的原理
-
Vue
会监视data
中所有层次的数据。 -
如何监测对象中的数据?
- 通过
setter
实现监视,且要在new Vue
时就传入要监测的数据。 - 对象中后追加的属性,
Vue
默认不做响应式处理。 - 如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value)
vm.$set(target,propertyName/index,value)
- 通过
-
如何监测数组中的数据?
- 通过包裹(包装,加工)数组更新元素的方法实现,本质就是做了两件事:
- 调用原生对应的方法对数组进行更新。
- 重新解析模板,进而更新页面。
- 在
Vue
修改数组中的某个元素一定要用如下方法:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
Vue.set()
或vm.$set()
- 特别注意:Vue.set() 和 vm.$set() 不能给
vm
或 vm的根数据对象(data,_data) 添加属性!!!
- 通过包裹(包装,加工)数组更新元素的方法实现,本质就是做了两件事:
-
使用过滤器,将过滤结果重新赋值给数组也会改变数组,触发Vue重新解析模板,更新页面。
3、Vue生命周期
3.1 引出生命周期
需求:文字从清晰变透明,透明度逐渐变化,透明度小于或等于0时,重新变为1。
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>引出生命周期</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<h2 v-if="a">你好啊</h2>
<h2 :style="{opacity}">欢迎学习Vue</h2>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。
new Vue({
el: '#root',
data: {
a: false,
opacity: 1
},
methods: {},
//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
mounted() {
console.log('mounted', this);
setInterval(() => {
this.opacity -= 0.01;
if (this.opacity <= 0) {
this.opacity = 1
}
}, 16)
},
})
//通过外部的定时器实现(不推荐)
/* setInterval(() => {
vm.opacity -= 0.01
if(vm.opacity <= 0) vm.opacity = 1
},16) */
</script>
</html>
总结
生命周期:
- 也叫:生命周期回调函数、生命周期函数、生命周期钩子。
- 是什么:
Vue
在关键时刻帮我们调用的一些特殊名称的函数。 - 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
- 生命周期函数中的
this
指向是 vm 或 组件实例对象。
3.2 分析生命周期
如图:
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>分析生命周期</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<h2 v-text="n"></h2>
<h2>当前的n值是:{{n}}</h2>
<button @click="add">点我n+1</button>
<button @click="bye">点我销毁vm</button>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。
new Vue({
el: '#root',
//可以把html代码写在template里,需要用引号包裹,页面就可以省略这部分代码了
// template:`
// <div>
// <h2>当前的n值是:{{n}}</h2>
// <button @click="add">点我n+1</button>
// </div>
// `,
data: {
n: 1
},
methods: {
/*改变n的值*/
add() {
console.log('add');
this.n++;
},
/*销毁vm*/
bye() {
console.log('bye');
this.$destroy();
}
},
/*监视属性*/
watch: {
/*监视n是否被修改*/
n() {
console.log('n变了');
}
},
/********************Vue生命周期函数******************************/
beforeCreate() {
console.log('beforeCreate');
},
/*初始化:数据监测,数据代理,下一阶段开始解析模板*/
created() {
console.log('created');
},
beforeMount() {
console.log('beforeMount');
},
/*初始化完成*/
mounted() {
console.log('mounted');
},
beforeUpdate() {
console.log('beforeUpdate');
},
/*更新完成,数据和页面实现同步,都是最新的*/
updated() {
console.log('updated');
},
/*Vue实例销毁之前*/
beforeDestroy() {
console.log('beforeDestroy');
},
destroyed() {
console.log('destroyed');
},
});
</script>
</html>
3.3 总结生命周期
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>总结生命周期</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<h2 :style="{opacity}">欢迎学习Vue</h2>
<button @click="opacity = 1">透明度设置为1</button>
<button @click="stop">点我停止变换</button>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。
new Vue({
el: '#root',
data: {
opacity: 1
},
methods: {
stop() {
this.$destroy()
}
},
//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
mounted() {
console.log('mounted', this);
this.timer = setInterval(() => {
console.log('setInterval');
this.opacity -= 0.01;
if (this.opacity <= 0) this.opacity = 1
}, 16)
},
beforeDestroy() {
clearInterval(this.timer);
console.log('vm即将驾鹤西游了')
},
})
</script>
</html>
总结
常用的生命周期钩子:
mounted
:发送ajax
请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。beforeDestroy
:清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。- 关于销毁
Vue
实例:- 销毁后借助
Vue
开发者工具看不到任何信息。 - 销毁后自定义事件会失效,但原生DOM事件依然有效。
- 一般不会在
beforeDestroy
操作数据,因为即便操作数据,也不会再触发更新流程了。
- 销毁后借助
4、结语
到此,Vue的核心内容差不多学习完了,接下来就是组件的内容了,如果这篇博客对你有帮助,欢迎点赞,评论,转发,一起进步,谢谢。