//从quasar处搬运 https://quasar.dev/vue-directives/material-ripple import './style.scss' let lastKeyCompositionStatus = false function isKeyCode(evt, keyCodes) { return ( lastKeyCompositionStatus === true || evt !== Object(evt) || evt.isComposing === true || evt.qKeyEvent === true ) ? false : [].concat(keyCodes).includes(evt.keyCode) } function css(element, css) { let style = element.style Object.keys(css).forEach(prop => { style[prop] = css[prop] }) } function position(e) { if (e.touches && e.touches[0]) { e = e.touches[0] } else if (e.changedTouches && e.changedTouches[0]) { e = e.changedTouches[0] } else if (e.targetTouches && e.targetTouches[0]) { e = e.targetTouches[0] } return { top: e.clientY, left: e.clientX } } function stop(e) { e.stopPropagation() } const listenOpts = { hasPassive: false, passiveCapture: true, notPassiveCapture: true } function showRipple(evt, el, ctx, forceCenter) { ctx.modifiers.stop === true && stop(evt) let {center, color} = ctx.modifiers center = center === true || forceCenter === true const node = document.createElement('span'), innerNode = document.createElement('span'), pos = position(evt), {left, top, width, height} = el.getBoundingClientRect(), diameter = Math.sqrt(width * width + height * height), radius = diameter / 2, centerX = `${(width - diameter) / 2}px`, x = center ? centerX : `${pos.left - left - radius}px`, centerY = `${(height - diameter) / 2}px`, y = center ? centerY : `${pos.top - top - radius}px` innerNode.className = 'q-ripple__inner' css(innerNode, { height: `${diameter}px`, width: `${diameter}px`, transform: `translate3d(${x},${y},0) scale3d(.2,.2,1)`, opacity: 0 }) node.className = `q-ripple${color ? ' text-' + color : ''}` node.setAttribute('dir', 'ltr') node.appendChild(innerNode) el.appendChild(node) const abort = () => { node.remove() window.clearTimeout(timer) } ctx.abort.push(abort) let timer = setTimeout(() => { innerNode.classList.add('q-ripple__inner--enter') innerNode.style.transform = `translate3d(${centerX},${centerY},0) scale3d(1,1,1)` innerNode.style.opacity = 0.2 timer = setTimeout(() => { innerNode.classList.remove('q-ripple__inner--enter') innerNode.classList.add('q-ripple__inner--leave') innerNode.style.opacity = 0 timer = setTimeout(() => { node.remove() ctx.abort.splice(ctx.abort.indexOf(abort), 1) }, 275) }, 250) }, 50) } function updateCtx(ctx, {value, modifiers, arg}) { ctx.enabled = value !== false if (ctx.enabled === true) { ctx.modifiers = Object(value) === value ? { stop: value.stop === true || modifiers.stop === true, center: value.center === true || modifiers.center === true, color: value.color || arg, keyCodes: [].concat(value.keyCodes || 13) } : { stop: modifiers.stop, center: modifiers.center, color: arg, keyCodes: [13] } } } export default { name: 'ripple', inserted(el, binding) { const ctx = { modifiers: {}, abort: [], click(evt) { if (ctx.enabled === true && evt.qSkipRipple !== true && evt.clientX >= 0) { showRipple(evt, el, ctx, evt.qKeyEvent === true) } }, keyup(evt) { if ( ctx.enabled === true && evt.qSkipRipple !== true && isKeyCode(evt, ctx.modifiers.keyCodes) === true ) { showRipple(evt, el, ctx, true) } } } updateCtx(ctx, binding) if (el.__qripple) { el.__qripple_old = el.__qripple } const computed = window.getComputedStyle(el) if (computed && computed.position === 'static') { el.style.position = 'relative' el.dataset.previousPosition = 'static' } el.__qripple = ctx el.addEventListener('click', ctx.click, listenOpts.passive) el.addEventListener('keyup', ctx.keyup, listenOpts.passive) }, update(el, binding) { el.__qripple !== void 0 && updateCtx(el.__qripple, binding) }, unbind(el) { const ctx = el.__qripple_old || el.__qripple if (ctx !== void 0) { ctx.abort.forEach(fn => { fn() }) el.removeEventListener('click', ctx.click, listenOpts.passive) el.removeEventListener('keyup', ctx.keyup, listenOpts.passive) delete el[el.__qripple_old ? '__qripple_old' : '__qripple'] } } }