From 9243370f1c0192652190a28ceba3c2c1ee7dbee5 Mon Sep 17 00:00:00 2001 From: aibayanyu Date: Sat, 18 Mar 2023 21:16:41 +0800 Subject: [PATCH] feat: add wave effect --- components/_util/wave/index.tsx | 2 +- components/_util/wave/wave-effect.tsx | 88 +++++++++++++++++++++++++-- site/demos/button/basic.vue | 1 + 3 files changed, 84 insertions(+), 7 deletions(-) diff --git a/components/_util/wave/index.tsx b/components/_util/wave/index.tsx index b18fb5f..c122f6b 100644 --- a/components/_util/wave/index.tsx +++ b/components/_util/wave/index.tsx @@ -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) => { diff --git a/components/_util/wave/wave-effect.tsx b/components/_util/wave/wave-effect.tsx index 7a08a7e..abef305 100644 --- a/components/_util/wave/wave-effect.tsx +++ b/components/_util/wave/wave-effect.tsx @@ -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() }, - setup() { - return () => null + setup(props, { attrs }) { + const divRef = shallowRef(undefined) + + const [color, setWaveColor] = useState(null) + const [borderRadius, setBorderRadius] = useState([]) + 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 = { + 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 ( +
+ ) + } } }) diff --git a/site/demos/button/basic.vue b/site/demos/button/basic.vue index bbfa221..67e9f3e 100644 --- a/site/demos/button/basic.vue +++ b/site/demos/button/basic.vue @@ -12,6 +12,7 @@ title: 基础按钮