生命周期(钩子)、指令标签、Composition API
一、生命周期(钩子)
1. 创建期间的生命周期函数
-
创建期间的生命周期函数:
- beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好data和 methods 属性
- created:例已经在内存中创建OK,此时data和methods已经创建OK,此时还没有开始编译模板
- beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中
- mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示
2. 运行期间的生命周期函数
-
运行期间的生命周期函数:
- beforeUpdate:状态更新之前执行此函数,此时data 中的状态值是最新的,但是界面上显示的数据还是旧的,因为此时还没有开始重新渲染DOM节点
- updated:实例更新完毕之后调用此函数,此时data 中的状态值和界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了
3. 销毁期间的生命周期函数
-
销毁期间的生命周期函数:
- beforeUnmounted:实例销毁之前调用。在这—步,实例仍然完全可用.
- unmounted:Vue实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
4. 总结Xmind
二、指令标签
1.事件指令——v-on
事件指令v-on:click=“handleClick” 简写成 @click="handleClick"
1.1 事件执行多方法
<button @click="handleBtnClick1(), handleBtnClick2()">多调用新增</button>
1.2 子标签点击才执行方法
<div @click.self="selfEvent">
{{counter}}
<button @click="handleBtnClick()">>
通过.self修饰符,比如这里{{counter}}点击才会执行selfEvent方法
</button>
</div>
//类似的事件修饰符还有 .prevent .once .capture .passive
1.3 禁止冒泡事件执行
<div @click="maopaopao">
<button @click.stop="handleBtnClick()">通过.stop修饰符来禁止maopaopao事件的执行</button>
</div>
1.4 按键与鼠标修饰符
//按键修饰符 .enter键 .tab .delete esc up down left right
//鼠标修饰符 left right middle
<div>
<input @keydown="handleKeyDown"/>
<input @keydown.enter="enterDown"/>
<div @click.ctrl.exact="ctrlAndMouseDown"/>按住ctrl+鼠标点击这个div才执行事件</div>
</div>
1.5 事件DOM操作
<button @click="handleBtnClick(2, $event)">新增</button>
handleBtnClick(num, event){
//event可获得原生js事件,获得一些dom属性进行操作
console.log(event.target);
this.counter += num;
}
2. 循环指令——v-for
2.1 循环数组
<div v-for="(item, index) in list" :key='index'>{{item}}--{{index}}</div>
data(){
return {
list: ['lee', 'bill', 'bob' ],
}
},
2.2 循环数组对象
<template v-for="(value, key, index) in listObject" :key="index">
<div v-if="key !== 'lastName'">
{{value}}--{{key}}--{{index}}
</div>
</template>
data(){
return {
listObject: {
firstName: 'lee',
lastName: 'dell',
job: 'teacher'
},
}
},
2.3 v-for与v-if优先级问题,活用template标签
<!--
if 和 for在同一个div内时,for级别比if高,if会失效,所以把if单独提出来写
-->
<div v-for="(value, key, index) in listObject" :key="index">
<div v-if="key !== 'lastName'">
{{value}}--{{key}}--{{index}}
</div>
</div>
<!--
但是上面那种循环会多生成div层,所以可以用template标签做占位符
-->
<template v-for="(value, key, index) in listObject" :key="index">
<div v-if="key !== 'lastName'">
{{value}}--{{key}}--{{index}}
</div>
</template>
3. 标签展示、DOM加载指令——v-show、v-if
标签展示与不展示指令,相当于:style="display:block/none"
v-if
v-else-if
v-else 要连接使用
会消除DOM节点,对于经常变化的标签建议使用v-show
4. 文本展示方式指令——v-text、v-html
v-html会将文本里面的html标签进行转义输出
5. 数据绑定与交互指令——v-bind、v-model、插值表达式
5.1 v-bind
v-bind:value="inputValue"可简写为:value="inputValue"
支持类型:html中的属性、css的样式、对象、数组、number 类型、bool类型
数据值可在data或setup函数中定义
// 绑定文本
<p v-bind="message"></p>
// 绑定属性
<p v-bind:src="http://...."></p>
<p v-bind:class="http://...."></p>
<p v-bind:style="http://...."></p>
// 绑定表达式
:class{className:true}
5.2 v-model
数据绑定形式。一般用于表单数据绑定
表单常用标签:input、textarea、checkbox、radio、select
<template>
<!--下拉框-->
<select v-model="selected">
<option value="A被选">A</option>
<option value="B被选">B</option>
<option value="C被选">C</option>
</select>
<span>Selected: {{ selected }}</span>
<!--单选按钮-->
<input type="radio" id="small" value="small_value" v-model="picked">
<label for="small">small</label>
<br>
<input type="radio" id="big" value="big_value" v-model="picked">
<label for="big">big</label>
<br>
<span>Picked: {{ picked }}</span>
<!--复选框-->
<input type="checkbox" id="one" value="value_one" v-model.lazy="checkedNames">
<label for="one">选项一</label>
<input type="checkbox" id="two" value="value_two" v-model.lazy="checkedNames">
<label for="two">选项二</label>
<input type="checkbox" id="three" value="value_three" v-model.lazy="checkedNames">
<label for="three">选项三</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</template>
data(){
return {
selected: '',
picked: '',
checkedNames: []
}
}
v-model也可以和.lazy、.trim和.number这些修饰符一起使用
<!-- 在每次 input 事件触发后将输入框的值与数据进行同步,添加 lazy 修饰符,
从而转变为使用 change 事件进行同步 -->
<input v-model.lazy="msg" >
<!--去除字符串首尾的空格-->
<input v-model.trim="msg">
<!--将数据转化为值类型-->
<input v-model.number="age" type="number">
5.3 插值表达式
可写js表达式:{{Math.max(1,2,3)}}
也可直接写:{{content}}
6. 一些其他常用指令——v-pre、v-once、v-block
7.总结Xmind
三、Composition API
1. 安装使用
首先利用cli4创建一个demo下载composition-api在main.js中引入使用
//下载
npm install --save @vue/composition-api
//在main.js 引入官方提供的vue-composition-api库
import VueCompositionApi from '@vue/composition-api';
Vue.use(VueCompositionApi)
2. 数据方法入口——setup()
之前定义的data,methods等都统一放入setup中实现
//home.vue里
<setup :data="123"></setup>
//setup.vue里
export default {
name:'Setup',
setup(props,context){
console.log(props.data)//123
console.log(context)
},
props:{
data:Number
}
}
// console.log(context)输出结果
{
root: (...),
parent: (...),
refs: (...),
attrs: (...),
listeners: (...),
isServer: (...),
ssrContext: (...),
emit: (...),
slots: {},
}
3. 代理对象多——reactive()
reactive()函数接受一个普通对象,返回一个响应式的数据对象.类似于2.x的组件里的data()函数,想要使用必须先引入reactive,模板中想要使用该数据必须return出去,此函数只能在setup函数里使用.
<template>
<div>
<span style="margin-right:10px">{{state.count}}</span>
<el-button type="primary" @click="changeCount">点击累加</el-button>
</div>
</template>
<script>
import { reactive } from '@vue/composition-api';
export default {
name:'Setup',
setup(){
//state响应式的数据对象
const state= reactive({
count:1
})
function changeCount() {
state.count++;
}
return{
state,
changeCount
}
}
}
//也可以return state 如这样返回在模板直接{{count}}就可以取到值
4. 代理对象一——ref()
4.1 ref会返回一个对象,并且只有value属性,不像reactive返回多个自定义的
//注意在setup内部访问值需要.value,在模板直接拿值可以使用
<template>
<div>{{count}}---{{name}}</div>
</template>
<script>
import {ref} from '@vue/composition-api';
export default {
name:'Ref',
setup(){
const count=ref(0);
//ref会返回一个对象,并且只有value属性
console.log(count.value)//0
console.log(name.value) //undefined
return {
count,
name:ref('zdb')
}
}
}
</script>
4.2 ref与reactive联动,不用.value调值
<template>
<div>{{state.count}}</div>
</template>
<script>
import { ref ,reactive } from '@vue/composition-api';
export default {
name:'Ref',
setup(){
const count=ref(0);
//ref会返回一个对象,并且只有value属性
const state=reactive({
count
})
state.count++;
return {
state
}
}
}
</script>
4.3 新的ref会覆盖旧的ref
<script>
import { ref ,reactive } from '@vue/composition-api';
export default {
name:'Ref',
setup(){
const c1=ref(0)
const state=reactive({
c1
})
const c2=ref(9)
state.c1=c2;
state.c1++;
console.log(c1.value) //0
console.log(c2.value) //10
console.log(state.c1) //10
}
}
</script>
5. 转换代理对象——toRef()
可以将reactive()创建出来的响应式对象,转换为普通的对象
//将reactive里定义的item转化为普通对象出来
const data = reactive({ item:{} });
const getItemData = async() => {
const result = await get(`/api/shop/${route.params.id}`)
data.item = result.data
}
const { item } = toRefs(data)
return { item, getItemData }
6. 计算函数——computed()
用来创建计算属性,computed()函数的返回值是一个ref的实例,使用computed之前需要按需导入
1.创建只读计算属性
<script>
import {ref , computed} from '@vue/composition-api';
export default {
name:'Computed',
setup(){
const count = ref(1);
const plusOne=computed(()=>{ return count.value++ })
console.log(plusOne.value) //1
plusOne.value++ //error
}
}
</script>
2.创建可读可写的计算属性
<template>
<div>
<div>count:{{count}}</div>
<div>computed:{{countComputed}}</div>
<el-button type="primary" @click="changeCount">点击累加</el-button>
</div>
</template>
<script>
import {ref , computed} from '@vue/composition-api';
export default {
name:'Computed',
setup(){
const count = ref(1);
const countComputed=computed({
//读取函数
get:()=> count.value+1,
//赋值函数
set:(val)=>count.value=val
})
const changeCount=()=>{
count.value++;
}
return{
count,
countComputed,
changeCount
}
}
}
</script>
京东到家项目代码实例(只应用了get然后返回了):
const calculations = computed(() => {
const productList = cartList[shopId]?.productList
const result = { total: 0, price: 0, allChecked: true}
if(productList) {
for(let i in productList) {
const product = productList[i]
result.total += product.count
if(product.check) {
result.price += (product.count * product.price)
}
if(product.count > 0 && !product.check) {
result.allChecked = false
}
}
}
result.price = result.price.toFixed(2)
return result
})
7. 监听函数——watch()
7.1 监听数据源变化做成一些操作、定时操作
7.2 可监听ref数据源,reactive数据源,多数据源
//reactvie
<script>
import { watch ,ref, reactive, toRefs } from '@vue/composition-api';
export default {
name:'Watch',
setup(){
const state=reactive({
count:0,
name:'zdb'
})
watch(
[()=>state.count,()=>state.name], //Object.values(toRefs(state))
([newCount,newName],[oldCount,oldName])=>{
console.log(`新的count${newCount}`)
console.log(`新的name${newName}`)
console.log(`旧的count${oldCount}`)
console.log(`旧的name${oldName}`)
},
//去掉此项页面会报错
{
lazy:true
}
)
setTimeout(()=>{
state.count+=15;
state.name+='zs'
},2000)
return{
state
}
},
}
</script>
//ref
<script>
import { watch ,ref, reactive, toRefs } from '@vue/composition-api';
export default {
name:'Watch',
setup(){
const count=ref(0);
const name=ref('zdb');
watch(
[count,name],
([newCount,newName],[oldCount,oldName])=>{
console.log(`新的count${newCount}`)
console.log(`新的name${newName}`)
console.log(`旧的count${oldCount}`)
console.log(`旧的name${oldName}`)
},
{
lazy:true
}
)
setTimeout(()=>{
count.value+=15;
name.value+='zs'
},2000)
return{
count,
name
}
},
}
</script>
7.3 消耗性能,可监听数据到一定阈值,取消watch函数
8. provide()&inject()
provide和inject可以实现嵌套组件之间数据传递.这两个函数只能在setup中使用.父组件中使用provide()函数向下传递数据,子组件使用inject()获取上层传递来的数据
//父组件
<template>
<div class="home">
父组件:
<Provide></Provide>
</div>
</template>
<script>
import Provide from '@/components/provide.vue'
import {provide,ref} from '@vue/composition-api'
export default {
name: 'Home',
components: {
Provide
},
setup(){
const msg=ref('我是父组件传递来的数据');
//参数一:共享的名称 参数二:共享的数据
provide('sendMsg',msg)
return {
msg
}
}
}
</script>
//子组件
<template>
<div>子组件:{{msg}}</div>
</template>
<script>
import {inject,ref} from '@vue/composition-api'
export default {
name:'Provide',
setup(){
const msg=inject('sendMsg')
return {
msg
}
}
}
</script>