Home  >  Article  >  Web Front-end  >  Vue component practice: Develop a loading Button component--LoadingButton

Vue component practice: Develop a loading Button component--LoadingButton

青灯夜游
青灯夜游forward
2022-05-23 20:24:524378browse

This article will guide you step by step in developing a super practical vueLoadingButton component--LoadingButton. I hope it will be helpful to everyone.

Vue component practice: Develop a loading Button component--LoadingButton

Component background

In daily work, we often encounter a scene:

Vue component practice: Develop a loading Button component--LoadingButton

Request some interface data when clicking a button, and in order to avoid repeated clicks by users, we usually add loading to these buttons. The function of adding loading itself is very simple. As long as we define a variable and use it in the Button component, but when doing background management projects, such a button may There are many, many variables in one component may be xxx_loading, which is time-consuming, labor-intensive and not elegant enough.

Next, we make a simple encapsulation of the Button component to solve this time-consuming, labor-intensive and inelegant loading problem. (Learning video sharing: vue video tutorial)

Inspiration source

We are using AntdModal dialog box, when our onOk is asynchronous function, the OK button of Modal will automatically add loading Effect, close the pop-up window after the function execution is completed, like this:

Vue component practice: Develop a loading Button component--LoadingButton

At this time, the code is as follows:

asyncFunc() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve()
    }, 2000)
  })
},
handleTestModal() {
  const that = this
  this.$confirm({
    title: '测试异步函数',
    content: '异步函数延迟两秒结束',
    async onOk() {
      await that.asyncFunc()
    }
  })
},

After seeing this effect, I thought that if I could encapsulate a Button component and pass in the function that needs to be executed, the component would automatically add loading according to the function execution. What effect would it have? Not very convenient.

Implement LoadingButton

Define component parameters

Just define a few here Commonly used parameters: text (button text) , type (button type) , asyncFunc (asynchronous function executed when the button is clicked) , delay(loading delay), in addition, a loading variable inside the component is needed to control the state of our Button component, the code is as follows:

export default {
    data() {
        return {
          loading: false
        }
    },
    props: {
        text: {
          type: String,
          default: '确定'
        },
        type: {
          type: String,
          default: 'primary'
        },
        delay: {
          type: Number,
          default: 0
        },
        asyncFunc: {
          type: Function,
          default: () => {}
        }
    },
}

Use the <span style="font-size: 18px;">Button</span> component in <span style="font-size: 18px;">antd</span> to perform the second step Sub-encapsulation

In our custom LoadingButton component, use the parameters defined above and bind a click event, The code is as follows:

<template>
  <Button :type="type" :loading="loading" @click="handleClick">
    {{ text }}
  </Button>
</template>

<script>
import { Button } from &#39;ant-design-vue&#39;

export default {
    components: {
        Button
    },
    methods: {
        handleClick() {}
    }
}
</script>

Judge asynchronous function<span style="font-size: 18px;">asyncFunc</span>

This part is The most important part of the entire component is how we determine whether the incoming function is an asynchronous function. When the asyncFunc function we pass in is an asynchronous function, the component needs to add a loading animation, then we should How to determine whether a function is an asynchronous function?

ReferenceantdHow is it implemented?

We just introduced the Modal dialog box of antd above. There is similar logic in it, so you might as well read this part of the related source code and take a look. Implementation method of antd:

// components/modal/ActionButton.jsx

onClick() {
  const { actionFn, closeModal } = this;
  if (actionFn) {
    let ret;
    if (actionFn.length) {
      ret = actionFn(closeModal);
    } else {
      ret = actionFn();
      if (!ret) {
        closeModal();
      }
    }
    if (ret && ret.then) {
      this.setState({ loading: true });
      ret.then(
        (...args) => {
          // It&#39;s unnecessary to set loading=false, for the Modal will be unmounted after close.
          // this.setState({ loading: false });
          closeModal(...args);
        },
        e => {
          // Emit error when catch promise reject
          // eslint-disable-next-line no-console
          console.error(e);
          // See: https://github.com/ant-design/ant-design/issues/6183
          this.setState({ loading: false });
        },
      );
    }
  } else {
    closeModal();
  }
},

Read the implementation of antd source code. We know that to determine whether a function is an asynchronous function, we can determine whether the function has .then(ret && ret.then) method, then we can also make a similar judgment. The code is as follows:

async handleClick() {
  const asyncFunc = this.asyncFunc
  if (!this.isFunc) {
    return
  }
  const ret = asyncFunc()

  // 如果是异步函数,则显示loading
  if (ret && ret.then) {
    this.loading = {
      delay: this.delay
    }
    ret.finally(() => {
      this.loading = false
    })
  }
}

TestLoadingButtonComponent

At this point our core component logic has been developed. Later we will write a demo to test whether this LoadingButton component meets expectations: demo The code is as follows:

<template>
  <div>
    <LoadingButton :delay="500" :asyncFunc="asyncFunc" />
  </div>
</template>

<script>
import LoadingButton from &#39;./LoadingButton.vue&#39;

export default {
  data() {
    return {
      loading: false
    }
  },
  components: {
    LoadingButton
  },
  methods: {
    asyncFunc() {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve()
        }, 2000)
      })
    }
  }
}
</script>

We wrote an asynchronous function asyncFunc to simulate asynchronous requests in actual business. Now you can see the effect:

Vue component practice: Develop a loading Button component--LoadingButton

is in line with the previous expected effect, so that when we have similar scenarios that require loading, we can directly use the LoadingButton component to click the asynchronous function that needs to be executed. Just pass it in, there is no need to define the loading variable.

写在最后

这个组件其实核心的代码非常少,也很容易读懂。由于最近在做一些业务这类场景比较多,感觉这个小组件还是挺实用的所以分享给大家,这里也是只对最重要的部分做了一个介绍,相信大家学会了之后也可以通过这个方式封装出符合自己实际场景需求的组件。最后,附上这个组件的完整代码:

<template>
  <Button :type="type" :loading="loading" @click="handleClick">
    {{ text }}
  </Button>
</template>

<script>
import { Button } from &#39;ant-design-vue&#39;

export default {
  data() {
    return {
      loading: false
    }
  },
  props: {
    text: {
      type: String,
      default: &#39;确定&#39;
    },
    type: {
      type: String,
      default: &#39;primary&#39;
    },
    delay: {
      type: Number,
      default: 0
    },
    asyncFunc: {
      type: Function,
      default: () => {}
    }
  },
  components: {
    Button
  },
  computed: {
    isFunc() {
      return typeof this.asyncFunc === &#39;function&#39;
    }
  },
  methods: {
    async handleClick() {
      const asyncFunc = this.asyncFunc
      if (!this.isFunc) {
        return
      }
      const ret = asyncFunc()

      // 如果是异步函数,则显示loading
      if (ret && ret.then) {
        this.loading = {
          delay: this.delay
        }
        ret.finally(() => {
          this.loading = false
        })
      }
    }
  }
}
</script>

原文地址:https://juejin.cn/post/7099234795720278046

作者:liangyue

(学习视频分享:web前端开发编程基础视频

The above is the detailed content of Vue component practice: Develop a loading Button component--LoadingButton. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:juejin.cn. If there is any infringement, please contact admin@php.cn delete