1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Vue3+TypeScript项目构建之实现自定义指令v-loading axios请求时的加载动画

Vue3+TypeScript项目构建之实现自定义指令v-loading axios请求时的加载动画

时间:2024-05-03 16:29:19

相关推荐

Vue3+TypeScript项目构建之实现自定义指令v-loading  axios请求时的加载动画

最终实现效果

可以实现提示文字背景颜色的自定义

xzw-loading-text=‘别急嘛~’ // 默认为加载中

xzw-loading-background=‘rgba(0, 0, 0, .4)’ // 默认背景色为rgba(255,255,255,.8)

创建自定义指令函数

路径:/src/directives/loading/index.ts

Vue3与Vue2的自定义指令钩子有了很大的改变改变,详情戳链接

Vue3自定义指令钩子

created - 新的!在元素的 attribute 或事件侦听器应用之前调用。

bind → beforeMount

inserted → mounted

beforeUpdate:新的!这是在元素本身更新之前调用的,很像组件生命周期钩子。

update → 移除!有太多的相似之处要更新,所以这是多余的,请改用 updated。

componentUpdated → updated

beforeUnmount:新的!与组件生命周期钩子类似,它将在卸载元素之前调用。

unbind -> unmounted

const MyDirective = {beforeMount(el, binding, vnode, prevVnode) {},mounted() {},beforeUpdate() {}, // 新updated() {},beforeUnmount() {}, // 新unmounted() {}}

上TS代码 然后解析

// 全局加载组件const handleMove = (e: TouchEvent) => {e.preventDefault()}export default {beforeMount(el: HTMLElement, binding: any) {},mounted() {},beforeUpdate() {}, // 新updated(el: HTMLElement, binding: any) {// 更新的时候用这个if (binding.value) {/*** binding.value就是v-loading='true'传过来的那个值* 如果传过来的值为true 你们就是要展示loading* el是当前指令绑定的对象 binding是传过来的值*/// 在移动端页面禁用滚动document.body.addEventListener('touchmove', handleMove, {passive: false })// 判断当前页面是否存在没有消失的loading// hasLoading 值为false 时表明没有loading 可以添加loadingconst hasLoading = el.getElementsByClassName('xzw-loading').length !== 0if (hasLoading) return '日你温哦,有loading了还添加个锤子'// 判断是否传入了自定义提示文字const hasCustomText = el.getAttribute('xzw-loading-text')// 判断是否传入了自定义背景色const hasCustomBgColor = el.getAttribute('xzw-loading-background')el.style.position = 'relative'const mask = document.createElement('div') // 创建最外层div 高度占满(包含滚动)const loadingBox = document.createElement('div') // 显示loading的div 高度是100vhconst svg = document.createElementNS('/2000/svg', 'svg') // svg标签 用来实现旋转的圆const circle = document.createElementNS('/2000/svg', 'circle') // 旋转的那个圆const text = document.createElement('p') // 加载的文字// 下面所添加的class样式都会在后面贴出mask.setAttribute('class', 'xzw-loading')mask.style.background = !hasCustomBgColor ? 'rgba(255, 255, 255, .8)' : hasCustomBgColorloadingBox.setAttribute('class', 'xzw-loading-box')svg.setAttribute('class', 'xzw-loading_circular refleash')svg.setAttribute('viewBox', '25 25 50 50')circle.setAttribute('cx', '50')circle.setAttribute('cy', '50')circle.setAttribute('r', '20')circle.setAttribute('fill', 'none')text.innerText = !hasCustomText ? '加载中' : hasCustomTextsvg.appendChild(circle)loadingBox.appendChild(svg)loadingBox.appendChild(text)mask.appendChild(loadingBox)el.appendChild(mask)} else {/*** 传过来的值为false 不需要展示loading* 移除loading相关dom*/for (let i = 0; i < el.childNodes.length; i++) {if ((el.childNodes[i] as any).className === 'xzw-loading') {const childNodes = el.getElementsByClassName('xzw-loading')[0]el.removeChild(childNodes)break}}// 弹窗消失时移除'禁用滑动事件'document.body.removeEventListener('touchmove', handleMove)}},beforeUnmount() {}, // 新unmounted() {}}

样式代码(修改类名后可直接使用)

// 自定义loading相关样式.xzw-loading{width: 100%;height: 100%;position: absolute;left: 0;top: 0;z-index: 100;text-align: center;p{color: $primary-color;}.xzw-loading-box{width: 100%;height: 100vh;display: flex;flex-direction: column;align-items: center;justify-content: center;}}// 旋转整个svg容器.refleash{animation: RotateCricle 1s linear infinite;}// svg容器样式 以及 里面的circle的旋转.xzw-loading_circular {width: 40px;height: 40px;color: $primary-color;margin-bottom: 20px;circle{animation: xzw-circular 1.5s ease-in-out infinite;stroke: currentColor;stroke-width: 3;stroke-linecap: round;}}@keyframes RotateCricle{from {transform: rotate(0deg);}to {transform: rotate(360deg);}}@keyframes xzw-circular{0% {stroke-dasharray: 1, 200;stroke-dashoffset: 0;}50% {stroke-dasharray: 90, 150;stroke-dashoffset: -20;}100% {stroke-dasharray: 90, 150;stroke-dashoffset: -120;}}

main.ts里注册为全局指令

import loading from '@/directives/loading/index'app.directive('loading', loading)

在页面中使用(简单演示)

<div class='container' v-loading='loading' xzw-loading-text='别急嘛~'xzw-loading-background='rgba(0, 0, 0, .4)'></div><button @click='handleClickGetData '>Click To Get Data</button>

export default defineComponent({setup(props, ctx) {const loading = ref<boolean>(false)const handleClickGetData = async() => {// 开启loadingloading.value = trueconst res = await GetData({id})if (res.data.code === 200) {// 关闭loadingloading.value = false}}return{handleClickGetData ,loading}}})

实现起来其实也不复杂。如果对你有帮助的话 请点个赞再收藏一下吧~

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。