let timer; // == 默认配置 const defaultOption = { opacity: 0.4, color: "auto", duration: 0.7, rate: function(pxPerSecond) { return pxPerSecond; }, easing: 'linear', finish: () => {} } // == 触发ripple效果 export const trigger = (e, option) => { option = Object.assign({}, defaultOption, option); let element = option.target || e.target; // 图片无子元素,选取父元素处理 if(e.target.tagName == 'IMG'){ element = e.target.parentElement; } element.classList.add('has-ripple'); element.insertAdjacentHTML("beforeend","") const ripple = element.querySelector('.ripple'); if (!ripple.offsetHeight && !ripple.offsetWidth) { var size = Math.max(element.offsetWidth, element.offsetHeight); ripple.style.width = size + 'px'; ripple.style.height = size + 'px'; } if(option.rate && typeof option.rate == "function") { var rate = Math.round( ripple.offsetWidth / option.duration ); var filteredRate = option.rate(rate); var newDuration = ( ripple.offsetWidth / filteredRate); if(option.duration.toFixed(2) !== newDuration.toFixed(2)) { option.duration = newDuration; } } var color = (option.color == "auto") ? element.style.color : option.color; ripple.style.animationDuration = (option.duration).toString() + 's'; ripple.style.animationTimingFunction = option.easing; ripple.style.background = color; ripple.style.opacity = option.opacity; ripple.classList.remove("ripple-animate"); var pageX,pageY; if (option.event === 'touchstart') { try { var origEvent; if (typeof e.changedTouches !== 'undefined') { origEvent = e.changedTouches[0]; } else { origEvent = e.originalEvent; } pageX = origEvent.pageX; pageY = origEvent.pageY; } catch (e) { pageX = ripple.offsetWidth / 2; pageY = ripple.offsetHeight / 2; } }else{ pageX = e.pageX; pageY = e.pageY; } var pos = getPos(element); var x = pageX - pos.left - ripple.offsetWidth / 2; var y = pageY - pos.top - ripple.offsetHeight / 2; ripple.style.top = y + 'px'; ripple.style.left = x + 'px'; ripple.classList.add('ripple-animate'); if(timer) clearTimeout(timer); timer = setTimeout(() => { element.removeChild(ripple); option.finish(e); },option.duration*800); } // == dom元素绑定ripper效果 export const bind = (selector,option) => { option = Object.assign({}, defaultOption, option); option.event = ('ontouchstart' in document) ? 'touchstart' : 'mousedown'; let triggerElems; if(typeof selector === 'string'){ triggerElems = document.querySelectorAll(selector); }else if('length' in selector){ triggerElems = selector; }else if(typeof selector === 'object'){ triggerElems = [selector]; } const triggerHandle = (e) => { trigger(e,option); }; for (let i = 0, n = triggerElems.length; i < n; i++) { let elem = triggerElems[i]; elem.addEventListener(option.event, triggerHandle); } // 销毁 function destroy() { for (let i = 0, n = triggerElems.length; i < n; i++) { let elem = triggerElems[i]; elem.removeEventListener(option.event, triggerHandle); } } return { destroy }; } function getPos(element) { var de = document.documentElement; var box = element.getBoundingClientRect(); var top = box.top + window.pageYOffset - de.clientTop; var left = box.left + window.pageXOffset - de.clientLeft; return { top: top, left: left }; }