1. 程式人生 > 實用技巧 >減少 Vue 專案初始化頁面的樣板程式碼

減少 Vue 專案初始化頁面的樣板程式碼

背景

在 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>