减少 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>
posted @ 2020-08-25 15:32  Liaofy  阅读(243)  评论(0编辑  收藏  举报