vue3的setup還能這么用
一、前言
vue3文檔地址:
https://v3.cn.vuejs.org/
本文來說一說vue3的setup都能怎么用
借用官網(wǎng)一句話
setup 選項(xiàng)是一個(gè)接收 props 和 context 的函數(shù)
也就是說它的基本寫法應(yīng)該是這樣的
export default{
name: 'test',
setup(props,context){
return {} // 這里返回的任何內(nèi)容都可以用于組件的其余部分
}
// 組件的“其余部分”
}
接收一個(gè)props和context函數(shù)并且將setup內(nèi)的內(nèi)容通過return暴露給組件的其余部分。
二、setup注意點(diǎn)
由于在執(zhí)行 setup函數(shù)的時(shí)候,還沒有執(zhí)行 Created 生命周期方法,所以在 setup 函數(shù)中,無法使用 data 和 methods 的變量和方法
由于我們不能在 setup函數(shù)中使用 data 和 methods,所以 Vue 為了避免我們錯(cuò)誤的使用,直接將 setup函數(shù)中的this 修改成了 undefined
三、定義響應(yīng)式數(shù)據(jù)
ref reactive
vue3通過ref reactive來定義響應(yīng)式數(shù)據(jù)
ref我們用來將基本數(shù)據(jù)類型定義為響應(yīng)式數(shù)據(jù),其本質(zhì)是基于Object.defineProperty()重新定義屬性的方式來實(shí)現(xiàn)(ref更適合定義基本數(shù)據(jù)類型)
reactive用來將引用類型定義為響應(yīng)式數(shù)據(jù),其本質(zhì)是基于Proxy實(shí)現(xiàn)對(duì)象代理
基本數(shù)據(jù)類型(單類型):除Object。String、Number、boolean、null、undefined。
引用類型:object。里面包含的 function、Array、Date。
定義
<script>
import {ref, reactive} from "vue";
export default {
name: "test",
setup(){
// 基本類型
const nub = ref(0)
const str = ref('inline')
const boo = ref(false)
// 引用類型
const obj = reactive({
name:'inline',
age:'18'
})
const arr = reactive(['0','1','2'])
return{
nub,
str,
boo,
obj,
arr,
}
}
}
</script>
復(fù)制代碼
使用
<template>
<div>
<h1>基本類型</h1>
<p>nub:{{ nub }}</p>
<p>str:{{ str }}</p>
<p>boo:{{ boo }}</p>
</div>
<div>
<h1>引用類型</h1>
<p>obj:{{ obj.name }}</p>
<p>arr:{{ arr[1] }}</p>
</div>
</template>
復(fù)制代碼
四、toRefs
如果我們用reactive的形式來定義響應(yīng)式變量
setup(){
const obj = reactive({
name:'inline',
gender:'男',
age:'18'
})
return{
obj
}
}
復(fù)制代碼
使用
<div>
<p>姓名:{{ obj.name }}</p>
<p>性別:{{ obj.gender }}</p>
<p>年齡:{{ obj.age }}</p>
</div>
復(fù)制代碼
這樣我們是不是發(fā)現(xiàn)在模板內(nèi)使用參數(shù)很麻煩,那我們想直接用{{ name }}的方式訪問行不行,答案是可行的
這里我們使用es6的擴(kuò)展運(yùn)算符
setup(){
const obj = reactive({
name:'inline',
gender:'男',
age:'18',
})
return{
...obj,
}
}
復(fù)制代碼
使用
<div>
<p>姓名:{{ name }}</p>
<p>性別:{{ gender }}</p>
<p>年齡:{{ age }}</p>
</div>
<div>
<button @click="name = 'juejin'">改變姓名</button>
<button @click="gender = '女'">改變性別</button>
<button @click="age = '20'">改變年齡</button>
</div>
復(fù)制代碼
結(jié)果
這里看到我們的參數(shù)都正常的顯示到了頁面上,但是我們?nèi)ジ淖儏?shù)時(shí)發(fā)現(xiàn)視圖并沒有更新,這是為什么呢???我們把擴(kuò)展運(yùn)算符寫成它的等價(jià)格式
const obj = reactive({
name:'inline',
gender:'男',A
age:'18',
})
// ...obj ==> name:obj.name
復(fù)制代碼
哎哎哎,等下 我的鼠標(biāo)浮動(dòng)上去怎么提示我name只是一個(gè)字符串?
image.png
那我們?cè)诳纯次覀冇胷ef定義值時(shí)提示什么
image.png
奧奧,這個(gè)時(shí)候我們看到name是一個(gè)Ref<string>,是一個(gè)響應(yīng)式字符串。
這樣我們就找到了為什么沒有更新視圖的原因,當(dāng)我們用...擴(kuò)展運(yùn)算符時(shí)我們得到的只是一個(gè)普通類型的數(shù)值,并不是一個(gè)響應(yīng)式數(shù)據(jù)
為了解決這個(gè)問題呢,vue3給我們提供了toRefs函數(shù),來讓我們看看效果如何
setup(){
const obj = reactive({
name:'inline',
gender:'男',
age:'18',
})
return{
...toRefs(obj),
}
}
復(fù)制代碼
<div>
<p>姓名:{{ name }}</p>
<p>性別:{{ gender }}</p>
<p>年齡:{{ age }}</p>
</div>
<div>
<button @click="name = 'juejin'">改變姓名</button>
<button @click="gender = '女'">改變性別</button>
<button @click="age = '20'">改變年齡</button>
</div>
復(fù)制代碼
參數(shù)都可以正常改變,成功改頭換面
toRefs總結(jié)
toRefs會(huì)將我們一個(gè)響應(yīng)式的對(duì)象轉(zhuǎn)變?yōu)橐粋€(gè)普通對(duì)象,然后將這個(gè)普通對(duì)象里的每一個(gè)屬性變?yōu)橐粋€(gè)響應(yīng)式的數(shù)據(jù)
五、setup中執(zhí)行方法
方式一
以reactive定義響應(yīng)式數(shù)據(jù)的方式來定義方法
<script>
import {ref, reactive,toRefs} from "vue";
export default {
name: "test",
setup(){
const str = ref('inline')
const fun = reactive({
fun1(data){
console.log(str.value)
this.fun2(data)
},
fun2(data){
console.log(data)
console.log('我是fun2')
}
})
return{
...toRefs(fun),
}
}
}
</script>
復(fù)制代碼
通過點(diǎn)擊事件將值傳給fun1,fun1接收到后在傳給fun2
這里我們用this.fun2()的方式去調(diào)用fun2,為什么這里用this可以正常執(zhí)行不會(huì)報(bào)undefind,因?yàn)檫@里的this非彼this,Vue2里的this是實(shí)例這里的this是對(duì)象
<button @click="fun1('你好')">點(diǎn)我1</button>
復(fù)制代碼
結(jié)果,成功調(diào)用并輸出
image.png
方式二
注意這里調(diào)用fun2的方式與方式一不同,直接調(diào)用就可以,不用this調(diào)用
export default {
name: "test",
setup(){
const fun1 = (data) => {
fun2(data)
}
const fun2 = (data) => {
console.log(data)
}
return{
fun1,
}
}
}
復(fù)制代碼
調(diào)用
<button @click="fun1('你好 inline')">點(diǎn)我1</button>
復(fù)制代碼
結(jié)果
image.png
方式三
這種方式避免了將功能邏輯都堆疊在setup的問題,我們可以將獨(dú)立的功能寫成單獨(dú)的函數(shù)
這里我在setup外寫了fun() login()兩個(gè)功能函數(shù),并在setup內(nèi)分別調(diào)用
import {ref, reactive,toRefs} from "vue";
export default {
name: "test",
setup(){
const test1 = fun() // 如果函數(shù)返回參數(shù)過多,可以賦值給變量并用擴(kuò)展運(yùn)算符暴露給組件的其余部分
const { test } = login() // 也可單個(gè)接收
return{
...toRefs(test1),
test,
}
}
}
// 功能1
function fun(){
let str = ref('我是功能1')
function fun1(data){
console.log(str.value)
fun2(data)
}
function fun2(data){
console.log(data)
}
return{
fun1,
fun2,
}
}
// 功能2
function login() {
const obj = reactive({
msg:'我是功能2,我愛掘金'
})
function test() {
console.log(obj.msg)
}
return{
test
}
}
</script>
復(fù)制代碼
調(diào)用
<button @click="fun1('你好 inline')">點(diǎn)我1</button>
<button @click="test">點(diǎn)我2</button>
復(fù)制代碼
方式四
與方式三一樣,只是我們將兩個(gè)功能函數(shù)提取出來放在單獨(dú)的.js文件中
image.png
然后引入組件,并在setup內(nèi)調(diào)用
<template>
<div style="text-align: center;margin-top: 50px">
<button @click="fun1('你好 inline')">點(diǎn)我1</button>
<button @click="test">點(diǎn)我2</button>
</div>
</template>
<script>
import {ref, reactive,toRefs} from "vue";
import { fun,login } from './test.js'
export default {
name: "test",
setup(){
const test1 = fun()
const { test } = login()
return{
...toRefs(test1),
test,
}
}
}
</script>
復(fù)制代碼
方式五
我們還可以這樣寫,這里我定義一個(gè)reactive響應(yīng)式對(duì)象,賦值給login變量,這個(gè)響應(yīng)式對(duì)象內(nèi)有我們登錄需要的參數(shù)、驗(yàn)證和方法,這里我們?nèi)糠旁趌ogin這個(gè)響應(yīng)式對(duì)象內(nèi)然后用toRefs及擴(kuò)展運(yùn)算符暴露出去
<script>
import {ref, reactive,toRefs} from "vue";
export default {
name: "test",
setup(){
const login = reactive({
param: {
username: '123',
password: '123456',
},
rules: {
username: [{ required: true, message: '請(qǐng)輸入用戶名', trigger: 'blur' }],
password: [{ required: true, message: '請(qǐng)輸入密碼', trigger: 'blur' }],
},
login(){
this.param.username = 'inline'
this.param.password = '123456'
console.log('成功登錄!')
}
})
return{
...toRefs(login),
}
}
}
</script>
復(fù)制代碼
我們使用一下
<input type="text" v-model="param.username">
<input type="password" v-model="param.password">
<button @click="login">登錄</button>
復(fù)制代碼
image.png
正常執(zhí)行,所以我們還可以將一個(gè)功能的所有方法和相關(guān)參數(shù)寫在一個(gè)reactive對(duì)象內(nèi)
如有遺漏的執(zhí)行方式歡迎評(píng)論區(qū)指出~~~
六、script setup
script setup已在vue3.2的版本上正式發(fā)布
用法
<script setup>
</script>
復(fù)制代碼
是不是異常簡(jiǎn)單
變量方法無需return
使用<script setup>時(shí),模板被編譯成一個(gè)內(nèi)聯(lián)在 setup 函數(shù)作用域內(nèi)的渲染函數(shù)。這意味著內(nèi)部聲明的任何頂級(jí)綁定<script setup>都可以直接在模板中使用
<script setup>
const msg = 'Hello!'
</script>
<template>
<div>{{ msg }}</div>
</template>
復(fù)制代碼
script setup內(nèi)定義的變量和方法無需返回,可直接使用
組件引入
導(dǎo)入的組件無需注冊(cè),可直接使用
<script setup>
// 導(dǎo)入的組件也可以直接在模板中使用
import Foo from './Foo.vue'
import { ref } from 'vue'
// 編寫合成API代碼,就像在正常設(shè)置中一樣
// 不需要手動(dòng)返回所有內(nèi)容
const count = ref(0)
const inc = () => {
count.value++
}
</script>
<template>
<Foo :count="count" @click="inc" />
</template>
復(fù)制代碼
發(fā)布Props和Emits
<script setup>
const props = defineProps({
foo: String
})
const emit = defineEmits(['update', 'delete'])
</script>
復(fù)制代碼
普通script和script setup
script setup可以和script同時(shí)存在
<script>
export const name = 1
</script>
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
復(fù)制代碼
script setup 附加選項(xiàng)
script setup給我們提供了大多數(shù)與 options api等效的能力
就是說options api能辦到的事 script setup大部分都能辦到
那還有哪些是script setup做不到的呢?如下:
name
inheritAttrs
插件或庫所需要的自定義選項(xiàng)
那我要是想用這些怎么辦呢?答案是分開寫
<script>
export default {
name: 'CustomName',
inheritAttrs: false,
customOptions: {}
}
</script>
<script setup>
// script setup logic
</script>
復(fù)制代碼
defineExpose
script setup定義的變量默認(rèn)不會(huì)暴露出去,因?yàn)樽兞窟@時(shí)候包含在setup的閉包中。這時(shí)我們可以使用definExpose({ })來暴露組件內(nèi)部屬性給父組件使用
<script setup>
const a = 1
const b = ref(2)
defineExpose({
a,
b
})
</script>
復(fù)制代碼
當(dāng)父組件通過模板引用獲取此組件的實(shí)例時(shí),檢索到的實(shí)例將會(huì)是這樣{ a: number, b: number }(引用會(huì)像在普通實(shí)例上一樣自動(dòng)展開)
關(guān)于本文
https://juejin.cn/post/7029339447078420493
七、寫在最后
script setup可以說的東西還有很多,我們可以深入探索。
在我們閱讀完官方文檔后,我們一定會(huì)進(jìn)行更深層次的學(xué)習(xí),比如看下框架底層是如何運(yùn)行的,以及源碼的閱讀。
這里廣東靚仔給下一些小建議:
在看源碼前,我們先去官方文檔復(fù)習(xí)下框架設(shè)計(jì)理念、源碼分層設(shè)計(jì)
閱讀下框架官方開發(fā)人員寫的相關(guān)文章
借助框架的調(diào)用棧來進(jìn)行源碼的閱讀,通過這個(gè)執(zhí)行流程,我們就完整的對(duì)源碼進(jìn)行了一個(gè)初步的了解
接下來再對(duì)源碼執(zhí)行過程中涉及的所有函數(shù)邏輯梳理一遍
作者:廣東靚仔
歡迎關(guān)注:前端早茶