学习笔记目录:
更新中…
生命周期和数据共享
1. 生命周期&生命周期函数
生命周期(Life Cycle)是指一个组件从创建 -> 运行 -> 销毁的整个阶段,强调的是一个时间段。生命周期函数:是由 vue 框架提供的内置函数,会伴随着组件的生命周期,自动按次序执行。
注意:生命周期强调的是时间段,生命周期函数强调的是时间点。
- Vue生命周期函数 也叫Vue生命周期钩子,就是Vue实例在某一时间点自动执行的函数。一个有11个生命周期函数,
分别是:
- 组件的创建阶段:(组件生命周期的第一阶段)
beforeCreate : 创建Vue实例前的时候执行,
created : 创建Vue实例完成后执行,
beforeMount : Vue实例开始渲染前执行,
mounted : Vue实例渲染完成后执行,
- 组件运行阶段(组件生命周期的第二阶段)
beforeUpdate : Vue实例修改前执行,
updated : Vue实例修改完成后执行,
- 组件销毁阶段(组件生命周期的第三阶段)
beforeDestroy : Vue开始消亡前执行,
destroyed : Vue实例消亡后执行,
生命周期图示
下图展示了实例的生命周期。你不需要立马弄明白所有的东西,不过随着你的不断学习和使用,它的参考价值会越来越高。
组件之间的数据共享
1. 组件之间的关系
在项目开发中,组件之间的最常见的关系分为如下两种:
① 父子关系
② 兄弟关系
2. 父子组件之间的数据共享
父子组件之间的数据共享又分为:
① 父 -> 子共享数据
② 子 -> 父共享数据
2.1 父组件向子组件共享数据
父组件向子组件共享数据需要使用自定义属性。示例代码如下
App.vue 文件代码
<template>
<div class="app-container">
<h1>App 根组件</h1>
<hr />
<div class="box">
<!-- 渲染 Left 组件和 Right 组件 -->
<!-- 这里面的属性,我们使用绑定的方式,绑定的时候,传入的是变量;不绑定的时候传入的是字符串 -->
<!-- msg 传入的是值,直接赋值给对方;user 对象 传入的是userInfo 这个对象的引用 -->
<!-- 简单值是直接复制一份传过去;复杂一点的是把数据的引用给传过去 -->
<Left :msg="message" :user="userInfo"></Left>
</div>
</div>
</template>
<script>
import Left from './components/Left.vue'
export default {
data(){
return {
message:'hello',
userInfo:{ name:'jack',age:18}
}
},
components:{
Left,
}
}
</script>
Left.vue 文件的代码
<template>
<div class="left-container">
<h3>Left 组件</h3>
<p>传过来 msg 的值 {{msg}} </p>
<p>传过来 user 的值 {{user}} </p>
</div>
</template>
<script>
export default {
props:['msg','user']
}
</script>
还需要知道的是:我们一般不建议修改 props 的值,有可能会报错(以对象的方式(传过来的是对象的引用)修改对象中的值的话,修改的源对象中的属性的值,但是仍然是一般不建议)
2.2 子组件向父组件共享数据
子组件向父组件共享数据使用自定义事件。示例代码如下:
父组件代码 App.vue
<template>
<div class="app-container">
<h1>App 根组件-----{{countFromSon}}</h1>
<div class="box">
<!-- 渲染 Left 组件和 Right 组件 -->
<Right @numChange='getNewNum'></Right>
</div>
</div>
</template>
<script>
import Right from './components/Right.vue'
export default {
data(){
return {
// 定义一个变量用来之后接收子组件传过来的值
countFromSon:0
}
},
components:{ Right },
methods:{
// 获取子组件传递过来的数据的方法
//子组件中的触发相应事件(本例中的点击事件)之后,会执行相应的函数(本例中的创建自定义点击事件,并传递参数 count),进而触发父组件中的事件(本例中的 @@numChange='getNewNum' 即执行getNewNum函数,并传递进去之前子组件传过来的参数 ),然后父组件就得到子组件的值了
getNewNum(val){
this.countFromSon=val
}
}
}
</script>
子组件代码 Right.vue
<template>
<div class="right-container">
<button @click="add"> +1 </button>
</div>
</template>
<script>
export default {
data(){
return{
// 子组件自己的数据,将来希望把 count 传递给父组件
count:0
}
},
methods:{
add(){
this.count += 1
// 修改数据时,通过 $emit() 触发(定义)自定义事件---就比如 @click 是点击事件
// $emit() 中的第一个参数是自定义事件(方法)名,第二个参数是向该自定义事件(方法)
this.$emit('numChange',this.count)
}
}
}
</script>
3. 兄弟组件之间的数据共享
在 vue2.x 中,兄弟组件之间数据共享的方案是 EventBus。
- EventBus 的使用步骤
① 创建 eventBus.js 模块,并向外共享一个 Vue 的实例对象
② 在数据发送方,调用 bus.$emit(‘事件名称’, 要发送的数据) 方法触发自定义事件
③ 在数据接收方,调用 bus.$on(‘事件名称’, 事件处理函数) 方法注册一个自定义事件
eventBus.js
import Vue from 'vue'
export default new Vue()
数据发送方
<script>
// 1.导入js模块
import bus from './eventBus'
export default {
data(){
return{
str:'sendData'
}
},
methods:{
// 通过 eventBus 来发送数据
send(){
bus.$emit('share',this.str
}
}
}
</script>
数据接收方
<script>
// 1.导入js模块
import bus from './eventBus'
export default {
data(){
return{
//定义一个接收值的属性
msgFromLeft:''
}
},
created(){
// 2.绑定自定义事件
bus.$on('share',(val)=>{
this.msgFromLeft=val
})
}
}
</script>
ref 引用
1. 什么是 ref 引用
前言:
vue 有一个优势:MVVM 在 vue 中,程序员不需要操作 DOM ,只需要把数据维护好即可!(vue 的数据驱动视图,数据会自动更新而且不会重新加载页面);所以我们在 vue 项目里面是不建议使用 DOM 的,但是如果必须要操作 DOM 的话,我们就可以使用 vue 给我们内置的一个对象 $refs 来实现
ref 用来辅助开发者在不依赖于 jQuery 的情况下,获取 DOM 元素或组件的引用。
2. 使用 ref 引用 DOM 元素
每个 vue 的组件实例上,都包含一个 $refs 对象,里面存储着对应的 DOM 元素或组件的引用。默认情况下,组件的 $refs 指向一个空对象。当给标签加上 ref 属性之后,我们就可以通过 $refs 对象的属性(标签的 ref 属性值来获取相应的 DOM 元素),之后就可以对该 DOM 元素进行进一步的操作。示例代码如下:
<template>
<div class="app-container">
<h1 ref="myh1">App 根组件-----countFromSon</h1>
<button @click="changeStyle">点击改变样式</button>
</div>
</template>
<script>
export default {
methods:{
changeStyle(){
this.$refs.myh1.style.color='red'
}
}
}
</script>
3. 使用 ref 引用组件实例
与之前对于普通的标签操作类似,我们直接在组件标签上面加上 ref 属性即可实现
Test.vue 组件
<template>
<div class="test-container">
<h3>测试 组件======{{count}}</h3>
<button @click="addOne">+1</button>
<button @click="reset">重置</button>
</div>
</template>
<script>
export default {
data(){
return{ count:0 }
},
methods:{
addOne(){
this.count++
},
reset(){
this.count=0
}
}
}
</script>
<style lang='less'>
.test-container {
padding: 0 20px 20px;
background-color: orange;
min-height: 250px;
flex: 1;
}
</style>
App.vue
<template>
<div class="app-container">
<h1 ref="myh1">App 根组件</h1>
<button @click="onReset">重置子组件中的 count 值为0</button>
<Test ref='comeTest'></Test>
</div>
</template>
<script>
import Test from './components/Test.vue'
export default {
components:{
Test
},
methods:{
onReset(){
//相当于在这里我们通过使用 $refs 直接获得了子元素的示例,然后直接对其进行操作,调用方法,修改数据都是可以的!
// this.$refs.comeTest.reset()
this.$refs.comeTest.count=0
}
}
}
</script>
小扩展:失去焦点的事件:blur; 实现获取焦点:DOM.foucs()
4. this.$nextTick( callback ) 方法
组件的 $nextTick( callback ) 方法,会把 callback 回调推迟到下一个 DOM 更新周期之后执行。通俗的理解是:等组件的DOM 更新完成之后,再执行 callback 回调函数。从而能保证 callback 回调函数可以操作到最新的 DOM 元素。
如下是:点击按钮显示输入框并自动获取焦点
<template>
<input type="text" v-if="inputVisable" ref="ipt"/>
<button v-else @click="showInput">展示 input 输入框</button>
</template>
<script>
export default {
data(){
return {
//默认不显示输入框
inputVisale:false
}
},
methods:{
//显示输入框并获取焦点的方法
showInput(){
this.inputVisale=true
//这里是把对文本框的操作推迟到下一次 DOM 更新之后,否则页面上就根本不存在文本元素
//因为在我们调用这个方法之前,inputVisale 的值是 false ,再加上显示与否使用的是 v-if 即:显示的话=>有该元素;不显示的话=>不存在该元素,
//当上面将 inputVisale 设置为TRUE 之后还未来得及渲染到本页面上面,即好没有创建这个元素的时候,我们也就无法获得,这里使用 .$nextTick() 方法将这里面的语句给推迟到更新完成之后执行
this.$nextTick(()=>{
this.$refs.ipt.focus()
})
}
}
}
</script>
购物车案例
1. 项目开始前需要知道的:
① 能够知道 vue 中常用的生命周期函数
-
创建阶段、运行阶段、销毁阶段
-
created、mounted
② 能够知道如何实现组件之间的数据共享
-
父 -> 子(自定义属性)
-
子 -> 父(自定义事件)
-
兄弟组件(EventBus)
③ 能够知道如何使用 ref 引用 DOM 元素或组件
-
给元素或组件添加 ref=“xxx” 的引用名称
-
通过 this.$refs.xxx 获取元素或组件的实例
-
$nextTick() 函数的执行时机
2. 项目中的几个需要注意的过程:
2.1 主页面
导入 Header Goods Footer 三个组件并使用
这三个组件里面的父–>子的传递我们都使用 props (需要注意的是:我们传值的时候不要忘了属性的绑定,不然传的就可能是字符串,而不是我们想要传递的值了)
还有就是通过 axios 的 get 请求来获取数据,注意,这里面我们会把这个获取数据的过程包装成为一个方法,然后在生命周期里面的 Created 周期里面执行该函数。
// 生命周期函数(创建完成之后要执行的函数)
created(){
// 调用请求数据的方法
this.initCartList()
},
methods:{
// 封装请求列表数据的方法
async initCartList(){
// 调用axios 的get请求
const {data:res}= await axios.get('https://www.escook.cn/api/cart')
// 只要是请求得到的数据,在页面的渲染期间要使用到,则必须转存到 data 中(否则我们是无法访问到的)
if(res.status===200){
this.list=res.list
}
},
},
2.2 商品的选择(前面的选择按钮)
单个商品前面的复选框:
子组件中的复选框选中之后,通过父—>子 的方式将选择状态传递给父组件并更新到对应的 list 列表中的属性里面
2.3 Footer 中的全选框
将 Footer 组件中的全选框的选中状态,通过子—>父传递给父组件,然后遍历 列表中的元素,分别赋值给列表中元素的属性
2.4 Footer 中 总价格的计算:(Footer 组件中的 结算后面的商品数量,使用的方法和这个类似)
首先在主界面中计算出来,然后通过子传值传递给子组件进行显示
// 已勾选商品的总价格
amt(){
// 1. 先进性过滤; 2.使用reduce 进行累加
return this.list.filter(item=>item.goods_state)
.reduce((total,item)=>total+=item.goods_price*item.goods_count,0)
}
2.5 Goods 组件用来展示数量
调用 Counter 组件,父—>子 传值,渲染 Counter 组件上的数量,数量的数据流向如下:
APP–>Goods—>Counter (还可以直接使用 EventBus 来传递)
这里我们需要知道的是:商品的数量和该商品的 id 是对应传递的,这样我们才能实现修改主页面上展示的商品的数量。
2.6 Counter 组件里面的点击加减事件
设置点击事件,之后通过相应的函数(定义一个对象,存放当前点击对象的 id 和他的 num 值加或者减 1 ,之后通过 EventBus 将数据传递给 App 组件)
学习笔记目录:
更新中…