背景
在 vue 项目开发中,对于大多数页面的初始化,都需要维护和业务无关的三个状态:pending、loaded、error,并根据状态显示不同的内容。譬如:
<template>
<div>
<div v-if="error">{{error.message}}</div>
<div v-else-if="loaded">{{text}}</div>
<div v-else>pending...</div>
</div>
</template>
<script>
// 模拟接口请求
const wait = time => new Promise(resolve => setTimeout(resolve, time))
export default {
data () {
return {
error: null,
loaded: false,
text: 1
};
},
created() {
wait(2500)
.then(() => this.text = 'test222')
.catch(e => this.error = e)
.finally(() => this.loaded = true)
}
}
</script>
不知不觉中,大家都在重复这些样板代码,这并不是啥好习惯。
对于通用的逻辑,我们可以抽象出来进行复用。
usage
test.vue
<template>
<Suspend :promise="usePromise">
<div>{{text}}</div>
</Suspend>
</template>
<script>
import Suspend from "./Suspend"
// 模拟接口请求
const wait = time => new Promise(resolve => setTimeout(resolve, time))
export default {
data () {
return {
usePromise: null,
text: 1
};
},
components: {
Suspend
},
created() {
this.usePromise = this.$_init()
},
methods: {
$_init() {
return wait(2500).then(() => this.text = 'test222')
}
}
}
</script>
Suspend.vue
具体样式根据项目自定义,下面只是一个粗糙的实现:
<template>
<div>
<slot v-if="error" name="error">{{error.message}}</slot>
<slot v-else-if="loaded"></slot>
<slot v-else name="pending">pending...</slot>
</div>
</template>
<script>
export default {
props: {
promise: {
validator: p => p && typeof p.then === 'function' && typeof p.catch === 'function',
}
},
data () {
return {
loaded: false,
error: null
};
},
watch: {
promise: {
immediate: true,
handler(value) {
if (!value) return;
this.loaded = false;
this.error = null;
return value
.then(() => this.loaded = true)
.catch(error => this.error = error)
}
}
},
}
</script>