学习列表
初学Vue(一)-- Vue简单入门
初学vue(二)-- 条件渲染、修饰符、循环
初学vue(四)-- axios前后端交互、组件
初学vue(五)-- 路由
异步 DOM 更新
- Vue 中采用了
异步DOM更新
的机制 - 如何更新页面?
- 数据发生改变后, vue 没有立即将数据的改变更新到视图中,
-
而是等到数据不再变化的时候 一次性的 将 数据的改变更新到视图中
//1. 验证了 for (let i = 0; i < 1000; i++) { this.count++ }
- 为什么是异步 DOM 更新?
- 性能的考虑
- 因为对于前端来说, 修改数据进行 DOM 操作是常有的事情,如果频繁操作 DOM,会严重影响页面的加载性能
- DOM 操作这是前端的性能的瓶颈
- 比如 : for (let i = 1; i < 10000; i++>) 如果同步 就要重新渲染 1000 次
- 验证 异步 DOM 更新 :
//2. 直接获取data 中的值 ,会立马获取成功
console.log(this.count)
this.count++
console.log(this.count)
// 但是 通过dom来获取count的值,因为DOM更新这个count值是异步的,是需要一点时间的
console.log(document.querySelector('h1').innerText) // 0
this.count = 100
console.log(document.querySelector('h1').innerText) // 0
-
需求 : 在数据更新后,立即获取到更新后的内容
DOM 更新后,会执行 this.$nextTick() 的回调函数,所以能拿到值
// setTimeout(() => {
// console.log(document.querySelector('h1').innerText)
// }, 1000)
this.$nextTick(() => {
console.log(document.querySelector('h1').innerText) // 100
})
一:过滤器
- 概念 :
- vue 中的过滤器(filter) : 数据格式化 ,
- 也就是说,让数据按照我们规定的一种格式输出
- 比如 : 对于日期来说,将日期格式化转化为
年-月-日 小时:分:秒
格式的过程
// 直接显示
<h1>{{ date }}</h1>
显示 : 2019-01-11T10:11:19.566Z
不是我们想要的
我们想要的 : 2019-01-11 18-11-53
- 全局过滤器 和 局部过滤器
- 说明 : 通过全局方式创建的过滤器,在任何一个 Vue 实例中都可以使用 (一般情况下,为了项目方便管理,都是一个 vue 实例)
- 注意点: 使用全局过滤器的时候,应该先创建全局过滤器,再创建 Vue 实例
- 局部创建的过滤器 只能在当前 vue 实例中使用
- 怎么注册 全局过滤器
// 第一个参数 : 过滤器的名字
// 第二个参数 : 是一个回调函数,只要使用过滤器的时候,这个回调函数就会执行
/// 通过回调函数的返回值得到格式化后的数据
Vue.filter('date', res => {
return '嘻嘻'
})
- 使用过滤器 示例 :
// 组件
<h1>时间戳-格式 {{ date2 | date }}</h1>
// js
Vue.filter('date', res => {
return `${res.getFullYear()}-${res.getMonth()}-${res.getDate()} ${res.getHours()}:${res.getMinutes()}:${res.getSeconds()}`
})
- moment 插件
- moment 地址
-
使用
1. 安装 : `npm i moment` 2. 引入 : 3. 使用
- 日期 => 指定格式
moment(res).format('YYYY-MM-DD HH-mm-ss')
- 时间戳 => 指定格式
moment(res).format('YYYY-MM-DD HH-mm-ss')
// 全局 Vue.filter('date', res => { return moment(res).format('YYYY-MM-DD HH-mm-ss') })
- 参数问题
- 示例
<h1>时间戳-格式 {{ date2 | date('YYYY-MM-DD HH-mm-ss',888) }}</h1>
// 默认值
Vue.filter('date', (res, format = 'YYYY-MM-DD', arg) => {
console.log(arg)
return moment(res).format(format)
})
-
局部过滤器
在 vm 的配置项里写一个
filters
对应的是一个对象
filters: {
date(res, format = 'YYYY-MM-DD', arg) {
return moment(res).format(format)
}
}
二:计算属性 computed
在模板中双向绑定一些数据或表达式,如果表达式过长或者逻辑更复杂时,就会变得臃肿和难以阅读,比如:
<div>
{{text.split(',').reverse().join(',')}}
<div>
<div id='app'>
{{reversedText}}
<div>
<script>
var app = new Vue({
el:'#app',
data:{
text:'123,456'
},
computed: {
reversedText: function(){
//这里的this指向的是当前的Vue实例
return this.text.split(',').reverse().join(',');
}
}
})
</script>
所有的计算属性都以函数的形式写在Vue实例内的computed选项内,最终返回计算后的结果。
你可以发现,这个例子完全可以用methods内的方法完成,甚至用methods的方法使用还能够接收参数,跟更加灵活,那么为什么要使用计算属性呢,因为计算属性是基于它的依赖缓存的。一个计算属性所依赖的数据发生变化时,它才会重新取值,所以text只要不改变,计算属性也就不更新,例如:
computed:{
now:function(){
return Date.now();
}
}
这里的Date。now() 不是响应式依赖,所以计算属性now不会更新。但是methods则不同,只要重新渲染,它就会被调用,因此函数也会被执行。
使用计算属性还是methods取决于你是否需要利用到缓存,当遍历大数组和做大量计算时,应当使用计算属性,除非你不希望得到缓存。
计算属性用法
在一个计算属性内可以完成各种复杂的逻辑,包括运算,函数调用等,只要最终返回一个结果就可以了。
计算属性可以依赖同一实例内多个数据,只要其中任意一个发生变化,计算属性就会重新执行,视图也会更新。
例如:假设计算两个商品的价格
<div id='app'>
总价:{{ prices }}
</div>
<script>
var app = new Vue({
el:'#app',
data:{
package1:[
{
name:'iphone 7',
price:7199,
count:2
},
{
name:'ipad',
price:2888,
count:1
}
],
package2:[
{
name:'apple',
price:3,
count:5
},
{
name:'banana',
price:2,
count:10
}
]
},
computed:{
prices:function(){
var prices = 0;
for(let i = 0,len = this.package1.length; i < len; i++){
prices += this.package1[i].price * this.package1[i].count;
}
for(let i = 0,len = this.package2.length; i < len; i++){
prices += this.package2[i].price * this.package2[i].count;
}
return prices;
}
}
})
</script>
计算属性除了可以依赖同一实例的多个数据,也可以依赖不同实例的数据,例如:
<div id='app1'></div>
<div id='app2'>
{{ reversedText }}
</div>
<script>
var app1 = new Vue({
el:'#app1',
data:{
text:'123,456'
}
});
var app2 = new Vue({
el:'#app2',
computed:{
reversedText:function(){
//这里依赖的是实例app1的数据text
return app1.text.split(',').reverse().join(',');// => '456,123'
}
}
})
</script>
计算属性的getter与setter
每一个计算属性都包含一个 getter与setter,默认调用getter访问,在你需要时也可以提供一个setter。当手动修改计算属性的值时,就会触发setter函数。例如:
<div id='app'>
姓名: {{ fullName }}
</div>
<script>
var app = new Vue({
el:'#app',
data:{
name:'张伟'
},
computed:{
fullName:{
//getter,用于读取
get:function(){
return this.name;
},
//setter,用于写入
set:function(newName){
this.name = newName;
}
}
}
})
三 : 监听 watch
- 说明 : Vue 中可以通过 watch 配置项,来监听 vue 实例中数据的变化
-
基本使用
watch: { // 监听name属性的数据变化 // 作用 : 只要name的值发生变化,这个方法就会被调用 // 第一个参数 : 新值 // 第二个参数 : 旧值,之前的前 name(newVal,oldVal){ console.log('新 :',newVal); console.log('旧 :',oldVal); } }
-
基本使用案例 :
需求 : 监听用户名文本框字符个数(3-6),并显示格式验证
<input type="text" v-model="name" />
<span v-show="isShow">用户名的字符 在 6-12之间</span> if
(/^[0-9a-zA-Z]{3,6}$/.test(newVal)) { 验证 }
- 监听对象 (数组也属于对象)
// data :
data: {
obj: {
name: 'zs'
}
},
// 组件
<input type="text" v-model="obj.name" />
// 监听
- 开始监听对象的属性
// 从对象的角度来监听的
因为对象和数组都是引用类型,引用类型变量存的是地址,地址没有变,所以不会触发watch
obj:{
// 深度监听 属性的变化
deep:true,
// 立即处理 进入页面就触发
immediate: true,
// 数据发生变化就会调用这个函数
handler( newVal ) {
console.log( newVal.name );
}
},
// 从属性的角度来监听
'obj.name' ( newVal ) {
console.log('监听对象的属性',newVal);
}
- 计算属性和watch的区别
computed 和 watch的区别
computed : 计算属性
- 1.根据已知值 ,得到一个新值
- 2. 新值随着已知值(相关的数据)变化而变化
1. 计算属性 ==> (得到的是)新值
2. 计算属性(num) ==> 是别人影响了我
watch : 监听器
1. 监听 ==> (监听)已知值
2. 监听数据 (num2) => 是我影响到了别人
四 : 本地缓存
1.存储值
监听数组和监听对象一样 需要深度监听
保存值,记得把对象转化为字符串(存的快 省空间)
// 监听
watch: {
// 监听list
todoList: {
deep: true,
handler(newVal) {
// console.log('发生变化了', newVal)
// 保存起来
localStorage.setItem('todoList', JSON.stringify(newVal))
}
}
},
2.取值 , 在 data 中可以初始值
记得给一个默认值 空数组 []
const todoList = JSON.parse(localStorage.getItem('todoList')) || [],
五、生命周期函数
- 所有的 vue 组件,都是 vue 实例, 一个组件对应一个实例,并且接收相同的选项对象(一些根实例特有的选项除外)
- 实例生命周期也叫做 : 组件生命周期
生命周期介绍
- 简单说 : 一个组件(实例) 从开始到最后消灭所经历的各种状态,就是一个组件(实例)的生命周期
- 生命周期钩子函数的定义 : 从组件被创建,到组件挂在到页面上运行,再到页面关闭组件被销毁,这三个阶段总是伴随着组件各种的事件,这些事件,统称为组件的生命周期函数 (简称 : 钩子函数)
- 开发人员可以通过 vue 提供的钩子函数,让我们写的代码参与到 vue 的生命周期里面来,让我们的代码在合适的阶段起到相应的作用
注意 :
- 注意 : vue 在执行过程中 会自动调用
生命周期钩子函数
, 我们只需要提供这些钩子函数即可 - 注意 : 钩子函数的名称都是 vue 中规定好的
5.0 学习 vue 组件生命周期 学什么?
- Vue 内部执行的流程
- 钩子函数如何使用 (两个重要的钩子函数 created mounted)
5.1 钩子函数 - beforeCreate
- 说明 : 在实例初始化之前,数据观测 和 event/watcher 事件配置之前被调用
- 组件实例刚被创建,组件属性计算之前, 例如 data 属性 methods 属性
- 注意 : 此时,无法获取 data 中的数据 和 methoids 中的方法
- 场景 : 几乎不用
5.2 钩子函数 - created
- 说明 : 组件实例创建完成,属性已绑定, 可以调用 methods 中的方法、可以获取 data 值
- vue 实例生命周期 参考 1
- vue 实例生命周期 参考 2
- 使用场景 : 1-发送 ajax 2-本地存储获取数据
beforeCreate() { // 无法获取数据和事件 console.warn('beforeCreate', this.msg, this.fn) }, created() { console.warn('created', this.msg, this.fn) },
5.3 钩子函数 - beforeMounted()
- 说明 : 在挂载开始之前被调用 (挂载:可以理解DOM 渲染)
5.3 钩子函数 - mounted()
- 说明 : 挂载之后, DOM 完成渲染
- 使用场景 : 1-发送 ajax 2-操作 DOM
记得把template去掉 // 渲染DOM之前 beforeMount() { // 渲染之前的 <h1 id="h1" @click="fn">{{ msg }}</h1> console.log(document.querySelector('h1')) }, // 渲染DOM之后 <h1 id="h1">测试</h1> mounted() { console.log(document.querySelector('h1')) }
5.4 钩子函数 - beforeUpdated()
- 说明:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
-
注意:此处获取的数据是更新后的数据,但是获取页面中的 DOM 元素是更新之前的
小提示 : 打印 this.$el ,打开小三角是之后的,是因为打印是有监听的功能,展示的是后面更改之后的
5.5 钩子函数 - updated()
- 说明:组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。
beforeUpdate() { // 更新之前的值 : 信息 console.warn('beforeUpdate',document.querySelector('h1').innerText) }, updated() { // 更新之后的值 : 信息1111 console.warn('updated', document.querySelector('h1').innerText) }
5.6 钩子函数 - beforeDestroy()
- 说明:实例销毁之前调用。在这一步,实例仍然完全可用。
- 使用场景:实例销毁之前,执行清理任务,比如:清除定时器等
created() {
this.timerId = setInterval(() => {
console.log(1111);
}, 500);
},
// 如果当组件销毁了,还不清除定时器会出现性能问题
// 在浏览器中可以尝试销毁 vm.$destroy()
// 最后销毁
beforeDestroy() {
clearInterval(this.timerId)
},
5.7 钩子函数 - destroyed()
说明:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
六 : 使用钩子函数来完善 数据存储
created {
this.list = JSON.parse(localStorage.getItem('list'))
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。