阅读 165

Material Design 风格点击水波纹实现

先来看下效果:example,远古时期写的东西,随便找几个按钮点击即可看到效果。

代码地址:ripple

canvas绘制和css3绘制我都实现过,最终还是css效果、性能更佳。

思路

这个其实十分简单,首先分两部分去理解:

  1. css动画,水波纹的效果是 (透明度1+缩放至0) -> (透明度0+缩放至1),可以用@keyframes来实现。而波纹的大小交给js动态设置,再把效果写成指定的calss,最后js动态输出该节点即可;

  2. 先生成一个节点,然后设置波纹的大小,可以根据节点的宽高取一个最大值作为波纹的大小,这里波纹永远都是正方形的。然后再鼠标摁下的时候获取坐标位置,最后输入该节点即可。至于什么时候销毁该节点,可以利用node.addEventListener("animationend", fn)来监听处理。

css 部分

[ripple] {     position: relative;     overflow: hidden; } [ripple] .ripple {     position: absolute;     border-radius: 100%;     transform: scale(0);     pointer-events: none;     animation: ripple .4s ease-out; } @keyframes ripple {     to {         transform: scale(2);         opacity: 0;     } } 复制代码

js 部分

这里有个细节,就是水波纹效果结束之后被移除的节点我将他们放到一个数组里面,下次使用的时候直接从数组里面读取,之前做游戏的时候使用的一种节能模式,在网页上还没验证过,不知道有没有真正节省到性能的开销...没有的话直接删除该逻辑操作,可以尽可能的减少代码量。

/**  * 水波纹节点对象池  * @type {Array<HTMLElement>}  */ const ripplePool = []; /**  * 点击水波纹  * @param {TouchEvent | MouseEvent} event 点击事件  * @param {HTMLElement} target 点击目标  */ function ripple(event, target) {     /**      * 水波纹动画节点      * @type {HTMLElement}      */     let node = null;     // 从对象池里面拿取节点     if (ripplePool.length > 1) {         node = ripplePool.shift();     } else {         node = document.createElement("div");         node.className = "ripple";     }     /** 点击目标矩阵尺寸 */     const rect = target.getBoundingClientRect();     /** 当前自定义颜色值 */     const color = target.getAttribute("color");     /** 波纹大小 */     let size = Math.max(rect.width, rect.height);     // 设置最大范围     if (size > 200) size = 200;     // 设置大小     node.style.height = node.style.width = size + "px";     // 默认是白色透明     node.style.backgroundColor = color || "rgba(255, 255, 255, .45)";     // 这里必须输出节点后再设置位置,不然会有问题     target.appendChild(node);     const y = event.touches ? event.touches[0].clientY : event.clientY;     const x = event.touches ? event.touches[0].clientX : event.clientX;     const top = y - rect.top - (node.offsetHeight / 2);     const left = x - rect.left - (node.offsetWidth / 2);     // console.log(top, left);     node.style.top = top + "px";     node.style.left = left + "px";     function end() {         node.removeEventListener("animationend", end);         // console.log("动画结束", node);         target.removeChild(node);         ripplePool.push(node);     }     node.addEventListener("animationend", end); } 复制代码

使用方式

传统网页模式:

<button class="button" ripple>BUTTON-1</button> <button class="button" ripple color="rgba(0,0,0,0.1)">BUTTON-2 设置波纹颜色</button> 复制代码

使用事件代理去完成方法操作,因为节点有可能是动态生成的。

const mobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|OperaMini/i.test(navigator.userAgent); /** 添加事件类型 */ const eventType = mobile ? "touchstart" : "mousedown"; document.body.addEventListener(eventType, function (e) {     /** 事件类型 */     const event = e || window.event || arguments.callee.caller.arguments[0];     /** 循环的次数 */     let loopCount = 3; // 这里的 3 次是布局的子节点层数,可根据布局层数增加减少     /**       * 定义目标变量       * @type {HTMLElement}       */     let target = event.target;     // 循环 3 次由里向外查找目标节点     while (loopCount > 0 && target && target != document.body) {         loopCount--;         if (target.hasAttribute("ripple")) {             ripple(event, target);             break;         }         target = target.parentNode;     } }); 复制代码

vue 项目使用自定义指令模式使用

<button class="button" v-ripple>BUTTON-1</button> 复制代码

Vue.directive("ripple", {     inserted(el, binding) {         el.setAttribute("ripple", "");         el.addEventListener(eventType, function (e) {             ripple(e, el);         });     } })


作者:黄景圣
链接:https://juejin.cn/post/7047782205002612773


文章分类
人工智能
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐