这篇文章主要介绍“Vue3中怎么使用CompositionAPI解决问题”,在日常操作中,相信很多人在Vue3中怎么使用CompositionAPI解决问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue3中怎么使用CompositionAPI解决问题”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
一、为什么选择CompositionAPI
Vue2的局限性
-
组件逻辑膨胀导致的可读性变差
-
无法跨组件重用代码
-
Vue2对TS的支持有限
在传统的OptionsAPI中我们需要将逻辑分散到以下六个部分。
OptionsAPI
-
components -
props -
data -
computed -
methods -
lifecycle methods
如何使用CompositionAPI解决问题
最佳的解决方法是将逻辑聚合就可以很好的代码可读性。
这就是我们的CompositionAPI语法能够实现的功能。CompositionAPI是一个完全可选的语法与原来的OptionAPI并没有冲突之处。他可以让我们将相同功能的代码组织在一起,而不需要散落到optionsAPI的各个角落
代码重用方法PK
Vue2中的跨组件重用代码,我们大概会有四个选择
1、Mixin – 混入
-
代码混入其实就是设计模式中的混合模式,缺点也非常明显。
-
可以理解为多重继承,简单的说就是一个人如何有两个父亲
缺点
-
无法避免属性名冲突
-
继承关系不清晰
2、Mixin Factory – 混入工厂
返回一个
✅代码重用方便
✅继承关系清洗
3、ScopeSlots – 作用域插槽
❌可读性不高
❌配置复杂 – 需要再模板中进行配置
❌性能低 – 每个插槽相当于一个实例
4、CompositionApi – 复合API
✅代码量少
✅没有引入新的语法,只是单纯函数
✅异常灵活
✅工具语法提示友好 – 因为是单纯函数所以 很容易实现语法提示、自动补偿
二、setup & ref
使用CompositionAPI理由
✅更好的Typescript支持
✅在复杂功能组件中可以实现根据特性组织代码 – 代码内聚性, 比如:
排序和搜索逻辑内聚
✅组件间代码复用
setup是什么
-
在以下方法前执行:
-
Components
-
Props
-
Data
-
Methods
-
Computed Properties
-
Lifecycle methods
-
可以不在使用难于理解的this
-
有两个可选参数
-
props – 属性 响应式对象 且 可以监听watch))
import {watch} from "vue"
export defalut {
props: {
name: String
},
setupprops) {
watch) => {
console.logprops.name)
})
}
}
-
context 上下文对象 – 用于代替以前的this方法可以访问的属性
setup props,context) {
const {attrs,slots,parent,root,emit} = context
}
ref是什么
对基本数据类型数据进行装箱操作使得成为一个响应式对象,可以跟踪数据变化。
总结
可维护性明显提高
-
可以控制哪些变量暴露
-
可以跟中哪些属性被定义 (属性继承与引用透明)
三、Methods
基础用法
自动拆装箱总结
-
JS :需要通过.value访问包装对象
-
模板: 自动拆箱
四、 Computed – 计算属性
这个地方实在没什么好讲的,和Vue2没变化
<template>
<div>
<div>Capacity: {{ capacity }}</div>
<p>Spases Left: {{ sapcesLeft }} out of {{ capacity }}</p>
<button @click="increaseCapacity)">Increase Capacity</button>
</div>
</template>
<script>
import { ref, computed, watch } from "vue";
export default {
setupprops, context) {
const capacity = ref3);
const attending = ref["Tim", "Bob", "Joe"]);
function increaseCapacity) {
capacity.value++;
}
const sapcesLeft = computed) => {
return capacity.value - attending.value.length;
});
return { capacity, increaseCapacity, attending, sapcesLeft };
},
};
</script>
五、Reactive – 响应式语法
之前reactive 的 Ref 去声明所有的响应式属性
import { ref,computed } from 'vue'
export default {
setup){
const capacity = ref4);
const attending = ref["Tim","Bob","Joe"]);
const spacesLeft = computed)=>{
return capacity.value - attending.value.length
})
function increaseCapacity){ capacity.value ++;}
return { capacity,increaseCapacity,attending,spacesLeft}
}
}
但是有另一个等效的方法用它去代替 reactive 的Ref
import { reactive,computed } from 'vue'
export default {
setup){
const event = reactive{
capacity:4,
attending:["Tim","Bob","Joe"],
spacesLeft:computed)=>{
return event.capacity - event.attending.length;
})
})
}
}
过去我们用vue2.0的data来声明响应式对象,但是现在在这里每一个属性都是响应式的包括computed 计算属性
这2种方式相比于第一种没有使用.
接下来 我们再声明method 这2种语法都ok,取决于你选择哪一种
setup){
const event = reactive){
capacity:4,
attending:["Tim","Bob","Joe"],
spacesLeft:computed)=>{
return event.capacity - event.attending.length;
})
function increaseCapacity){event.capacity++}
//return整个对象
return {event,increaseCapacity}
}
}
<p>Spaces Left:{{event.spacesLeft}} out of {{event.capacity}}</p>
<h3>Attending</h3>
<ul>>
<li v-for="name,index) in event.attending" :key="index">
{{name}}
</li>
</ul>
<button @click="increaseCapacity)"> Increase Capacity</button>
在这里我们使用对象都是.属性的方式,但是如果 这个结构变化了,event分开了编程了一个个片段,这个时候就不能用.属性的方式了
//在这里可以使用toRefs
import {reactive,computed,toRefs} from 'vue'
export default{
setup){
const event = reactive{
capacity:4,
attending:["Tim","Bob","Joe"],
spacesLeft:computed)=>{
return event.capacity -event.attending.length;
})
})
function increaseCapacity){ event.capacity ++ }
return {...toRefsevent),increaseCapacity}
}
}
如果没有 increaseCapacity) 这个方法 直接可以简化为
return toRefsevent)
完整代码
<div>
<p>Space Left : {{event.spacesLeft}} out of {{event.capacity}} </p>
<h3>Attending</h3>
<ul>
<li v-for="name,index)" in event.attending :key="index">{{name}}
</li>
</ul>
<button @click="increaseCapacity">Increase Capacity</button>
</div>
</template>
<script>
//第一种
import {ref,computed } from 'vue'
export default {
setup){
const capacity = ref4)
const attending = ref["Tim","Bob","Joe"])
const spaceLeft = computed)=>{
return capacity.value - attending.value.length;
});
function increaseCapacity){ capacity.value++; }
return {capacity,increaseCapacity,attending,spaceLeft}
}
}
//返回一个响应式函数 第二种
import { reactive,computed } from 'vue'
export default {
setup){
const event = reactive{
capacity:4,
attending:["Tim","Bob","Joe"],
spaceLeft:computed)=>{
return event.capacity - event.attending.length;
})
})
//我们不再使用.value
function increaseCapacity) { event.capacity++; }
//把这个event放入到template中
return { event,increaseCapacity}
}
}
</script>
六、 Modularizing
使用CompositionAPI的两个理由
1、可以按照功能组织代码
2、组件间功能代码复用
七、 LifecycleHooks – 生命周期钩子
| Vue2 | Vue3 |
|---|---|
| beforeCreate | ❌setup替代) |
| created | ❌setup替代) |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeDestroy | onBeforeUnmount |
| destroyed | onUnmounted |
| errorCaptured | onErrorCaptured |
| – | ?onRenderTracked |
| – | ?onRenderTriggered |
setup中调用生命周期钩子
import { onBeforeMount,onMounted } from "vue";
export default {
setup) {
onBeforeMount) => {
console.log'Before Mount!')
})
onMounted) => {
console.log'Before Mount!')
})
},
};
八、Watch – 监听器
// 所有依赖响应式对象监听
watchEffect) => {
results.value = getEventCountsearchInput.value);
});
// 特定响应式对象监听
watch
searchInput,
) => {
console.log"watch searchInput:");
}
);
// 特定响应式对象监听 可以获取新旧值
watch
searchInput,
newVal, oldVal) => {
console.log"watch searchInput:", newVal, oldVal);
},
);
// 多响应式对象监听
watch
[firstName,lastName],
[newFirst,newLast], [oldFirst,oldlast]) => {
// .....
},
);
// 非懒加载方式监听 可以设置初始值
watch
searchInput,
newVal, oldVal) => {
console.log"watch searchInput:", newVal, oldVal);
},
{
immediate: true,
}
);
九、Sharing State – 共享状态
编写一个公共函数usePromise函数需求如下:
-
results : 返回Promise执行结果
-
loading: 返回Promise运行状态
-
PENDING :true
-
REJECTED : false
-
RESOLVED: false
-
error : 返回执行错误
import { ref } from "vue";
export default function usePromisefn) {
const results = refnull);
// is PENDING
const loading = reffalse);
const error = refnull);
const createPromise = async ...args) => {
loading.value = true;
error.value = null;
results.value = null;
try {
results.value = await fn...args);
} catch err) {
error.value = err;
} finally {
loading.value = false;
}
};
return { results, loading, error, createPromise };
}
应用
import { ref, watch } from "vue";
import usePromise from "./usePromise";
export default {
setup) {
const searchInput = ref"");
function getEventCount) {
return new Promiseresolve) => {
setTimeout) => resolve3), 1000);
});
}
const getEvents = usePromisesearchInput) => getEventCount));
watchsearchInput, ) => {
if searchInput.value !== "") {
getEvents.createPromisesearchInput);
} else {
getEvents.results.value = null;
}
});
return { searchInput, ...getEvents };
},
};
十、Suspense – 悬念
复杂的Loading实现
我们考虑一下当你加载一个远程数据时,如何显示loading状态
通常我们可以在模板中使用v-if
但是在一个组件树中,其中几个子组件需要远程加载数据,当加载完成前父组件希望处于Loading状态时我们就必须借助全局状态管理来管理这个Loading状态
Suspense基础语法
这个问题在Vue3中有一个全新的解决方法。
这就是Suspense Component,悬念组件。
<template>
<div>
<div v-if="error">Uh oh .. {{ error }}</div>
<Suspense>
<template #default>
<div>
<Event />
<AsyncEvent />
</div>
</template>
<template #fallback> Loading.... </template>
</Suspense>
</div>
</template>
<script>
import { ref, onErrorCaptured, defineAsyncComponent } from "vue";
import Event from "./Event.vue";
const AsyncEvent = defineAsyncComponent) => import"./Event.vue"));
export default {
components: {
Event,
AsyncEvent,
},
setup) {
const error = refnull);
onErrorCapturede) => {
error.value = e;
// 阻止错误继续冒泡
return true;
});
return { error };
},
};
</script>
骨架屏实现
十一、Teleport – 传送门
功能
类似React中的Portal, 可以将特定的html模板传送到Dom的任何位置
基础语法
通过选择器QuerySelector配置
示例代码
<template>
<div>
<teleport to="#end-of-body" :disabled="!showText">
<!-- 【Teleport : This should be at the end 】 -->
<div>
<video src="../assets/flower.webm" muted controls="controls" autoplay="autoplay" loop="loop">
</video>
</div>
</teleport>
<div>【Teleport : This should be at the top】</div>
<button @click="showText = !showText">Toggle showText</button>
</div>
</template>
<script>
import { ref } from "vue";
export default {
setup) {
const showText = reffalse);
setInterval) => {
showText.value = !showText.value;
}, 1000);
return { showText };
},
};
</script>


















