全局API
createApp
返回一個(gè)提供應(yīng)用上下文的應(yīng)用實(shí)例。應(yīng)用實(shí)例掛載的整個(gè)組件樹共享同一個(gè)上下文。
const app = createApp(Component);
app.mount('#root');
defineComponent
創(chuàng)建組件
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
let counter = ref(0);
const increment = () => {
counter.value += 1;
}
return {
counter,
increment
}
},
render() {
const {counter, increment} = this;
return (
<div>
<p>Counter: {counter}</p>
<button onClick={increment}>+</button>
</div>
);
},
});
或者是一個(gè) setup 函數(shù),函數(shù)名稱將作為組件名稱來使用
import { defineComponent, ref } from 'vue';
const Parent = defineComponent(function Parent() {
let age = ref(10);
const incrementAge = () => {
age.value += 1;
}
return {
age,
incrementAge
}
})
console.log('Parent', Parent)
// {
// name: "Parent2"
// setup: ? Parent2()
// }
defineAsyncComponent
創(chuàng)建一個(gè)異步加載組件
// 全局注冊
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
app.component('async-component', AsyncComp)
// 局部注冊
import {createApp, defineAsyncComponent } from 'vue'
createApp({
components: {
AsyncComponent: defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
}
})
// 高階組件
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent({
// 工廠函數(shù)
loader: () => import('./Foo.vue')
// 加載異步組件時(shí)要使用的組件
loadingComponent: LoadingComponent,
// 加載失敗時(shí)要使用的組件
errorComponent: ErrorComponent,
// 在顯示 loadingComponent 之前的延遲 | 默認(rèn)值:200(單位 ms)
delay: 200,
// 如果提供了 timeout ,并且加載組件的時(shí)間超過了設(shè)定值,將顯示錯(cuò)誤組件
// 默認(rèn)值:Infinity(即永不超時(shí),單位 ms)
timeout: 3000,
// 定義組件是否可掛起 | 默認(rèn)值:true
suspensible: false,
/**
*
* @param {*} error 錯(cuò)誤信息對象
* @param {*} retry 一個(gè)函數(shù),用于指示當(dāng) promise 加載器 reject 時(shí),加載器是否應(yīng)該重試
* @param {*} fail 一個(gè)函數(shù),指示加載程序結(jié)束退出
* @param {*} attempts 允許的最大重試次數(shù)
*/
onError(error, retry, fail, attempts) {
if (error.message.match(/fetch/) && attempts <= 3) {
// 請求發(fā)生錯(cuò)誤時(shí)重試,最多可嘗試 3 次
retry()
} else {
// 注意,retry/fail 就像 promise 的 resolve/reject 一樣:
// 必須調(diào)用其中一個(gè)才能繼續(xù)錯(cuò)誤處理。
fail()
}
}
})
resolveComponent
在當(dāng)前應(yīng)用中查找組件, 只能在 render 或 setup 函數(shù)中使用。
import { createApp, defineComponent, resolveComponent} from 'vue'
const app = createApp({});
app.component('ResolveComponent', {
render(){
return (<h1>This is a ResolveComponent</h1>)
}
})
app.mount('#root');
defineComponent({
render() {
// return component or componentName;
const ResolveComponent = resolveComponent('ResolveComponent');
return (
<div>
<ResolveComponent />
</div>
)
}
})
resolveDynamicComponent
查找組件
import {defineComponent, resolveDynamicComponent} from 'vue'
defineComponent({
setup() {
const isShow = ref(false);
return {
isShow
}
},
render() {
// return component or componentName;
const ResDynamicComponent = resolveDynamicComponent({
render() {
return (
<div>
<h1>This is a ResolveDynamicComponent</h1>
</div>
)
}
})
return (
<div>
{
isShow ? <ResDynamicComponent /> : ''
}
</div>
)
}
})
resolveDirective
在當(dāng)前應(yīng)用中查找指令, 只能在 render 或 setup 函數(shù)中使用。
import { createApp, defineComponent, resolveDirective} from 'vue'
const app = createApp({})
app.directive('highlight', {})
defineComponent({
setup() {
// return Directive or undefined;
const directive = resolveDirective('highlight');
}
})
withDirectives
defineComponent({
render() {
const focus = resolveDirective('focus')
return withDirectives(<input type="text" v-focus />, [[focus]])
}
})
createRenderer
nextTick
將回調(diào)推遲到下一個(gè) DOM 更新周期之后執(zhí)行。在更改了一些數(shù)據(jù)以等待 DOM 更新后立即使用它。
mergeProps
const props = mergeProps({
class: 'active'
}, this.$attrs)
4) 比較Vue2與Vue3的響應(yīng)式(重要)
vue2的響應(yīng)式
- 核心:
- 對象: 通過defineProperty對對象的已有屬性值的讀取和修改進(jìn)行劫持(監(jiān)視/攔截)
- 數(shù)組: 通過重寫數(shù)組更新數(shù)組一系列更新元素的方法來實(shí)現(xiàn)元素修改的劫持
Object.defineProperty(data, 'count', {
get () {},
set () {}
})
- 問題
- 對象直接新添加的屬性或刪除已有屬性, 界面不會自動更新
- 直接通過下標(biāo)替換元素或更新length, 界面不會自動更新 arr[1] = {}
Vue3的響應(yīng)式
- 核心:
- 通過Proxy(代理): 攔截對data任意屬性的任意(13種)操作, 包括屬性值的讀寫, 屬性的添加, 屬性的刪除等...
- 通過 Reflect(反射): 動態(tài)對被代理對象的相應(yīng)屬性進(jìn)行特定的操作
- 文檔:
new Proxy(data, {
// 攔截讀取屬性值
get (target, prop) {
return Reflect.get(target, prop)
},
// 攔截設(shè)置屬性值或添加新屬性
set (target, prop, value) {
return Reflect.set(target, prop, value)
},
// 攔截刪除屬性
deleteProperty (target, prop) {
return Reflect.deleteProperty(target, prop)
}
})
proxy.name = 'tom'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Proxy 與 Reflect</title>
</head>
<body>
<script>
const user = {
name: "John",
age: 12
};
/*
proxyUser是代理對象, user是被代理對象
后面所有的操作都是通過代理對象來操作被代理對象內(nèi)部屬性
*/
const proxyUser = new Proxy(user, {
get(target, prop) {
console.log('劫持get()', prop)
return Reflect.get(target, prop)
},
set(target, prop, val) {
console.log('劫持set()', prop, val)
return Reflect.set(target, prop, val); // (2)
},
deleteProperty (target, prop) {
console.log('劫持delete屬性', prop)
return Reflect.deleteProperty(target, prop)
}
});
// 讀取屬性值
console.log(proxyUser===user)
console.log(proxyUser.name, proxyUser.age)
// 設(shè)置屬性值
proxyUser.name = 'bob'
proxyUser.age = 13
console.log(user)
// 添加屬性
proxyUser.sex = '男'
console.log(user)
// 刪除屬性
delete proxyUser.sex
console.log(user)
</script>
</body>
</html>
5) setup細(xì)節(jié)
-
setup執(zhí)行的時(shí)機(jī)
- 在beforeCreate之前執(zhí)行(一次), 此時(shí)組件對象還沒有創(chuàng)建
- this是undefined, 不能通過this來訪問data/computed/methods / props
- 其實(shí)所有的composition API相關(guān)回調(diào)函數(shù)中也都不可以
-
setup的返回值
- 一般都返回一個(gè)對象: 為模板提供數(shù)據(jù), 也就是模板中可以直接使用此對象中的所有屬性/方法
- 返回對象中的屬性會與data函數(shù)返回對象的屬性合并成為組件對象的屬性
- 返回對象中的方法會與methods中的方法合并成功組件對象的方法
- 如果有重名, setup優(yōu)先
- 注意:
- 一般不要混合使用: methods中可以訪問setup提供的屬性和方法, 但在setup方法中不能訪問data和methods
- setup不能是一個(gè)async函數(shù): 因?yàn)榉祷刂挡辉偈莚eturn的對象, 而是promise, 模板看不到return對象中的屬性數(shù)據(jù)
-
setup的參數(shù)
- setup(props, context) / setup(props, {attrs, slots, emit})
- props: 包含props配置聲明且傳入了的所有屬性的對象
- attrs: 包含沒有在props配置中聲明的屬性的對象, 相當(dāng)于 this.$attrs
- slots: 包含所有傳入的插槽內(nèi)容的對象, 相當(dāng)于 this.$slots
- emit: 用來分發(fā)自定義事件的函數(shù), 相當(dāng)于 this.$emit
<template>
<h2>App</h2>
<p>msg: {{msg}}</p>
<button @click="fn('--')">更新</button>
<child :msg="msg" msg2="cba" @fn="fn"/>
</template>
<script lang="ts">
import {
reactive,
ref,
} from 'vue'
import child from './child.vue'
export default {
components: {
child
},
setup () {
const msg = ref('abc')
function fn (content: string) {
msg.value += content
}
return {
msg,
fn
}
}
}
</script>
<template>
<div>
<h3>{{n}}</h3>
<h3>{{m}}</h3>
<h3>msg: {{msg}}</h3>
<h3>msg2: {{$attrs.msg2}}</h3>
<slot name="xxx"></slot>
<button @click="update">更新</button>
</div>
</template>
<script lang="ts">
import {
ref,
defineComponent
} from 'vue'
export default defineComponent({
name: 'child',
props: ['msg'],
emits: ['fn'], // 可選的, 聲明了更利于程序員閱讀, 且可以對分發(fā)的事件數(shù)據(jù)進(jìn)行校驗(yàn)
data () {
console.log('data', this)
return {
// n: 1
}
},
beforeCreate () {
console.log('beforeCreate', this)
},
methods: {
// update () {
// this.n++
// this.m++
// }
},
// setup (props, context) {
setup (props, {attrs, emit, slots}) {
console.log('setup', this)
console.log(props.msg, attrs.msg2, slots, emit)
const m = ref(2)
const n = ref(3)
function update () {
// console.log('--', this)
// this.n += 2
// this.m += 2
m.value += 2
n.value += 2
// 分發(fā)自定義事件
emit('fn', '++')
}
return {
m,
n,
update,
}
},
})
</script>
6) reactive與ref-細(xì)節(jié)
- 是Vue3的 composition API中2個(gè)最重要的響應(yīng)式API
- ref用來處理基本類型數(shù)據(jù), reactive用來處理對象(遞歸深度響應(yīng)式)
- 如果用ref對象/數(shù)組, 內(nèi)部會自動將對象/數(shù)組轉(zhuǎn)換為reactive的代理對象
- ref內(nèi)部: 通過給value屬性添加getter/setter來實(shí)現(xiàn)對數(shù)據(jù)的劫持
- reactive內(nèi)部: 通過使用Proxy來實(shí)現(xiàn)對對象內(nèi)部所有數(shù)據(jù)的劫持, 并通過Reflect操作對象內(nèi)部數(shù)據(jù)
- ref的數(shù)據(jù)操作: 在js中要.value, 在模板中不需要(內(nèi)部解析模板時(shí)會自動添加.value)
<template>
<h2>App</h2>
<p>m1: {{m1}}</p>
<p>m2: {{m2}}</p>
<p>m3: {{m3}}</p>
<button @click="update">更新</button>
</template>
<script lang="ts">
import {
reactive,
ref
} from 'vue'
export default {
setup () {
const m1 = ref('abc')
const m2 = reactive({x: 1, y: {z: 'abc'}})
// 使用ref處理對象 ==> 對象會被自動reactive為proxy對象
const m3 = ref({a1: 2, a2: {a3: 'abc'}})
console.log(m1, m2, m3)
console.log(m3.value.a2) // 也是一個(gè)proxy對象
function update() {
m1.value += '--'
m2.x += 1
m2.y.z += '++'
m3.value = {a1: 3, a2: {a3: 'abc---'}}
m3.value.a2.a3 += '==' // reactive對對象進(jìn)行了深度數(shù)據(jù)劫持
console.log(m3.value.a2)
}
return {
m1,
m2,
m3,
update
}
}
}
</script>
7) 計(jì)算屬性與監(jiān)視
-
computed函數(shù):
- 與computed配置功能一致
- 只有g(shù)etter
- 有g(shù)etter和setter
-
watch函數(shù)
- 與watch配置功能一致
- 監(jiān)視指定的一個(gè)或多個(gè)響應(yīng)式數(shù)據(jù), 一旦數(shù)據(jù)變化, 就自動執(zhí)行監(jiān)視回調(diào)
- 默認(rèn)初始時(shí)不執(zhí)行回調(diào), 但可以通過配置immediate為true, 來指定初始時(shí)立即執(zhí)行第一次
- 通過配置deep為true, 來指定深度監(jiān)視
-
watchEffect函數(shù)
- 不用直接指定要監(jiān)視的數(shù)據(jù), 回調(diào)函數(shù)中使用的哪些響應(yīng)式數(shù)據(jù)就監(jiān)視哪些響應(yīng)式數(shù)據(jù)
- 默認(rèn)初始時(shí)就會執(zhí)行第一次, 從而可以收集需要監(jiān)視的數(shù)據(jù)
- 監(jiān)視數(shù)據(jù)發(fā)生變化時(shí)回調(diào)
<template>
<h2>App</h2>
fistName: <input v-model="user.firstName"/><br>
lastName: <input v-model="user.lastName"/><br>
fullName1: <input v-model="fullName1"/><br>
fullName2: <input v-model="fullName2"><br>
fullName3: <input v-model="fullName3"><br>
</template>
<script lang="ts">
/*
計(jì)算屬性與監(jiān)視
1\. computed函數(shù):
與computed配置功能一致
只有g(shù)etter
有g(shù)etter和setter
2\. watch函數(shù)
與watch配置功能一致
監(jiān)視指定的一個(gè)或多個(gè)響應(yīng)式數(shù)據(jù), 一旦數(shù)據(jù)變化, 就自動執(zhí)行監(jiān)視回調(diào)
默認(rèn)初始時(shí)不執(zhí)行回調(diào), 但可以通過配置immediate為true, 來指定初始時(shí)立即執(zhí)行第一次
通過配置deep為true, 來指定深度監(jiān)視
3\. watchEffect函數(shù)
不用直接指定要監(jiān)視的數(shù)據(jù), 回調(diào)函數(shù)中使用的哪些響應(yīng)式數(shù)據(jù)就監(jiān)視哪些響應(yīng)式數(shù)據(jù)
默認(rèn)初始時(shí)就會執(zhí)行第一次, 從而可以收集需要監(jiān)視的數(shù)據(jù)
監(jiān)視數(shù)據(jù)發(fā)生變化時(shí)回調(diào)
*/
import {
reactive,
ref,
computed,
watch,
watchEffect
} from 'vue'
export default {
setup () {
const user = reactive({
firstName: 'A',
lastName: 'B'
})
// 只有g(shù)etter的計(jì)算屬性
const fullName1 = computed(() => {
console.log('fullName1')
return user.firstName + '-' + user.lastName
})
// 有g(shù)etter與setter的計(jì)算屬性
const fullName2 = computed({
get () {
console.log('fullName2 get')
return user.firstName + '-' + user.lastName
},
set (value: string) {
console.log('fullName2 set')
const names = value.split('-')
user.firstName = names[0]
user.lastName = names[1]
}
})
const fullName3 = ref('')
/*
watchEffect: 監(jiān)視所有回調(diào)中使用的數(shù)據(jù)
*/
/*
watchEffect(() => {
console.log('watchEffect')
fullName3.value = user.firstName + '-' + user.lastName
})
*/
/*
使用watch的2個(gè)特性:
深度監(jiān)視
初始化立即執(zhí)行
*/
watch(user, () => {
fullName3.value = user.firstName + '-' + user.lastName
}, {
immediate: true, // 是否初始化立即執(zhí)行一次, 默認(rèn)是false
deep: true, // 是否是深度監(jiān)視, 默認(rèn)是false
})
/*
watch一個(gè)數(shù)據(jù)
默認(rèn)在數(shù)據(jù)發(fā)生改變時(shí)執(zhí)行回調(diào)
*/
watch(fullName3, (value) => {
console.log('watch')
const names = value.split('-')
user.firstName = names[0]
user.lastName = names[1]
})
/*
watch多個(gè)數(shù)據(jù):
使用數(shù)組來指定
如果是ref對象, 直接指定
如果是reactive對象中的屬性, 必須通過函數(shù)來指定
*/
watch([() => user.firstName, () => user.lastName, fullName3], (values) => {
console.log('監(jiān)視多個(gè)數(shù)據(jù)', values)
})
return {
user,
fullName1,
fullName2,
fullName3
}
}
}
</script>
8) 生命周期
vue2.x的生命周期

vue3的生命周期

與 2.x 版本生命周期相對應(yīng)的組合式 API
-
beforeCreate-> 使用setup() -
created-> 使用setup() -
beforeMount->onBeforeMount -
mounted->onMounted -
beforeUpdate->onBeforeUpdate -
updated->onUpdated -
beforeDestroy->onBeforeUnmount -
destroyed->onUnmounted -
errorCaptured->onErrorCaptured
新增的鉤子函數(shù)
組合式 API 還提供了以下調(diào)試鉤子函數(shù):
- onRenderTracked
- onRenderTriggered
<template>
<div class="about">
<h2>msg: {{msg}}</h2>
<hr>
<button @click="update">更新</button>
</div>
</template>
<script lang="ts">
import {
ref,
onMounted,
onUpdated,
onUnmounted,
onBeforeMount,
onBeforeUpdate,
onBeforeUnmount
} from "vue"
export default {
beforeCreate () {
console.log('beforeCreate()')
},
created () {
console.log('created')
},
beforeMount () {
console.log('beforeMount')
},
mounted () {
console.log('mounted')
},
beforeUpdate () {
console.log('beforeUpdate')
},
updated () {
console.log('updated')
},
beforeUnmount () {
console.log('beforeUnmount')
},
unmounted () {
console.log('unmounted')
},
setup() {
const msg = ref('abc')
const update = () => {
msg.value += '--'
}
onBeforeMount(() => {
console.log('--onBeforeMount')
})
onMounted(() => {
console.log('--onMounted')
})
onBeforeUpdate(() => {
console.log('--onBeforeUpdate')
})
onUpdated(() => {
console.log('--onUpdated')
})
onBeforeUnmount(() => {
console.log('--onBeforeUnmount')
})
onUnmounted(() => {
console.log('--onUnmounted')
})
return {
msg,
update
}
}
}
</script>
<template>
<h2>App</h2>
<button @click="isShow=!isShow">切換</button>
<hr>
<Child v-if="isShow"/>
</template>
<script lang="ts">
import Child from './Child.vue'
export default {
data () {
return {
isShow: true
}
},
components: {
Child
}
}
</script>
09) 自定義hook函數(shù)
使用Vue3的組合API封裝的可復(fù)用的功能函數(shù)
自定義hook的作用類似于vue2中的mixin技術(shù)
自定義Hook的優(yōu)勢: 很清楚復(fù)用功能代碼的來源, 更清楚易懂
-
需求1: 收集用戶鼠標(biāo)點(diǎn)擊的頁面坐標(biāo)
hooks/useMousePosition.ts
import { ref, onMounted, onUnmounted } from 'vue'
/*
收集用戶鼠標(biāo)點(diǎn)擊的頁面坐標(biāo)
*/
export default function useMousePosition () {
// 初始化坐標(biāo)數(shù)據(jù)
const x = ref(-1)
const y = ref(-1)
// 用于收集點(diǎn)擊事件坐標(biāo)的函數(shù)
const updatePosition = (e: MouseEvent) => {
x.value = e.pageX
y.value = e.pageY
}
// 掛載后綁定點(diǎn)擊監(jiān)聽
onMounted(() => {
document.addEventListener('click', updatePosition)
})
// 卸載前解綁點(diǎn)擊監(jiān)聽
onUnmounted(() => {
document.removeEventListener('click', updatePosition)
})
return {x, y}
}
<template>
<div>
<h2>x: {{x}}, y: {{y}}</h2>
</div>
</template>
<script>
import {
ref
} from "vue"
/*
在組件中引入并使用自定義hook
自定義hook的作用類似于vue2中的mixin技術(shù)
自定義Hook的優(yōu)勢: 很清楚復(fù)用功能代碼的來源, 更清楚易懂
*/
import useMousePosition from './hooks/useMousePosition'
export default {
setup() {
const {x, y} = useMousePosition()
return {
x,
y,
}
}
}
</script>
利用TS泛型強(qiáng)化類型檢查
-
需求2: 封裝發(fā)ajax請求的hook函數(shù)
hooks/useRequest.ts
import { ref } from 'vue'
import axios from 'axios'
/*
使用axios發(fā)送異步ajax請求
*/
export default function useUrlLoader<T>(url: string) {
const result = ref<T | null>(null)
const loading = ref(true)
const errorMsg = ref(null)
axios.get(url)
.then(response => {
loading.value = false
result.value = response.data
})
.catch(e => {
loading.value = false
errorMsg.value = e.message || '未知錯(cuò)誤'
})
return {
loading,
result,
errorMsg,
}
}
<template>
<div class="about">
<h2 v-if="loading">LOADING...</h2>
<h2 v-else-if="errorMsg">{{errorMsg}}</h2>
<!-- <ul v-else>
<li>id: {{result.id}}</li>
<li>name: {{result.name}}</li>
<li>distance: {{result.distance}}</li>
</ul> -->
<ul v-for="p in result" :key="p.id">
<li>id: {{p.id}}</li>
<li>title: {{p.title}}</li>
<li>price: {{p.price}}</li>
</ul>
<!-- <img v-if="result" :src="result[0].url" alt=""> -->
</div>
</template>
<script lang="ts">
import {
watch
} from "vue"
import useRequest from './hooks/useRequest'
// 地址數(shù)據(jù)接口
interface AddressResult {
id: number;
name: string;
distance: string;
}
// 產(chǎn)品數(shù)據(jù)接口
interface ProductResult {
id: string;
title: string;
price: number;
}
export default {
setup() {
// const {loading, result, errorMsg} = useRequest<AddressResult>('/data/address.json')
const {loading, result, errorMsg} = useRequest<ProductResult[]>('/data/products.json')
watch(result, () => {
if (result.value) {
console.log(result.value.length) // 有提示
}
})
return {
loading,
result,
errorMsg
}
}
}
</script>
10) toRefs
把一個(gè)響應(yīng)式對象轉(zhuǎn)換成普通對象,該普通對象的每個(gè) property 都是一個(gè) ref
應(yīng)用: 當(dāng)從合成函數(shù)返回響應(yīng)式對象時(shí),toRefs 非常有用,這樣消費(fèi)組件就可以在不丟失響應(yīng)式的情況下對返回的對象進(jìn)行分解使用
問題: reactive 對象取出的所有屬性值都是非響應(yīng)式的
解決: 利用 toRefs 可以將一個(gè)響應(yīng)式 reactive 對象的所有原始屬性轉(zhuǎn)換為響應(yīng)式的 ref 屬性
<template>
<h2>App</h2>
<h3>foo: {{foo}}</h3>
<h3>bar: {{bar}}</h3>
<h3>foo2: {{foo2}}</h3>
<h3>bar2: {{bar2}}</h3>
</template>
<script lang="ts">
import { reactive, toRefs } from 'vue'
/*
toRefs:
將響應(yīng)式對象中所有屬性包裝為ref對象, 并返回包含這些ref對象的普通對象
應(yīng)用: 當(dāng)從合成函數(shù)返回響應(yīng)式對象時(shí),toRefs 非常有用,
這樣消費(fèi)組件就可以在不丟失響應(yīng)式的情況下對返回的對象進(jìn)行分解使用
*/
export default {
setup () {
const state = reactive({
foo: 'a',
bar: 'b',
})
const stateAsRefs = toRefs(state)
setTimeout(() => {
state.foo += '++'
state.bar += '++'
}, 2000);
const {foo2, bar2} = useReatureX()
return {
// ...state,
...stateAsRefs,
foo2,
bar2
}
},
}
function useReatureX() {
const state = reactive({
foo2: 'a',
bar2: 'b',
})
setTimeout(() => {
state.foo2 += '++'
state.bar2 += '++'
}, 2000);
return toRefs(state)
}
</script>
11) ref獲取元素
利用ref函數(shù)獲取組件中的標(biāo)簽元素
功能需求: 讓輸入框自動獲取焦點(diǎn)
<template>
<h2>App</h2>
<input type="text">---
<input type="text" ref="inputRef">
</template>
<script lang="ts">
import { onMounted, ref } from 'vue'
/*
ref獲取元素: 利用ref函數(shù)獲取組件中的標(biāo)簽元素
功能需求: 讓輸入框自動獲取焦點(diǎn)
*/
export default {
setup() {
const inputRef = ref<HTMLElement|null>(null)
onMounted(() => {
inputRef.value && inputRef.value.focus()
})
return {
inputRef
}
},
}
</script>