減少 Vue 專案初始化頁面的樣板程式碼
阿新 • • 發佈:2020-08-25
背景
在 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>