mirror of
				https://github.com/pure-admin/vue-pure-admin.git
				synced 2025-11-03 13:44:47 +08:00 
			
		
		
		
	feat: 新增v-ripple指令(水波纹效果) (#956)
* feat: 新增v-ripple指令(水波纹效果) * feat: 新增波纹demo
This commit is contained in:
		
							parent
							
								
									d83f28dbd3
								
							
						
					
					
						commit
						0f0fbdac51
					
				@ -90,6 +90,7 @@ menus:
 | 
				
			|||||||
  hsMenuTree: Menu Tree
 | 
					  hsMenuTree: Menu Tree
 | 
				
			||||||
  hsVideoFrame: Video Frame Capture
 | 
					  hsVideoFrame: Video Frame Capture
 | 
				
			||||||
  hsWavesurfer: Audio Visualization
 | 
					  hsWavesurfer: Audio Visualization
 | 
				
			||||||
 | 
					  hsRipple: Ripple
 | 
				
			||||||
  hsOptimize: Debounce、Throttle、Copy、Longpress Directives
 | 
					  hsOptimize: Debounce、Throttle、Copy、Longpress Directives
 | 
				
			||||||
  hsWatermark: Water Mark
 | 
					  hsWatermark: Water Mark
 | 
				
			||||||
  hsPrint: Print
 | 
					  hsPrint: Print
 | 
				
			||||||
 | 
				
			|||||||
@ -90,6 +90,7 @@ menus:
 | 
				
			|||||||
  hsMenuTree: 菜单树结构
 | 
					  hsMenuTree: 菜单树结构
 | 
				
			||||||
  hsVideoFrame: 视频帧截取-wasm版
 | 
					  hsVideoFrame: 视频帧截取-wasm版
 | 
				
			||||||
  hsWavesurfer: 音频可视化
 | 
					  hsWavesurfer: 音频可视化
 | 
				
			||||||
 | 
					  hsRipple: 波纹(Ripple)
 | 
				
			||||||
  hsOptimize: 防抖、截流、复制、长按指令
 | 
					  hsOptimize: 防抖、截流、复制、长按指令
 | 
				
			||||||
  hsWatermark: 水印
 | 
					  hsWatermark: 水印
 | 
				
			||||||
  hsPrint: 打印
 | 
					  hsPrint: 打印
 | 
				
			||||||
 | 
				
			|||||||
@ -2,3 +2,4 @@ export * from "./auth";
 | 
				
			|||||||
export * from "./copy";
 | 
					export * from "./copy";
 | 
				
			||||||
export * from "./longpress";
 | 
					export * from "./longpress";
 | 
				
			||||||
export * from "./optimize";
 | 
					export * from "./optimize";
 | 
				
			||||||
 | 
					export * from "./ripple";
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										48
									
								
								src/directives/ripple/index.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/directives/ripple/index.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					/* stylelint-disable-next-line scss/dollar-variable-colon-space-after */
 | 
				
			||||||
 | 
					$ripple-animation-transition-in:
 | 
				
			||||||
 | 
					  transform 0.4s cubic-bezier(0, 0, 0.2, 1),
 | 
				
			||||||
 | 
					  opacity 0.2s cubic-bezier(0, 0, 0.2, 1) !default;
 | 
				
			||||||
 | 
					$ripple-animation-transition-out: opacity 0.5s cubic-bezier(0, 0, 0.2, 1) !default;
 | 
				
			||||||
 | 
					$ripple-animation-visible-opacity: 0.25 !default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.v-ripple {
 | 
				
			||||||
 | 
					  &__container {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    z-index: 0;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					    pointer-events: none;
 | 
				
			||||||
 | 
					    border-radius: inherit;
 | 
				
			||||||
 | 
					    contain: strict;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &__animation {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					    pointer-events: none;
 | 
				
			||||||
 | 
					    background: currentcolor;
 | 
				
			||||||
 | 
					    border-radius: 50%;
 | 
				
			||||||
 | 
					    opacity: 0;
 | 
				
			||||||
 | 
					    will-change: transform, opacity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &--enter {
 | 
				
			||||||
 | 
					      opacity: 0;
 | 
				
			||||||
 | 
					      transition: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &--in {
 | 
				
			||||||
 | 
					      opacity: $ripple-animation-visible-opacity;
 | 
				
			||||||
 | 
					      transition: $ripple-animation-transition-in;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &--out {
 | 
				
			||||||
 | 
					      opacity: 0;
 | 
				
			||||||
 | 
					      transition: $ripple-animation-transition-out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										234
									
								
								src/directives/ripple/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								src/directives/ripple/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,234 @@
 | 
				
			|||||||
 | 
					import "./index.scss";
 | 
				
			||||||
 | 
					import { isObject } from "@pureadmin/utils";
 | 
				
			||||||
 | 
					import type { Directive, DirectiveBinding } from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface RippleOptions {
 | 
				
			||||||
 | 
					  class?: string;
 | 
				
			||||||
 | 
					  center?: boolean;
 | 
				
			||||||
 | 
					  circle?: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface RippleDirectiveBinding
 | 
				
			||||||
 | 
					  extends Omit<DirectiveBinding, "modifiers" | "value"> {
 | 
				
			||||||
 | 
					  value?: boolean | { class: string };
 | 
				
			||||||
 | 
					  modifiers: {
 | 
				
			||||||
 | 
					    center?: boolean;
 | 
				
			||||||
 | 
					    circle?: boolean;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function transform(el: HTMLElement, value: string) {
 | 
				
			||||||
 | 
					  el.style.transform = value;
 | 
				
			||||||
 | 
					  el.style.webkitTransform = value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const calculate = (
 | 
				
			||||||
 | 
					  e: PointerEvent,
 | 
				
			||||||
 | 
					  el: HTMLElement,
 | 
				
			||||||
 | 
					  value: RippleOptions = {}
 | 
				
			||||||
 | 
					) => {
 | 
				
			||||||
 | 
					  const offset = el.getBoundingClientRect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 获取点击位置距离 el 的垂直和水平距离
 | 
				
			||||||
 | 
					  let localX = e.clientX - offset.left;
 | 
				
			||||||
 | 
					  let localY = e.clientY - offset.top;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let radius = 0;
 | 
				
			||||||
 | 
					  let scale = 0.3;
 | 
				
			||||||
 | 
					  // 计算点击位置到 el 顶点最远距离,即为圆的最大半径(勾股定理)
 | 
				
			||||||
 | 
					  if (el._ripple?.circle) {
 | 
				
			||||||
 | 
					    scale = 0.15;
 | 
				
			||||||
 | 
					    radius = el.clientWidth / 2;
 | 
				
			||||||
 | 
					    radius = value.center
 | 
				
			||||||
 | 
					      ? radius
 | 
				
			||||||
 | 
					      : radius + Math.sqrt((localX - radius) ** 2 + (localY - radius) ** 2) / 4;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    radius = Math.sqrt(el.clientWidth ** 2 + el.clientHeight ** 2) / 2;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 中心点坐标
 | 
				
			||||||
 | 
					  const centerX = `${(el.clientWidth - radius * 2) / 2}px`;
 | 
				
			||||||
 | 
					  const centerY = `${(el.clientHeight - radius * 2) / 2}px`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 点击位置坐标
 | 
				
			||||||
 | 
					  const x = value.center ? centerX : `${localX - radius}px`;
 | 
				
			||||||
 | 
					  const y = value.center ? centerY : `${localY - radius}px`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return { radius, scale, x, y, centerX, centerY };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ripples = {
 | 
				
			||||||
 | 
					  show(e: PointerEvent, el: HTMLElement, value: RippleOptions = {}) {
 | 
				
			||||||
 | 
					    if (!el?._ripple?.enabled) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 创建 ripple 元素和 ripple 父元素
 | 
				
			||||||
 | 
					    const container = document.createElement("span");
 | 
				
			||||||
 | 
					    const animation = document.createElement("span");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    container.appendChild(animation);
 | 
				
			||||||
 | 
					    container.className = "v-ripple__container";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (value.class) {
 | 
				
			||||||
 | 
					      container.className += ` ${value.class}`;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { radius, scale, x, y, centerX, centerY } = calculate(e, el, value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ripple 圆大小
 | 
				
			||||||
 | 
					    const size = `${radius * 2}px`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    animation.className = "v-ripple__animation";
 | 
				
			||||||
 | 
					    animation.style.width = size;
 | 
				
			||||||
 | 
					    animation.style.height = size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    el.appendChild(container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 获取目标元素样式表
 | 
				
			||||||
 | 
					    const computed = window.getComputedStyle(el);
 | 
				
			||||||
 | 
					    // 防止 position 被覆盖导致 ripple 位置有问题
 | 
				
			||||||
 | 
					    if (computed && computed.position === "static") {
 | 
				
			||||||
 | 
					      el.style.position = "relative";
 | 
				
			||||||
 | 
					      el.dataset.previousPosition = "static";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    animation.classList.add("v-ripple__animation--enter");
 | 
				
			||||||
 | 
					    animation.classList.add("v-ripple__animation--visible");
 | 
				
			||||||
 | 
					    transform(
 | 
				
			||||||
 | 
					      animation,
 | 
				
			||||||
 | 
					      `translate(${x}, ${y}) scale3d(${scale},${scale},${scale})`
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    animation.dataset.activated = String(performance.now());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      animation.classList.remove("v-ripple__animation--enter");
 | 
				
			||||||
 | 
					      animation.classList.add("v-ripple__animation--in");
 | 
				
			||||||
 | 
					      transform(animation, `translate(${centerX}, ${centerY}) scale3d(1,1,1)`);
 | 
				
			||||||
 | 
					    }, 0);
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  hide(el: HTMLElement | null) {
 | 
				
			||||||
 | 
					    if (!el?._ripple?.enabled) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const ripples = el.getElementsByClassName("v-ripple__animation");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ripples.length === 0) return;
 | 
				
			||||||
 | 
					    const animation = ripples[ripples.length - 1] as HTMLElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (animation.dataset.isHiding) return;
 | 
				
			||||||
 | 
					    else animation.dataset.isHiding = "true";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const diff = performance.now() - Number(animation.dataset.activated);
 | 
				
			||||||
 | 
					    const delay = Math.max(250 - diff, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      animation.classList.remove("v-ripple__animation--in");
 | 
				
			||||||
 | 
					      animation.classList.add("v-ripple__animation--out");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      setTimeout(() => {
 | 
				
			||||||
 | 
					        const ripples = el.getElementsByClassName("v-ripple__animation");
 | 
				
			||||||
 | 
					        if (ripples.length === 1 && el.dataset.previousPosition) {
 | 
				
			||||||
 | 
					          el.style.position = el.dataset.previousPosition;
 | 
				
			||||||
 | 
					          delete el.dataset.previousPosition;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (animation.parentNode?.parentNode === el)
 | 
				
			||||||
 | 
					          el.removeChild(animation.parentNode);
 | 
				
			||||||
 | 
					      }, 300);
 | 
				
			||||||
 | 
					    }, delay);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function isRippleEnabled(value: any): value is true {
 | 
				
			||||||
 | 
					  return typeof value === "undefined" || !!value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function rippleShow(e: PointerEvent) {
 | 
				
			||||||
 | 
					  const value: RippleOptions = {};
 | 
				
			||||||
 | 
					  const element = e.currentTarget as HTMLElement | undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!element?._ripple || element._ripple.touched) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  value.center = element._ripple.centered;
 | 
				
			||||||
 | 
					  if (element._ripple.class) {
 | 
				
			||||||
 | 
					    value.class = element._ripple.class;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ripples.show(e, element, value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function rippleHide(e: Event) {
 | 
				
			||||||
 | 
					  const element = e.currentTarget as HTMLElement | null;
 | 
				
			||||||
 | 
					  if (!element?._ripple) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  window.setTimeout(() => {
 | 
				
			||||||
 | 
					    if (element._ripple) {
 | 
				
			||||||
 | 
					      element._ripple.touched = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  ripples.hide(element);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function updateRipple(
 | 
				
			||||||
 | 
					  el: HTMLElement,
 | 
				
			||||||
 | 
					  binding: RippleDirectiveBinding,
 | 
				
			||||||
 | 
					  wasEnabled: boolean
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					  const { value, modifiers } = binding;
 | 
				
			||||||
 | 
					  const enabled = isRippleEnabled(value);
 | 
				
			||||||
 | 
					  if (!enabled) {
 | 
				
			||||||
 | 
					    ripples.hide(el);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  el._ripple = el._ripple ?? {};
 | 
				
			||||||
 | 
					  el._ripple.enabled = enabled;
 | 
				
			||||||
 | 
					  el._ripple.centered = modifiers.center;
 | 
				
			||||||
 | 
					  el._ripple.circle = modifiers.circle;
 | 
				
			||||||
 | 
					  if (isObject(value) && value.class) {
 | 
				
			||||||
 | 
					    el._ripple.class = value.class;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (enabled && !wasEnabled) {
 | 
				
			||||||
 | 
					    el.addEventListener("pointerdown", rippleShow);
 | 
				
			||||||
 | 
					    el.addEventListener("pointerup", rippleHide);
 | 
				
			||||||
 | 
					  } else if (!enabled && wasEnabled) {
 | 
				
			||||||
 | 
					    removeListeners(el);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function removeListeners(el: HTMLElement) {
 | 
				
			||||||
 | 
					  el.removeEventListener("pointerdown", rippleShow);
 | 
				
			||||||
 | 
					  el.removeEventListener("pointerup", rippleHide);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function mounted(el: HTMLElement, binding: RippleDirectiveBinding) {
 | 
				
			||||||
 | 
					  updateRipple(el, binding, false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function unmounted(el: HTMLElement) {
 | 
				
			||||||
 | 
					  delete el._ripple;
 | 
				
			||||||
 | 
					  removeListeners(el);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function updated(el: HTMLElement, binding: RippleDirectiveBinding) {
 | 
				
			||||||
 | 
					  if (binding.value === binding.oldValue) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const wasEnabled = isRippleEnabled(binding.oldValue);
 | 
				
			||||||
 | 
					  updateRipple(el, binding, wasEnabled);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @description 指令 v-ripple
 | 
				
			||||||
 | 
					 * @use 用法如下
 | 
				
			||||||
 | 
					 * 1. v-ripple 代表启用基本的 ripple 功能
 | 
				
			||||||
 | 
					 * 2. v-ripple="{ class: 'text-red' }" 代表自定义 ripple 颜色,支持 tailwindcss,生效样式是 color
 | 
				
			||||||
 | 
					 * 3. v-ripple.center 代表从中心扩散
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const Ripple: Directive = {
 | 
				
			||||||
 | 
					  mounted,
 | 
				
			||||||
 | 
					  unmounted,
 | 
				
			||||||
 | 
					  updated
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -42,6 +42,15 @@ export default {
 | 
				
			|||||||
        title: $t("menus.hsExcel")
 | 
					        title: $t("menus.hsExcel")
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      path: "/components/ripple",
 | 
				
			||||||
 | 
					      name: "Ripple",
 | 
				
			||||||
 | 
					      component: () => import("@/views/able/ripple.vue"),
 | 
				
			||||||
 | 
					      meta: {
 | 
				
			||||||
 | 
					        title: $t("menus.hsRipple"),
 | 
				
			||||||
 | 
					        extraIcon: "IF-pure-iconfont-new svg"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      path: "/able/debounce",
 | 
					      path: "/able/debounce",
 | 
				
			||||||
      name: "Debounce",
 | 
					      name: "Debounce",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										71
									
								
								src/views/able/ripple.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/views/able/ripple.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					defineOptions({
 | 
				
			||||||
 | 
					  name: "Ripple"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <el-card shadow="never">
 | 
				
			||||||
 | 
					    <template #header>
 | 
				
			||||||
 | 
					      <div class="font-medium">波纹(Ripple)</div>
 | 
				
			||||||
 | 
					    </template>
 | 
				
			||||||
 | 
					    <div class="mb-5">组件中的波纹</div>
 | 
				
			||||||
 | 
					    <el-alert
 | 
				
			||||||
 | 
					      title="v-ripple在某些组件中使用波纹特效会异常,这是因为v-ripple指令只能作用于当前元素,某些组件有多层元素嵌套,且目标元素没在顶层,所以会导致特效异常"
 | 
				
			||||||
 | 
					      type="warning"
 | 
				
			||||||
 | 
					      :closable="false"
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					    <el-space wrap class="my-5">
 | 
				
			||||||
 | 
					      <el-button v-ripple>Default</el-button>
 | 
				
			||||||
 | 
					      <el-button v-ripple type="primary">Primary</el-button>
 | 
				
			||||||
 | 
					      <el-button v-ripple type="success">Success</el-button>
 | 
				
			||||||
 | 
					      <el-button v-ripple type="info">Info</el-button>
 | 
				
			||||||
 | 
					      <el-button v-ripple type="warning">Warning</el-button>
 | 
				
			||||||
 | 
					      <el-button v-ripple type="danger">Danger</el-button>
 | 
				
			||||||
 | 
					    </el-space>
 | 
				
			||||||
 | 
					    <el-card v-ripple class="mb-5 w-[510px] select-none" shadow="hover">
 | 
				
			||||||
 | 
					      卡片
 | 
				
			||||||
 | 
					    </el-card>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="mb-5">
 | 
				
			||||||
 | 
					      只要在组件或HTML元素上使用v-ripple指令,就可以启用基本的ripple功能
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					      v-ripple
 | 
				
			||||||
 | 
					      class="mb-5 text-center shadow-md rounded-md p-8 text-lg select-none"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      HTML元素
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <span
 | 
				
			||||||
 | 
					      v-ripple
 | 
				
			||||||
 | 
					      class="inline-block shadow-md rounded-md p-8 text-lg select-none"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      行内元素需要添加display: block或display: inline-block才能生效
 | 
				
			||||||
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="my-5">
 | 
				
			||||||
 | 
					      当使用v-ripple.center时,将始终从目标的中心处产生波纹
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					      v-ripple.center
 | 
				
			||||||
 | 
					      class="mb-5 text-center shadow-md rounded-md p-8 text-lg select-none"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      始终从中心触发波纹
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="mb-5">
 | 
				
			||||||
 | 
					      使用v-ripple="{ class: '' }"添加类来自定义波纹颜色,支持tailwindcss
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <el-alert
 | 
				
			||||||
 | 
					      title="自定义样式生效为文字颜色,例如:color: 'red';"
 | 
				
			||||||
 | 
					      type="warning"
 | 
				
			||||||
 | 
					      :closable="false"
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					      v-ripple="{ class: 'text-red-500' }"
 | 
				
			||||||
 | 
					      class="my-5 text-center shadow-md rounded-md p-4 text-lg select-none"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      自定义波纹颜色
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </el-card>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
							
								
								
									
										14
									
								
								types/global.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								types/global.d.ts
									
									
									
									
										vendored
									
									
								
							@ -180,4 +180,18 @@ declare global {
 | 
				
			|||||||
    $storage: ResponsiveStorage;
 | 
					    $storage: ResponsiveStorage;
 | 
				
			||||||
    $config: PlatformConfigs;
 | 
					    $config: PlatformConfigs;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 扩展 `Elemet`
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  interface Element {
 | 
				
			||||||
 | 
					    // v-ripple 作用于 src/directives/ripple/index.ts 文件
 | 
				
			||||||
 | 
					    _ripple?: {
 | 
				
			||||||
 | 
					      enabled?: boolean;
 | 
				
			||||||
 | 
					      centered?: boolean;
 | 
				
			||||||
 | 
					      class?: string;
 | 
				
			||||||
 | 
					      circle?: boolean;
 | 
				
			||||||
 | 
					      touched?: boolean;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user