前言
一个页面有多个按钮,每个按钮都要添加loading效果,高级前端是如何在Vue3控制按钮是否显示loading效果的呢?
普通前端
我们先来看看初级普通前端平常是怎么给按钮添加loading效果的:
<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"> 按钮1 </el-button> <el-button @click="handler2" :loading="loading2"> 按钮2 </el-button> <el-button type="primary" plain @click="handler3" :loading="loading3"> 按钮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"> <template v-for="(_, key, i) in slots" :key="i" #[key]> <slot :name="key" /> </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"> 按钮1 </MyButton> <MyButton @click="asyncFn"> 按钮2 </MyButton> <MyButton type="primary" plain @click="handler3"> <template #loading> <div class="custom-loading"> <svg class="circular" viewBox="-10, -10, 50, 50"> <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)" /> </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>
相关源码
总结
可以通过defineProps(['onEventName'])
声明事件,组件内部通过props.onEventName()
触发事件,并且可以获取到事件回调函数的返回值,进而组件内部做更多逻辑处理,如给一个按钮组件自动添加loading等@eventName
本质就是一个语法糖
,最后还是会编译为onEventName
通过属性的形式
传递给组件。如需了解更多,请查看文章:通过编译源码解析Vue不同方式监听事件的区别 结语
感谢您的耐心阅读,如果觉得这篇文章对您有帮助和启发,麻烦给个大大的赞~
文章转自:https://juejin.cn/post/7378893690145816612