组合API
为什么出现组合API
对于小型项目而言,使用Vue2的方式,数据和业务逻辑分离确实方便,但是当项目过大后,在一个Vue中加功能就会加数据加逻辑,数据和逻辑并不在一起,维护难度加大,复用性降低,大部分功能看似相似,却做着复制粘贴的功能开发
组合API使用示例
ref:简单数据处理
import { ref } from "vue";
export default {
name: "App",
// 入口函数
setup() {
// 1. 使用 ref 只能定义基本类型的变化,不能监听复杂类型的变化(对象/数组)
let count = ref(0);
// 2. 在组合 API 中,如果想定义方法,不用定义到 methods 中,直接定义即可
function myFn() {
count.value += 1;
}
// 3. 注意点:在组合 API 中定义的变量/方法,要想在外面使用,必须通过 return 暴露出去
return { count, myFn };
},
};
reactive:复杂数据处理(对象,数组)
import { reactive } from "vue";
export default {
name: "App",
// 入口函数
setup() {
// 1. 使用 reactive 定义(对象/数组)
let state = reactive({
stus: [{ id: 1, name: "zs", age: 10 }],
});
// 2. 改变其中的一个值,其会相应变换
function changeStus() {
state.stus[0].age += 1;
}
return { state, changeStus };
},
};
/*
1. 什么是reactive?
- reactive 是 Vue3中提供的实现响应式数据的方法
- 在 Vue2中响应式数据是通过defineProperty来实现的
而在Vue3中响应式数据是通过 ES6 中的 Proxy 来实现的
- 本质:就是将传入的数据包装成一个 Proxy 对象
2. reactive 注意点:
- reactive 参数必须是对象(json/arr)
- 如果给 reactive 传递了其他对象
+ 默认情况下修改对象,界面不会自动更新
+ 如果想更新,可以通过重新赋值的方式
*/
抽离
import { reactive } from "vue";
export default {
name: "App",
setup() {
// 只需要在这里引入进来就行了
let { state, changeStus } = change();
return { state, changeStus };
},
};
// 在外面定义一个业务逻辑单元(类似类,有数据和操作)
function change() {
// 1. 使用 reactive 定义(对象/数组)
let state = reactive({
stus: [{ id: 1, name: "zs", age: 10 }],
});
// 2. 改变其中的一个值,其会相应变换
function changeStus() {
state.stus[0].age += 1;
}
return { state, changeStus };
}
抽离到js
// chang.js
// 在外面定义一个业务逻辑单元(类似类,有数据和操作)
import { reactive } from "vue";
export default function change() {
// 1. 使用 reactive 定义(对象/数组)
let state = reactive({
stus: [
{ id: 1, name: "zs", age: 10 },
{ id: 2, name: "ls", age: 20 },
{ id: 3, name: "ww", age: 30 },
]
});
// 2. 改变其中的一个值,其会相应变换
function changeStus() {
state.stus[0].age += 1
}
return { state, changeStus }
}
使用
import change from "./change";
export default {
name: "App",
setup() {
// 只需要在这里引入进来就行了
let { state, changeStus } = change();
return { state, changeStus };
},
};
本质
从setup中暴露的数据,会注入到 Option api 的data中, 从setup 中暴露的方法,会注入到Option api的methods中
setup 执行(注入)时机
在 beforeCreate 和 created 之间
- beforeCreate:表示组件刚刚被创建出来,组件的data和methods还没初始化好
- setup
- Created:表示组件刚刚被创建出来,并且组件的data和methods已经初始化好
结论:
- 由于在执行 setup 函数的时候,还没有执行 Created 生命周期方法,所以在 setup 函数中,是无法使用 data和methods的
- 由于我们不能在 setup 函数中使用 data 和 methods,所以Vue为了避免我们错误的使用,它直接将setup函数中的this修改成了undefined
- setup 函数只能是同步的不能是异步的(不能在函数前面加 async)
允许多个根节点
在Vue3中,一个模板可以有多个根节点了
CSS直接绑定JS变量
<script setup>
let globleWidth = 100px
</script>
<style lang="sass>
.box
width: v-bind(globleWidth )
</style>
变量直接使用
在setup
中定义的变量可以直接在模板中使用
<template>
<button type="button" @click="count++">count is: {{ count }}</button>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
响应式绑定
在Vue3中,变量的响应式采用了ref()
和reactive()
函数进行绑定,否则变量改变后,页面的数据依然无法改变
ref()
是对reactive()
的二次包装ref()
定义的数据访问的时候要多一个.value
ref()
定义基本数据类型reactive()
定义数组和对象
计算属性
只执行一次,减少计算,有缓存机制
import { computed } from 'vue'
const double = computed(()=>{
return count.value* 2;
})
监听
监听数据的变化,然后需要执行的操作
import { watch} from 'vue'
watch(user, () => {
fullName3.value = user.firstName + '-' + user.lastName;
}, {
immediate: true, // 是否初始化立即执行一次, 默认是false
deep: true, // 是否是深度监视, 默认是false
});
watch(user, (newValue, oldValue) => {
fullName3.value = user.firstName + '-' + user.lastName;
});
watch(() => user.name, (newValue, oldValue) => {
fullName3.value = user.firstName + '-' + user.lastName;
});
插槽
https://blog.csdn.net/m0_47135993/article/details/124259448
动态组件
用于解决Tab切换的场景
<template>
<div class="tabs-content" @click="switchTab(tab)" v-for="(tab, index) in tabData" :key="index">
{{ tab.name }}
</div>
<component :is="currentTab.tabComp"></component>
</template>
<script setup lang="ts">
import { reactive, markRaw } from 'vue'
import A from './A.vue'
import B from './B.vue'
import C from './C.vue'
type tabType = {
name: string,
tabComp: any
}
type Comp = Pick<tabType, 'tabComp'>
const tabData = reactive<tabType[]>([
{
name: 'A组件',
// proxy会代理reactive中的所有内容
// 无需对组件进行proxy代理
// 必须使用markRaw跳过对组件的代理,否则vue会给警告
tabComp: markRaw(A)
},
{
name: 'B组件',
tabComp: markRaw(B)
},
{
name: 'C组件',
tabComp: markRaw(C)
},
])
let currentTab = reactive<Comp>({
tabComp: tabData[0].tabComp
})
const switchTab = (tab: tabType) => {
currentTab.tabComp = tab.tabComp
}
</script>
<style scoped lang="less">
.tabs-content {
display: inline-block;
width: 100px;
border: 1px solid #ccc;
background: rgb(175, 96, 96);
color: white;
}
</style>
异步组件
用于如滚动到组件再进行加载,否则不加载,实现按需引入等
provide和inject
//父组件代码
<script>
import { provide } from "vue"
export default {
setup(){
provide('info',"值")
}
}
</script>
//子组件 代码
<template>
{{info}}
</template>
<script>
import { inject } from "vue"
export default {
setup(){
const info = inject('info')
return{
info
}
}
}
</script>