mirror of
				https://github.com/antd-tiny-vue/antd-tiny-vue.git
				synced 2025-10-31 16:51:45 +08:00 
			
		
		
		
	feat: add wave effect
This commit is contained in:
		| @@ -20,7 +20,7 @@ const Wave = defineComponent({ | ||||
|     const [, hashId] = useStyle(prefixCls) | ||||
|     const showWave = useWave( | ||||
|       containerRef, | ||||
|       computed(() => classNames(prefixCls, hashId)) | ||||
|       computed(() => classNames(prefixCls.value, hashId.value)) | ||||
|     ) | ||||
|  | ||||
|     const onClick = (e: MouseEvent) => { | ||||
|   | ||||
| @@ -1,15 +1,91 @@ | ||||
| import type { ComputedRef, Ref } from 'vue' | ||||
| import { unrefElement } from '@vueuse/core' | ||||
| import { defineComponent, render } from 'vue' | ||||
| import { objectType } from '@v-c/utils' | ||||
|  | ||||
| import { unrefElement, useResizeObserver } from '@vueuse/core' | ||||
| import { computed, defineComponent, onMounted, render, shallowRef, toRef } from 'vue' | ||||
| import { classNames, delayTimer, objectType, safeNextick, useState } from '@v-c/utils' | ||||
| import { getTargetWaveColor } from './util' | ||||
| function validateNum(value: number) { | ||||
|   return Number.isNaN(value) ? 0 : value | ||||
| } | ||||
| export const WaveEffect = defineComponent({ | ||||
|   name: 'WaveEffect', | ||||
|   props: { | ||||
|     target: objectType<HTMLElement>() | ||||
|   }, | ||||
|   setup() { | ||||
|     return () => null | ||||
|   setup(props, { attrs }) { | ||||
|     const divRef = shallowRef<HTMLDivElement | undefined>(undefined) | ||||
|  | ||||
|     const [color, setWaveColor] = useState<string | null>(null) | ||||
|     const [borderRadius, setBorderRadius] = useState<number[]>([]) | ||||
|     const [left, setLeft] = useState(0) | ||||
|     const [top, setTop] = useState(0) | ||||
|     const [width, setWidth] = useState(0) | ||||
|     const [height, setHeight] = useState(0) | ||||
|     const [enabled, setEnabled] = useState(false) | ||||
|     const [active, setActive] = useState(false) | ||||
|     const waveStyle = computed(() => { | ||||
|       const style: Record<string, any> = { | ||||
|         left: `${left.value}px`, | ||||
|         top: `${top.value}px`, | ||||
|         width: `${width.value}px`, | ||||
|         height: `${height.value}px`, | ||||
|         borderRadius: borderRadius.value.map(radius => `${radius}px`).join(' ') | ||||
|       } | ||||
|       if (color.value) { | ||||
|         style['--wave-color'] = color.value | ||||
|       } | ||||
|       return style | ||||
|     }) | ||||
|     function syncPos() { | ||||
|       const { target } = props | ||||
|       const nodeStyle = getComputedStyle(target) | ||||
|  | ||||
|       // Get wave color from target | ||||
|       setWaveColor(getTargetWaveColor(target)) | ||||
|  | ||||
|       const isStatic = nodeStyle.position === 'static' | ||||
|  | ||||
|       // Rect | ||||
|       const { borderLeftWidth, borderTopWidth } = nodeStyle | ||||
|       setLeft(isStatic ? target.offsetLeft : validateNum(-parseFloat(borderLeftWidth))) | ||||
|       setTop(isStatic ? target.offsetTop : validateNum(-parseFloat(borderTopWidth))) | ||||
|       setWidth(target.offsetWidth) | ||||
|       setHeight(target.offsetHeight) | ||||
|  | ||||
|       // Get border radius | ||||
|       const { borderTopLeftRadius, borderTopRightRadius, borderBottomLeftRadius, borderBottomRightRadius } = nodeStyle | ||||
|  | ||||
|       setBorderRadius([borderTopLeftRadius, borderTopRightRadius, borderBottomRightRadius, borderBottomLeftRadius].map(radius => validateNum(parseFloat(radius)))) | ||||
|     } | ||||
|     onMounted(async () => { | ||||
|       syncPos() | ||||
|       setEnabled(true) | ||||
|       await safeNextick() | ||||
|       setActive(true) | ||||
|       await delayTimer(5000) | ||||
|       const holder = divRef.value?.parentElement | ||||
|       holder!.parentElement?.removeChild(holder!) | ||||
|     }) | ||||
|     const motionClassName = computed(() => | ||||
|       classNames({ | ||||
|         'wave-motion-appear': enabled.value, | ||||
|         'wave-motion': true | ||||
|       }) | ||||
|     ) | ||||
|     const motionClassNameActive = computed(() => ({ | ||||
|       'wave-motion-appear-active': active.value | ||||
|     })) | ||||
|     useResizeObserver(toRef(props, 'target'), syncPos) | ||||
|  | ||||
|     return () => { | ||||
|       if (!enabled.value) return null | ||||
|       return ( | ||||
|         <div | ||||
|           ref={divRef} | ||||
|           class={[attrs.class, motionClassName.value, motionClassNameActive.value]} | ||||
|           style={waveStyle.value} | ||||
|         /> | ||||
|       ) | ||||
|     } | ||||
|   } | ||||
| }) | ||||
|  | ||||
|   | ||||
| @@ -12,6 +12,7 @@ title: 基础按钮 | ||||
| <template> | ||||
|   <div> | ||||
|     <a-button>这是按钮</a-button> | ||||
|     <div style="height: 10px"></div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user