在Vue3中高级前端是这样给按钮添加loading效果的

前端77 2024-08-13 17:03:02 阅读 68

前言

一个页面有多个按钮,每个按钮都要添加loading效果,高级前端是如何在Vue3控制按钮是否显示loading效果的呢?

普通前端

我们先来看看初级普通前端平常是怎么给按钮添加loading效果的:

<code><script setup >

import { ref } from 'vue'

const asyncFn = () => new Promise(resolve => {

setTimeout(resolve, 3000)

})

const loading1 = ref(false)

const handler1 = async () => {

loading1.value = true

try {

await asyncFn()

} finally {

loading1.value = false

}

}

const loading2 = ref(false)

const handler2 = async () => {

loading2.value = true

try {

await asyncFn()

} finally {

loading2.value = false

}

}

const loading3 = ref(false)

const handler3 = async () => {

loading3.value = true

try {

await asyncFn()

} finally {

loading3.value = false

}

}

</script>

<template>

<el-button type="primary" @click="handler1" :loading="loading1">code>

按钮1

</el-button>

<el-button @click="handler2" :loading="loading2">code>

按钮2

</el-button>

<el-button type="primary" plain @click="handler3" :loading="loading3">code>

按钮3

</el-button>

</template>

通过以上代码可以看到,一个页面有多个按钮,每个按钮都要添加loading效果,所以声明了loading1、loading2、loading3 ...变量来控制按钮是否显示loading效果,非常不优雅。 那么高级前端是如何优雅的给按钮添加loading效果的呢?

高级前端

首先先封装一个MyButton组件:

<script setup >

import { ref, useSlots } from 'vue'

const props = defineProps(['onClick'])

const loading = ref(false)

const clickHandler = async (e) => {

loading.value = true

try {

await props.onClick(e)

} finally {

loading.value = false

}

}

const slots = useSlots()

</script>

<template>

<el-button @click="clickHandler" :loading="loading">code>

<template v-for="(_, key, i) in slots" :key="i" #[key]>code>

<slot :name="key" />code>

</template>

</el-button>

</template>

接下来引用MyButton组件,绑定click事件,返回Promise就可以优雅的给按钮添加一个loading效果了

<script setup >

import MyButton from './MyButton.vue';

const asyncFn = () => new Promise(resolve => {

setTimeout(resolve, 3000)

})

const handler1 = async () => {

// ...

await asyncFn()

}

const handler3 = () => {

// ...

return asyncFn()

}

</script>

<template>

<MyButton type="primary" @click="handler1">code>

按钮1

</MyButton>

<MyButton @click="asyncFn">code>

按钮2

</MyButton>

<MyButton type="primary" plain @click="handler3">code>

<template #loading>

<div class="custom-loading">code>

<svg class="circular" viewBox="-10, -10, 50, 50">code>

<path class="path" d="

M 30 15

L 28 17

M 25.61 25.61

A 15 15, 0, 0, 1, 15 30

A 15 15, 0, 1, 1, 27.99 7.5

L 15 15

" style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)" />code>

</svg>

</div>

</template>

按钮3

</MyButton>

</template>

<style scoped>

.el-button .custom-loading .circular {

margin-right: 6px;

width: 18px;

height: 18px;

animation: loading-rotate 2s linear infinite;

}

.el-button .custom-loading .circular .path {

animation: loading-dash 1.5s ease-in-out infinite;

stroke-dasharray: 90, 150;

stroke-dashoffset: 0;

stroke-width: 2;

stroke: var(--el-button-text-color);

stroke-linecap: round;

}

</style>

 

相关源码

总结

可以通过<code>defineProps(['onEventName'])声明事件,组件内部通过props.onEventName()触发事件,并且可以获取到事件回调函数的返回值,进而组件内部做更多逻辑处理,如给一个按钮组件自动添加loading等@eventName本质就是一个语法糖,最后还是会编译为onEventName通过属性的形式 传递给组件。如需了解更多,请查看文章:通过编译源码解析Vue不同方式监听事件的区别

结语

感谢您的耐心阅读,如果觉得这篇文章对您有帮助和启发,麻烦给个大大的赞~

文章转自:https://juejin.cn/post/7378893690145816612

 



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。