今天学vue3中的setup
它是vue项目文件的一个函数,写的地方和data,oncreate,methods等同级。
好处:业务逻辑代码集中
也就是这样:
一、在哪使用
<script>
export default {
components: {
},
data() {
return{
}
},
setup(){
return {
}
}
}
</script>
同时还有单文件组件语法糖<script setup>
<script setup>
console.log('hello script setup')
</script>
和上文使用效果一致
里面的代码会被编译成组件 setup() 函数的内容。
二、此函数的加载时机
新的 setup 选项在组件创建之前执行,一旦 props 被解析,就将作为组合式 API 的入口。
props解析后,组件创建前,因此:
在 setup 中你应该避免使用 this,因为它不会找到组件实例。setup 的调用发生在 data property、computed property 或 methods 被解析之前,所以它们无法在 setup 中被获取。
三、使用示例
背景:从后端获取数据
// 父组件(主页面):
<template>
<my-list :address='xxxx/xxxx/xxx' :userId='userId'>
</template>
<script>
import { defineAsyncComponent } from "vue" // 用于异步引入组件
export default {
components: {
myList: defineAsyncComponent(() => import('./composables/list.vue')),
},
data() {
return{
userId: '001'
}
}
}
</script>
// 子组件:
<template>
<div>{{list}}</div>
</template>
<script>
import { toRefs } from 'vue'
// 官网中用的例子是ref,这里用toRefs,两者的区别在于,ref浅拷贝,toRefs深拷贝。
// const a = ref([]) const b = ref(c)
// const a = toRefs ([]) const b = toRefs (c)
// 本例中使用的--没区别 有区别,c一个会随着b变一个不会
import { fetchData } from '@/api/repositories'
export default{
props:{
address: String
userId: String
},
setup(props) {
let list = toRefs([]) // 创建了一个响应式变量,用.value获取响应式值
const getList = async () => {
list.value = await fetchData(address,props.userId)
}
onMounted(getList ) // 在 `mounted` 时调用 `getList`完整写法是:onMounted( () => { getList() } )
return {
list,
getList
}
},
}
</script>
四、分析
这里插一条setup内部执行顺序的问题,
结论:从上到下执行,记录周期函数,作出返回值return,执行周期函数。
这里放三个情况:用来辨析
import { ref, onMounted, } from 'vue';
// 发起接口请求
function fetchList() {
let res = [
{id:'1',name:'JAVA',author:'s0nei',price:6},
{id:'2',name:'HTML',author:'d1iber',price:7},
{id:'3',name:'JS',author:'j1lion',price:8},
{id:'4',name:'C',author:'s0nei',price:9}
]
return res
}
export default function useList() {
const res = fetchList()
return {
res
};
}
// 正确,能返回出res,但是这个时候是执行时赋值,想要控制赋值时机比如mounted时,要其他操作,看下面
import { ref, onMounted, watch } from 'vue';
// 发起接口请求
function fetchList() {
let res = [
{id:'1',name:'JAVA',author:'s0nei',price:6},
{id:'2',name:'HTML',author:'d1iber',price:7},
{id:'3',name:'JS',author:'j1lion',price:8},
{id:'4',name:'C',author:'s0nei',price:9}
]
return res
}
export default function useList() {
let res = []
const getList = () => {
res = fetchList()
}
onMounted(()=>{
getList()
})
return {
res
};
}
// 错误,res仅仅是[],因为return已经做出来了,之后才是mounted执行,执行完了以后因为res不是响应式的,不会更新res值
import { ref, onMounted, watch } from 'vue';
// 发起接口请求
function fetchList() {
let res = [
{id:'1',name:'JAVA',author:'s0nei',price:6},
{id:'2',name:'HTML',author:'d1iber',price:7},
{id:'3',name:'JS',author:'j1lion',price:8},
{id:'4',name:'C',author:'s0nei',price:9}
]
return res
}
export default function useList() {
let res = ref([])
const getList = () => {
res.value = fetchList()
}
onMounted(()=>{
getList()
})
return {
res
};
// 正确,创建了响应式的,先return一个[],然后在MOUNTED的时候被改成正确值
}
五、发现问题
这样子写纵使有关业务的代码都集中在了一起,但是多个业务时候会很长,下一步开始用组件把他们分开。