懒加载
Suspense搭配async函数的setup
父组件
<template>
<div class="app">
<h3>我是App组件</h3>
<Suspense>
<template v-slot:default>
<Child />
</template>
<template v-slot:fallback>
<h3>稍等,加载中...</h3>
</template>
</Suspense>
</div>
</template>
<script>
// import Child from './components/Child'//静态引入
import { defineAsyncComponent } from "vue";
const Child = defineAsyncComponent(() => import("./components/Child")); //异步引入
export default {
name: "App",
components: { Child },
};
</script>
<style>
.app {
background-color: gray;
padding: 10px;
}
</style>
子组件
<template>
<div class="child">
<h3>我是Child组件</h3>
{{ sum }}
</div>
</template>
<script>
import { ref } from "vue";
export default {
name: "Child",
async setup() {
let sum = ref(0);
let p = new Promise((resolve) => {
setTimeout(() => {
resolve({ sum });
}, 3000);
});
return await p;
},
};
</script>
<style>
.child {
background-color: skyblue;
padding: 10px;
}
</style>
路由懒加载
const routes = [
{
path: '/home',
component: () => import('./Home.vue')
},
// 其他路由...
];
路由预加载
const routes = [
{
path: '/home',
component: () => import('./Home.vue'),
meta: { preload: true }
},
// 其他路由...
];
异步组件
const AsyncFooWithOptions = defineAsyncComponent({
// 加载函数
loader: () => import("./demo.vue"),
//加载过程中的组件
loadingComponent: LoadingComponent,
//加载失败的组件
errorComponent: ErrorComponent,
// 在显示loadingComponent组件之前, 等待多长时间
delay: 200,
//加载组件的超时时间,如果超过这个值,则显示错误组件, 默认Infinity永不超时, 单位ms
timeout: 3000,
//定义组件是否可以挂起, 默认true
suspensible:true,
/** 异步组件加载失败的回调函数
* err: 错误信息,
* retry: 函数, 调用retry尝试重新加载
* fail: 函数, 指示加载程序结束退出
* attempts: 记录尝试的次数
*/
onError: function(err, retry, fail, attempts) {
}
})
缓存路由组件
vue-router
//使用vue-router时,切换页面时缓存页面
{
path: '/',
component: () => import('./views/index'),
name: 'index',
meta: {
title: '首页',
keepAlive: true,
},
},
vue文件
一种写法
<template>
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" v-if="$route.meta.keepAlive" :key="$route.name"></component>
</keep-alive>
<component :is="Component" v-if="!$route.meta.keepAlive" :key="$route.name">></component>
</router-view>
</template>
另一种写法
<template>
<div>vue-router小例子</div>
<div>router-link</div>
<router-view v-slot="{ Component }">
<keep-alive :include="KeepAliveList">
<component :is="Component"></component>
</keep-alive>
</router-view>
</template>
<script>
export default {
name: 'App',
data() {
return { KeepAliveList: [] }
},
watch: {
$route(to) {
//监听路由变化,把配置路由中keepAlive为true的name添加到include动态数组中
if (to.meta.keepAlive && this.KeepAliveList.indexOf(to.name) === -1) {
this.KeepAliveList.push(to.name)
}
},
},
}
</script>
effectScope
用于收集在其中所创建的副作用,并能对其进行统一的处理
使用场景
避免随着组件生命周期重复创建某些监听
// 使用到的组件都会重复创建监听器
function useMouse() {
const x = ref(0)
const y = ref(0)
function handler(e) {
x.value = e.x
y.value = e.y
}
window.addEventListener('mousemove', handler)
onUnmounted(() => {
window.removeEventListener('mousemove', handler)
})
return { x, y }
}
通过effecScope创建独立的scope
function useMouse() {
const x = ref(0)
const y = ref(0)
function handler(e) {
x.value = e.x
y.value = e.y
}
window.addEventListener('mousemove', handler)
// 通过onScopeDispose替换onUnmounted,意味着可以脱离组件使用
onScopeDispose(() => {
window.removeEventListener('mousemove', handler)
})
return { x, y }
}
function createSharedComposable(composable) {
let subscribers = 0
let state, scope
const dispose = () => {
// 通过闭包进行计数,当subscribers为0时,stop掉该scope
// 如果在组件中使用,则onUnmounted就意味着subscribers-1
if (scope && --subscribers <= 0) {
scope.stop()
state = scope = null
}
}
return (...args) => {
subscribers++
if (!state) {
scope = effectScope(true)
state = scope.run(() => composable(...args))
}
onScopeDispose(dispose)
return state
}
}
const useSharedMouse = createSharedComposable(useMouse)
export default useSharedMouse
简易的状态管理
import { effectScope } from '@vue/composition-api'
export default run => {
let isChange = false
let state
const scope = effectScope(true)
return () => {
// 防止重复触发
if (!isChange) {
state = scope.run(run)
isChange = true
}
return state
}
}
// store.js
import { computed, ref } from '@vue/composition-api'
import useGlobalState from './useGlobalState'
export default useGlobalState(
() => {
// state
const count = ref(0)
// getters
const doubleCount = computed(() => count.value * 2)
// actions
function increment() {
count.value++
}
return { count, doubleCount, increment }
}
)
// A.vue
import useStore from '@/hooks/useStore'
const { count, doubleCount, increment } = useStore()
// B.vue
import useStore from '@/hooks/useStore'
const { count, doubleCount, increment } = useStore()