生命周期
【options API】中,生命周期钩子是被暴露在vue实例上的选项,我们只需要调用使用即可。
【composition API】中,我们需要将生命周期钩子导入项目,然后才能使用。
注意格式的变化
<script>
import { onMounted } from 'vue';
export default {
setup(){
onMounted(()=>{
console.log("hello")
})
}
}
</script>
在这里,beforecreate和created被setup方法本身所替代,我们在在setup中将会访问到9个生命周期:
onBeforeMount:在挂载之前被调用,渲染函数render首次被调用
onMounted:组件挂载时调用
onBeforeUpdate:数据更新时调用,发生在虚拟DOM打补丁之前。
onUpdated:因数据更改导致的虚拟DOM重新渲染和打补丁时调用
onBeforeUnmount:在卸载组件实例之前调用,此阶段的实例依旧是正常的。
onActivated:被keep-alive缓存的组件激活时调用
onDeactivated:被keep-alive缓存的组件停用时调用
onErrorCaptured:当捕获一个来自子孙组件的错误时被调用,有三个参数:错误对象、发生错误的组件实例、一个包含错误来源信息的字符串;此钩子会返回false来阻止改错误继续向上传播
举例
<script>
import { onMounted } from 'vue';
export default {
setup(){
//立即执行函数
(function() {
console.log("立即执行")
})();
function hello(){
console.log("hello")
}
onMounted(()=>{
console.log("生命周期")
})
hello()
return{
hello
}
}
}
</script>
输出顺序:
因此setup内部定义的方法是在onmonuted之前执行的
立即执行函数:
立即执行函数(Immediately Invoked Function Expression,IIFE立即执行函数(Immediately Invoked Function Expression,IIFE)是一种在定义时立即执行的JavaScript函数。它使用匿名函数表达式(Function Expression)来封装一些代码,并且这段代码会在定义后立即执行。
IIFE的基本语法如下:
(function() {
// 在这里编写需要执行的代码
})();
或者可以使用箭头函数语法:
(() => {
// 在这里编写需要执行的代码
})();
IIFE的主要作用是创建一个新的作用域,避免变量污染全局作用域。它可以访问外部作用域中的变量,但无法修改它们。这使得IIFE非常适合用于模块化和封装JavaScript代码。
provide
vue3中的provide/inject(提供注入)
有了provide/inject不用一级一级传递,只要是父组件提供了某个数据,隔代组件就能直接获取都数据,从而很方便。
provide为后代提供数据
注意
在 3.x , provide 需要导入并在 setup 里启用,并且现在是一个全新的方法。
每次要 provide 一个数据的时候,就要单独调用一次。
每次调用的时候,都需要传入 2 个参数:
参数 | 类型 | 说明 |
key | string | 数据的名称 |
value | any | 数据的值 |
// 记得导入provide
import { defineComponent, provide } from 'vue'
export default defineComponent({
// ...
setup () {
// 定义好数据
const msg: string = 'Hello World!';
// provide出去
provide('msg', msg);
}
})
inject的注入
注意
在 3.x, inject 和 provide 一样,也是需要先导入然后在 setup 里启用,也是一个全新的方法。
每次要 inject 一个数据的时候,就要单独调用一次。
每次调用的时候,只需要传入 1 个参数:
参数 | 类型 | 说明 |
key | string | 与provide对应的数据名称 |
参数是注入名,也就是key
// 记得导入inject
import { defineComponent, inject } from 'vue'
export default defineComponent({
// ...
setup () {
const msg: string = inject('msg') || '';
}
})
如果提供的值是一个 ref,注入进来的会是该 ref 对象,不会自动解包为其内部的值,具有响应式
例子
子组件home用inject接收
<template>
<h3>
{{ homemessage }}
</h3>
</template>
<script>
import { inject } from 'vue';
export default {
setup(){
const homemessage=inject("message")
console.log(homemessage)
return{
homemessage
}
}
}
</script>
<style>
</style>
父组件app用provide传递
<template>
<home></home>
</template>
<script>
import { ref,provide } from 'vue';
import home from "./home.vue"
export default {
components:{
home
},
setup(){
const mess = ref("hellomessage")
provide("message",mess)
return{
mess
}
}
}
</script>
<style>
</style>
注意
一般情况下,传递给后代的数据不应该被后代组件改变,后代组件只能获取数据,不能改变数据
setup语法糖
如何使用 setup script 语法糖
需要启用 <script setup> 语法糖,需要在 <script> 代码块加上 setup 属性
也就是说 : 只需在 script 标签上写上 setup 就可以了
<script setup>
console.log('hello script setup')
</script>
里面的代码会被编译成组件 setup() 函数当中的内容
<script setup> 和 <script> 的执行时机是不同的:
普通的 <script> 只会在组件第一次被引入的时候执行一次
而 <script setup> 中的代码会在每次组件实例被创建的时候执行
好处:
1.不需要return返回了
当使用 <script setup> 的时候,任何在 <script setup> 声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板中直接使用
2、响应式
ref响应式数据和从 setup() 函数中返回值一样,值在模板中使用的时候会自动解包,不需要用xxx.value取值。
<template>
<button @click="add">{{ count }}</button>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
const add=()=>{
count.value++
}
</script>
<style>
</style>
3、自动注册
我们引入组件之后,就不需要在components选项中注册它了,直接就能在模板中使用了。被引入时的变量名直接作为自定义组件的标签名使用。当然了,引入方法,变量也是一样的,直接就能在template里用了。
<template>
<subassembly @getChili="getChili" :title="msg" />
</template>
<script setup>
import {ref} from 'vue'
//这里我们引入了子组件 subassembly
import subassembly from './subassembly.vue'
</script>
组件通信
注意:defineProps,defineEmits,defineExpose这三个api都是可以直接在 <script setup>里使用的,不需要引入。
defineProps :代替props,接收父组件传递的数据(父组件向子组件传参)
父组件
<template>
<div>我是父组件----1</div>
<chil @getChili="getChili" :title="msg" />
</template>
<script setup>
import {ref} from 'vue'
import chil from "./chil.vue"
//把值传递给子组件 ---> :title="msg" <Home @getChili="getChili" :title="msg" />
const msg = ref('父的值')
</script>
子组件
<template>
<div>我是子组件----2</div>
<div style="color: red">{{props.title}}</div>
</template>
<script setup>
import {defineProps} from 'vue'
//接收父组件 传过来的值!
const props = defineProps({
title: {
type: String
}
});
//打印一下 接收父组件的值
console.log(props.title) //父的值
</script>
defineEmit 代替emit,子组件向父组件传递数据(子组件向外暴露数据)
父组件
<template>
<div>我是父组件----1</div>
<div>{{data}}</div>
<chil @getChili="getChili" :title="msg" />
</template>
<script setup>
import {ref} from 'vue'
import chil from "./chil.vue"
//空值接收 子组件的传值
let data = ref(null)
const getChili = (e) => {
data.value = e
console.log(e) //子组件的值
}
</script>
子组件
<template>
<hr>
<div>我是子组件----2</div>
<button @click="toEmits">点击传到父组件</button>
</template>
<script setup>
import {defineEmits,ref} from 'vue'
//先定义一下子 在发送值
const emits = defineEmits(['getChili']);
const toEmits = () => {
emits('getChili','子的值')
}
</script>
defineExpose :子组件暴露自身数据,(父组件获取子组件属性)
在标准组件写法里,子组件的数据都是默认隐式暴露给父组件的,但在script-setup模式下,所有数据只是默认return给template 使用,不会暴露到组件外,所以父组件是无法直接通过挂载ref 变量获取子组件的数据。
如果要调用子组件的数据,需要先在子组件显示的暴露出来,才能够正确的拿到,这个操作,就是由defineExpose来完成。
defineExpose是vue3新增的一个api,放在<scipt setup>下使用的,目的是把属性和方法暴露出去,可以用于父子组件通信,子组件把属性暴露出去, 父组件用ref获取子组件DOM,子组件暴露的方法或属性可以用dom获取。
父组件
父组件用ref获取子组件dom拿到暴露的属性
shield.value.xiaoZhi拿到子组件暴露的属性
<template>
<button @click="shiEmots">获取暴露</button>
<chil ref="shield"/>
</template>
<script setup>
import chil from "./chil.vue"
import {defineEmits,defineProps,ref} from 'vue'
const shield = ref()
const shiEmots = () =>{
//子组件接收暴露出来得值
console.log('接收reactive暴漏出来的值',shield.value.xiaoZhi)
console.log('接收ref暴漏出来的值',shield.value.xiaoXiaoZhi)
}
</script>
子组件
子组件使用defineExpose把那个变量暴露出去
<template>
<div>我是子组件....{{ xiaoZhi.stator }}</div>
</template>
<script setup>
import {ref, defineExpose, reactive} from 'vue'
let xiaoZhi = reactive({
stator: '小志',
age: 27
})
let xiaoXiaoZhi = ref('小小志');
console.log(xiaoXiaoZhi)
defineExpose({
xiaoZhi,
xiaoXiaoZhi
})
</script>
这里的ref是Vue.js中的一个函数,用于创建一个响应式的引用。在这个例子中,shield是一个响应式的引用,它指向了子组件chil的实例。当子组件的属性发生变化时,shield的值也会相应地更新。
在模板中,通过ref="shield"将shield与子组件关联起来。这样,在shiEmots方法中,可以通过shield.value访问到子组件的属性和方法。