一、生命周期函数
1.创建期
创建(实例化)期 , 会自动执行 且只会执行一次
vue2中的实例化期 的方法 beforeCreate 和 created 被 setup 代替了
2.挂载期
挂载期 , 会自动执行 且只会执行一次。可以在这里发送网络请求,创建定时器,监听事件
//挂载期
onBeforeMount(()=>{
console.log('onBeforeMount 挂载前');
})
onMounted(()=>{
console.log('onMounted 挂载完成');
3.更新期
更新期的方法可以反复执行
//更新期
onBeforeUpdate(()=>{
console.log('onBeforeUpdate 更新前');
})
onUpdated(()=>{
console.log('onUpdated 更新完成');
})
4.卸载期
卸载期的方法只会执行一次
//卸载期
onBeforeUnmount(()=>{
console.log('onBeforeUnmount 卸载前');
//可以在这里取消发送网络请求,销毁定时器,取消事件监听
})
onUnmounted(()=>{
console.log('onUnmounted 卸载完成');
})
5.捕获来自子组件的错误
可以在 errorCaptured()
中更改组件状态来为用户显示一个错误状态。
二、组件通信
1.父向子传值
1.父组件在子组件身上通过自定义属性传值,
2.子组件内部通过defineProps接收值
父组件
<template>
<div class="app">
<child :count="count"/>----在父组件内部渲染的子组件身上通过自定义属性money传值给外部的子组件
</div>
</template>
<script setup>
import {ref} from 'vue'
import Child from './components/Child.vue'---导入子组件
var count = ref(100)
</script>
子组件
<template>
<div class="child">
<h3>child子组件 - {{count}}</h3>
</div>
</template>
<script setup>
import { defineProps} from 'vue'
var {count} = defineProps({----defineProps接收值,并且defineProps中的数据是只读的值( 不能直接修改 )
count: Number,
})
</script>
<style>
</style>
2.子向父传值
1.父组件在子组件身上绑定自定义事件并设置回调函数
2.子组件内部通过defineEmits获取emit方法, 调用emit方法触发事件并传值.
父组件
<template>
<div class="app">
<!-- 渲染子组件 -->
<child @msg="getMsg"/>---在子组件身上绑定自定义事件msy并指定一个回调函数getMsy
</div>
</template>
<script setup>
import child from './components/child.vue'----导入子组件
let getMsy=(data)=>{
console.log('从子组件传来的值:',data);
}
</script>
<style>
</style>
子组件
<template>
<div class="child">
<h3>child 组件 {{str}} <button @click="haneleClick">传值</button> </h3>
</div>
</template>
<script setup>
import {ref} from 'vue'
import {provide} from 'vue'
var str = ref("vue3 composition api")
var emit = defineEmits(['msg']);---获取emit
var haneleClick = ()=>{
emit('msg',8888);---触发事件并传值
}
</script>
<style>
</style>
3.跨级传值
1.外层组件通过provide方法传值,
2.内层组件通过inject方法接收值.
外层组件
<template>
<div class="app">
<childx />
</div>
</template>
<script setup>
import childx from './components/childx.vue'----导入内层组件
import {ref} from 'vue'
provide('money',6666);---传值
</script>
内层组件
<template>
<div class="c">
<h3>c组件 - {{money}}</h3>
</div>
</template>
<script setup>
import { inject } from "vue";
var money = inject('money')---接收值
</script>
4.兄弟组件传值
1.先实例化一个公共的通信对象(mitt),
2.其中一个组件提前在mounted中用on监听事件并设置一个回调函数,
3.另外一个兄弟组件通过emit去触发事件并传值.
与vue2兄弟组件传值一致
兄组件:传递值
<template>
<div class="childa">
<h3>childa组件</h3>
<button @click="handleClick">传值给b组件</button>
</div>
</template>
<script>
import mitt from '../utils/eventbus'---------导入通信对象
export default {
methods:{
handleClick(){
mitt.emit('trandferdata','我喜欢你!')-------mitt.emit触发事件并传值
}
}
}
</script>
<style>
</style>
公共的通信对象
前提:下载mitt(npm i mitt)
import mitt from 'mitt'
export default mitt()----实例化 通信对象 并导出
弟组件:接收值
<template>
<div class="childb">
<h3>childb组件</h3>
</div>
</template>
<script>
import mitt from '../utils/eventbus'---------导入通信对象
export default {
methods:{
getdata(data){
console.log('接收到a组件传来的值:',data);
}
},
mounted(){
mitt.on('trandferdata',this.getdata)--------监听事件并设置一个回调函数
},
beforeUnmount(){
mitt.off('trandferdata',this.getdata)-------防止内存泄漏取消监听
}
}
</script>
<style>
</style>
三、使用ref
1.获取dom节点
1.在标签身上定义一个ref属性,
2.在组件实例化时定义一个ref变量 变量的名称必须和标签身上的ref属性值相同
3.在组件挂载完成后就可以通过ref变量获取标签的dom节点
<template>
<div class="app">
<input ref="inputbox" type="text" placeholder="搜索商品">---标签身上定义一个ref属性
</div>
</template>
<script setup>
import {onBeforeMount, onMounted,ref} from 'vue'
var inputbox = ref(null)---定义一个ref变量 变量的名称必须和标签身上的ref属性值相同
onBeforeMount(()=>{
console.log('onBeforeMount 挂载前');
})
onMounted(()=>{
console.log('onMounted 挂载完成');
console.log( inputbox.value );
})
</script>
2.获取子组件实例
1.子组件身上定义一个ref属性
2.在组件实例化时定义一个ref变量 变量的名称必须和标签身上的ref属性值相同
3.在组件挂载完成后就可以通过ref变量获取子组件的实例
注意: 子组件内部必须使用defineExpose暴露对应的方法, 父组件才可以获取子组件的实例并调用子组件的方法
父组件
<template>
<div class="app">
<Dialog ref="dialogcom" />---子组件身上定义一个ref属性
</div>
</template>
<script setup>
import {onBeforeMount, onMounted,ref} from 'vue'
import Dialog from './components/Dialog.vue'----导入子组件
var dialogcom = ref(null)----定义一个ref变量 变量的名称必须和标签身上的ref属性值相同
onBeforeMount(()=>{
console.log('onBeforeMount 挂载前');
})
onMounted(()=>{
console.log('onMounted 挂载完成');
console.log( dialogcom.value );----获取到子组件的实例,但是并不能使用子组件的数据或者方法,因为子组件的方法的方法被私有化,使用前需要子组件内部先暴露
})
</script>
子组件 :在子组件中, 所有的状态变量, 方法 都被私有化了, 其他组件想要调用子组件的方法, 子组件内部必须暴露对应的方法.
<script setup>
import { ref,defineExpose } from "vue";
var isvisiable = ref(false);
var show = ()=>{
console.log('show');
isvisiable.value = true;
}
var hide = ()=>{
isvisiable.value = false;
}
defineExpose({----对外暴露一些方法
show
})
</script>
四、pinia
Pinia 是 Vue 的专属状态管理库,允许跨组件或页面共享状态。目的是设计一个拥有组合式 API 的 Vue 状态管理库。
步骤:
1.defineStore() 定义一个数据模块( 负责管理一部分数据 )
参数一: 模块名
参数二: 回调函数, 回调函数当中的代码决定了该模块管理了哪些数据, 以及如何管理这些数据
2.实例化数据模块并导出
3.暴露模块内的数据和方法
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'---------1.定义一个数据模块
export const usetlStore = defineStore('tl', () => {------2.实例化usetlStore并导出
定义状态
var tasklist = ref([]);
定义计算方法
var totalCount = computed(()=>{
return tasklist.value.length;
})
var finishedCount = computed(()=>{
return tasklist.value.filter(item=>item.status).length;
})
var unfinishedCount = computed(()=>{
return tasklist.value.filter(item=>!item.status).length;
})
var addTask = (name)=>{---------------------新增任务
//1.构造一个新的任务对象
var obj = { id: tasklist.value.length+1 ,name ,status:false };
//2.添加任务对象到任务列表中
tasklist.value.push(obj);
}
var changeTaskStatus = (id)=>{--------------更改任务状态
//1.查找id对应的任务
var task = tasklist.value.find(item=>item.id == id);
//2.更改找到的任务对象的状态
if( task ){
task.status = !task.status;
}
}
var deleteTask = (id)=>{--------------------删除任务
//1.查找id对应的任务
var i = tasklist.value.findIndex(item=>item.id == id);
//2.删除对应的任务
if( i != -1 ){
tasklist.value.splice(i,1);
}
}
3.暴露模块内的数据和方法
return {
tasklist,
totalCount,
finishedCount,
unfinishedCount,
addTask,
changeTaskStatus,
deleteTask
}
})
五、路由
步骤:
1.导入userRouter:import { useRouter } from 'vue-router'
2.实例化router:var router = useRouter()
<template>
<div class="tasklist">
<!-- 动态渲染任务列表( 从tl模块 ) -->
<div class="task" v-for="(item,index) in tl.tasklist" :key="index">
<div class="left">
<input type="checkbox" :checked="item.status" @click="handleClick(item.id)">
<span>{{item.name}}</span>
</div>
<span @click="handleReview(item.id)">查看</span>
<span @click="handleDelete(item.id)">删除</span>
</div>
</div>
</template>
<script setup>
import { usetlStore } from '../stores/tl'---导入usetlStore
import { useRouter } from 'vue-router' ------------------1.导入tl模块
var tl = usetlStore();------实例化tl模块
var router = useRouter()---------------------------------2.实例化router
var handleClick = (id)=>{
tl.changeTaskStatus( id );-----更改任务状态
};
var handleReview = (id)=>{
router.push({ path:'/detail',query:{id} });----------3.跳路由到详情页
};
var handleDelete = (id)=>{
tl.deleteTask(id);---------删除任务
}
</script>