mirror of
				https://github.com/antd-tiny-vue/antd-tiny-vue.git
				synced 2025-11-01 01:01:44 +08:00 
			
		
		
		
	feat: add wave effect
This commit is contained in:
		| @@ -20,7 +20,7 @@ const Wave = defineComponent({ | |||||||
|     const [, hashId] = useStyle(prefixCls) |     const [, hashId] = useStyle(prefixCls) | ||||||
|     const showWave = useWave( |     const showWave = useWave( | ||||||
|       containerRef, |       containerRef, | ||||||
|       computed(() => classNames(prefixCls, hashId)) |       computed(() => classNames(prefixCls.value, hashId.value)) | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     const onClick = (e: MouseEvent) => { |     const onClick = (e: MouseEvent) => { | ||||||
|   | |||||||
| @@ -1,15 +1,91 @@ | |||||||
| import type { ComputedRef, Ref } from 'vue' | import type { ComputedRef, Ref } from 'vue' | ||||||
| import { unrefElement } from '@vueuse/core' | import { unrefElement, useResizeObserver } from '@vueuse/core' | ||||||
| import { defineComponent, render } from 'vue' | import { computed, defineComponent, onMounted, render, shallowRef, toRef } from 'vue' | ||||||
| import { objectType } from '@v-c/utils' | 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({ | export const WaveEffect = defineComponent({ | ||||||
|   name: 'WaveEffect', |   name: 'WaveEffect', | ||||||
|   props: { |   props: { | ||||||
|     target: objectType<HTMLElement>() |     target: objectType<HTMLElement>() | ||||||
|   }, |   }, | ||||||
|   setup() { |   setup(props, { attrs }) { | ||||||
|     return () => null |     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> | <template> | ||||||
|   <div> |   <div> | ||||||
|     <a-button>这是按钮</a-button> |     <a-button>这是按钮</a-button> | ||||||
|  |     <div style="height: 10px"></div> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user