和Vue2使用的optionsAPI(例如: 数据放 data 中, 方法放 methods中)不同的是, Vue3是用了composition API, 提升了代码的可读性和可维护性, 同时也保留了Vue2的optionsAPI.
<template>
<div>当前点击次数:{{ count }}</div>
<button @click="add">点击</button>
</template>
<script lang="ts">
import { defineComponent, reactive, ref } from 'vue'
export default defineComponent({
setup() {
const count = ref(0)
const add = () => {
count.value++
}
return {
count,
add,
}
},
})
</script>
setup
返回。但是defineComponent和setup这种写法有点累赘, 所以现在官方推荐使用setup模板。 script setup是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。相比于普通的 script 语法更加简洁
<template>
<div>当前点击次数:{{ count }}</div>
<button @click="add">点击</button>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
const add = () => {
count.value++
}
</script>
script setup 优势:
ts
项目不需要再 defineComponent
包裹了。return
了, template
可直接使用,顶层的绑定会自动暴露给模板。在Vue3中 computed为函数, 写法有两种, 且可以使用多次
<template>
<div>原本的值 <input type="text" v-model.number="num" /></div>
<div>改变后的值 {{ nextNum }}</div>
<div>相互影响的值 <input type="text" v-model.number="revNum" /></div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
const num= ref(10)
// 不带set的计算属性
const nextNum = computed(() => {
return num.value + 1
})
// 带set的计算属性
const revNum= computed({
get() {
return num.value + 2
},
set(val: number) {
num.value = val - 2
},
})
</script>
watch 侦听器, 接收三个参数
// 监听单个ref
const num = ref(100)
watch(num, (value, oldValue) => {
console.log(value)
})
// 监听多个ref
const num1 = ref(100)
const num2 = ref(0)
watch([num1, num2], (value) => {
console.log(value)
})
// 监听ref复杂数据
const user = ref({
name: 'name',
age: 18,
})
watch(
user,
(value) => {
console.log('user变化了', value)
},
{
// 深度监听,当ref的值是一个复杂数据类型,需要深度监听
// 但是如果是以reactive创建的复杂类型数据,则不需要
deep: true,
immediate: true
}
)
父传子 (script setup中子组件引入后可以使用)
父组件中给子组件传值与Vue2相同故省略, 主要不同在子组件获取父组件的值, 不再使用props, 而需要使用defineProps
// 父组件给子组件传入两个值
<script setup lang="ts">
import { computed } from 'vue'
// 规定传递数据的类型
interface Props {
age: number
name: string
}
// defineProps: 接收父组件传递的数据
const props = defineProps<Props>()
// 使用
const addAge = computed(() => {
return props.age ++
})
</script>
<template>
<h3>子组件---{{ addAge }} --- {{ name }}</h3>
</template>
子传父
defineEmits
获取emit对象(因为没有this)// 子组件
const rValue = ref('give back')
// 定义回传的方法 defineEmits
const emit = defineEmits(['giveBack'])
const giveBack = () => {
emit('giveBack', rValue)
}
跨层级通讯-依赖注入 - provide 和 inject
//父组件
import { provide, ref } from 'vue'
const num = ref(100)
// provide提供给子组件 key和value不需要相同
provide('num', num)
<script setup lang="ts">
import { inject, Ref } from 'vue'
// inject来插入来自父组件的值
const getNum = inject<Ref<number>>('num')
const changeNum = (m: number) => {
getNum && getNum.value ++
}
</script>
<template>
<h5>子组件--{{ getNum }}</h5>
<button @click="changeNum">修改</button>
</template>
在标签中使用 ref="xxx"
来记录取的哪个元素
在script中,通过赋值来取得值,但是赋值的命名必须与标签中的命名一致
<div ref="divRef">通过Ref拿我</div>
<button @click="changeRefHTML>点我改变</button>
//script
const divRef = ref<HTMLDivElement | null>(null)
const changeRefHTML = () => {
if (divRef.value) {
divRef.value.innerHTML = '变了'
}
}
通过ref获取子组件的值/方法
//父组件中使用子组件
<Form ref="formRef" />
<button @click="changeSon">点我改变</button>
// 获取子组件
import Form from "./components/Form.vue"
// typeof获取类型 Instancetype 泛型类型
const formRef = ref<InstanceType<typeof Form> | null>(null)
const changeSon = () => {
if (refForm.value) {
// 子组件里面的方法/取值方法类似
refForm.value.refMethod()
}
}