在前面我们讲解过计算属性computed:当我们的某些属性是依赖其他状态时,我们可以使用计算属性来处理
在前面的Options API中,我们是使用computed选项来完成的;
在Composition API中,我们可以在 setup 函数中使用 computed 方法来编写一个计算属性;
如何使用computed呢?
方式一:接收一个getter函数,并为 getter 函数返回的值,返回一个不变的 ref 对象;
方式二:接收一个具有 get 和 set 的对象,返回一个可变的(可读写)ref 对象;
export default {
setup() {
// 1.定义数据
const names = reactive({
firstName: 'kobe',
lastName: 'bryant',
});
const fullname = computed({
set: function (newValue) {
const tempNames = newValue.split(' ');
names.firstName = tempNames[0];
names.lastName = tempNames[1];
},
get: function () {
return names.firstName + ' ' + names.lastName;
},
});
console.log(fullname);
function setFullname() {
fullname.value = 'coder why';
console.log(names);
}
// 2.定义score
const score = ref(89);
const scoreLevel = computed(() => {
return score.value >= 60 ? '及格' : '不及格';
});
return {
names,
fullname,
setFullname,
scoreLevel,
};
},
};
再setup中使用ref获取元素或者组件
只需要定义一个ref对象 绑定到元素或者组件的ref属性上即可
<template>
<h2 ref="titleRef">我是标题h2>
<button ref="btnRef">按钮button>
<show-info ref="showInfoRef">show-info>
<button @click="getElements">获取元素button>
template>
<script>
import { ref, onMounted } from 'vue'
import ShowInfo from './ShowInfo.vue'
export default {
components: {
ShowInfo
},
setup() {
const titleRef = ref()
const btnRef = ref()
const showInfoRef = ref()
// mounted的生命周期函数
onMounted(() => {
console.log(titleRef.value)
console.log(btnRef.value)
console.log(showInfoRef.value)
showInfoRef.value.showInfoFoo()
})
function getElements() {
console.log(titleRef.value)
}
return {
titleRef,
btnRef,
showInfoRef,
getElements
}
}
}
script>
setup可以用来替代data methods computed等等这些选项 也可以替代生命周期钩子
可以直接再setup中使用onX函数注册生命周期钩子
setup() {
// 在执行setup函数的过程中, 你需要注册别的生命周期函数
onMounted(() => {
console.log('onmounted');
});
onUpdated(() => {
console.log('onUpdated');
});
onUnmounted(() => {
console.log('onUnmounted');
});
},
Composition API也可以替代之前的Provide和Inject的选项
我们可以通过 provide来提供数据:
可以通过 provide 方法来定义每个 Property;
provide可以传入两个参数:
name:提供的属性名称;
value:提供的属性值;
为了增加 provide 值和 inject 值之间的响应性,我们可以在 provide 值时使用 ref 和 reactive。
setup() {
const name = ref("why")
provide("name", name)
provide("age", 18)
return {
name
}
}
在 后代组件 中可以通过 inject 来注入需要的属性和对应的值:
可以通过 inject 来注入需要的内容;
inject可以传入两个参数:
要 inject 的 property 的 name;
默认值;
setup() {
const name = inject("name")
const age = inject("age")
const height = inject("height", 1.88)
return {
name,
age,
height
}
}
在前面的Options API中,我们可以通过watch选项来侦听data或者props的数据变化,当数据变化时执行某一些操作。
在Composition API中,我们可以使用watchEffect和watch来完成响应式数据的侦听;
watchEffect:用于自动收集响应式数据的依赖;
watch:需要手动指定侦听的数据源;
watch的API完全等同于组件watch选项的Property:
watch需要侦听特定的数据源,并且执行其回调函数;
默认情况下它是惰性的,只有当被侦听的源发生变化时才会执行回调;
const name = ref('kobe')
watch(name, (newValue, oldValue) => {
console.log(newValue, oldValue);
})
const changeName = () => {
name.value = 'james'
}
侦听器可以使用数组同时侦听多个源
const name = ref('kobe')
const age = ref(18)
const changeName = () => {
name.value = 'james'
}
watch([name,age], (newValue, oldValue) => {
console.log(newValue, oldValue)
})
如果我们希望侦听一个深层的侦听,那么依然需要设置 deep 为true:
也可以传入 immediate 立即执行;
监听reactive数据变化后, 获取普通对象
const info = reactive({
name = 'kobe',
age = 18,
})
watch(() => ({ ...info }), (newValue, oldValue) => {
console.log(newValue, oldValue)
}, {
immediate: true,
deep: true
})
当侦听到某些响应式数据变化时,我们希望执行某些操作,这个时候可以使用 watchEffect。
我们来看一个案例:
首先,watchEffect传入的函数会被立即执行一次,并且在执行的过程中会收集依赖;
其次,只有收集的依赖发生变化时,watchEffect传入的函数才会再次执行;
const name = ref('kobe')
const age = ref(18)
watchEffect(() => {
console.log('watchEffect执行', name.vlaue, age.value)
})
如果在发生某些情况下,我们希望停止侦听,这个时候我们可以获取watchEffect的返回值函数,调用该函数即可。
const counter = ref(0)
const name = ref("why")
const stopWatch = watchEffect(() => {
console.log("-------", counter.value, name.value)
if (counter.value >= 10) {
stopWatch()
}
})
< script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖,当同时使用 SFC 与组合式 API 时则推荐该语法。
更少的样板内容,更简洁的代码;
能够使用纯 Typescript 声明 prop 和抛出事件;
更好的运行时性能 ;
更好的 IDE 类型推断性能 ;
这个语法需要将setup attribute添加到
<script setup>
console.log('hello world')
script >
里面的代码会被编译成组件 setup() 函数的内容:
这意味着与普通的
当使用 < script setup> 的时候,任何在
响应式数据需要通过ref、reactive来创建。
< script setup> 范围里的值也能被直接作为自定义组件的标签名使用:
为了在声明 props 和 emits 选项时获得完整的类型推断支持,我们可以使用 defineProps 和 defineEmits API,它们将自动
地在 < script setup> 中可用:
<template>
<div>ShowInfo: {{ name }}-{{ age }}div>
<button @click="showInfoBtnClick">showInfoButtonbutton>
template>
<script setup>
// 定义props
const props = defineProps({
name: {
type: String,
default: "默认值"
},
age: {
type: Number,
default: 0
}
})
// 绑定函数, 并且发出事件
const emits = defineEmits(["infoBtnClick"])
function showInfoBtnClick() {
emits("infoBtnClick", "showInfo内部发生了点击")
}
// 定义foo的函数
function foo() {
console.log("foo function")
}
defineExpose({
foo
})
script>
<style scoped>
style>
使用 < script setup> 的组件是默认关闭的:
通过模板 ref 或者 $parent 链获取到的组件的公开实例,不会暴露任何在 < script setup> 中声明的绑定;
通过 defineExpose 编译器宏来显式指定在
<template>
<div>AppContent: {{ message }}div>
<button @click="changeMessage">修改messagebutton>
<show-info name="kobe"
:age="18"
@info-btn-click="infoBtnClick"
ref="showInfoRef">
show-info>
<show-info>show-info>
<show-info>show-info>
template>
<script setup>
// 1.所有编写在顶层中的代码, 都是默认暴露给template可以使用
import { ref, onMounted } from 'vue'
import ShowInfo from './ShowInfo.vue'
// 2.定义响应式数据
const message = ref("Hello World")
console.log(message.value)
// 3.定义绑定的函数
function changeMessage() {
message.value = "你好啊"
}
function infoBtnClick(payload) {
console.log("监听到showInfo内部的点击:", payload)
}
// 4.获取组件实例
const showInfoRef = ref()
onMounted(() => {
showInfoRef.value.foo()
})
script>
<style scoped>
style>