1. 纯css实现波纹效果
    说明:使用伪元素:after定义波纹效果,一开始opacity为0,用户不可见,点击后进入active状态,opacity变为0.3,不缩放,transition: 0s。退出active状态后,自然重新显示:after中的样式,opacity变为0,放大10倍,由于transition设置1s,故有一个肉眼可见的变化过程。
    用户看到的效果:一个圆逐渐变大变淡,最后消失。
    缺点:使用css实现的,无法定位鼠标位置,每次波纹出现的位置都是固定的。

    <button class="btn ripple">Button</button>
    
    .btn {
      position: relative;
      margin: 0 auto;
      width: 200px;
      height: 50px;
      line-height: 50px;
      border-radius: 4px;
      box-shadow: 0 0 10px gray;
      background-color: #fff;
      overflow: hidden;
      cursor: pointer;
    }
    
    .ripple {
        position: relative;
        //隐藏溢出的径向渐变背景
        overflow: hidden;
    }
    
    .ripple:after {
        content: "";
        display: block;
        position: absolute;
        width: 100%;
        height: 100%;
        top: 0;
        left: 0;
        pointer-events: none;
        background-image: radial-gradient(circle, #666 10%, transparent 20%);
        background-repeat: no-repeat;
        background-position: 50%;
        transform: scale(10, 10);
        opacity: 0;
        transition: transform 1s, opacity 1s;
    }
    
    .ripple:active:after {
     //设置初始状态
        transform: scale(0, 0);
        opacity: .3;
        transition: 0s;
    }
    
  2. 使用js实现波纹效果
    说明:使用js可以获取鼠标(手指)位置,从而改变波纹位置,这里我使用vue封装了一个组件 = =
    监听的事件是touchstart和touchend(手指触摸屏幕)(手机),电脑端可以改为mousedown和mouseup(鼠标事件)

    <template>
      <div class="ripple--wapper" ref="rootElement">
        <div class="ripple--container" ref="rippleContainer" @touchstart="showRipple" @touchend="cleanRipple"></div>
        <slot />
      </div>
    </template>
    
    <script>
    export default {
      name:'ripple',
      data () {
        return {
          timer: 0
        }
      },
      props: {
        size: {
          type: Number,
          default: 100
        }
      },
      deactivated () {
        if(this.timer) {
          clearTimeout(this.timer)
        }
        while (this.$refs.rippleContainer.firstChild) {
          this.$refs.rippleContainer.removeChild(this.$refs.rippleContainer.firstChild)
        }
      },
      methods:{
        showRipple (e) {
          const target = this.$refs.rippleContainer
          const ripple = document.createElement('span')
          const size = this.size
          const pos = this.$refs.rippleContainer.getBoundingClientRect()
          const clientX = e.targetTouches[0].clientX
          const clientY = e.targetTouches[0].clientY
          const x = clientX - pos.left - size / 2
          const y = clientY - pos.top - size / 2
          const style = `top:${y/50}rem;left:${x/50}rem;width:${size/50}rem;height:${size/50}rem`
          ripple.setAttribute('style', style)
          const container = this.$refs.rippleContainer
          container.appendChild(ripple)
        },
        cleanRipple () {
          const _this = this
          if(this.timer) {
            clearTimeout(this.timer)
          }
          this.timer=setTimeout(() =>{
            //清除ripple
            if (_this.$refs.rippleContainer && _this.$refs.rippleContainer.firstChild) {
              _this.$refs.rippleContainer.removeChild(_this.$refs.rippleContainer.firstChild)
            }
          }, 1000)
        }
      }
    }
    </script>
    <style lang="less">
    @import "~assets/variable";
    .ripple--wapper {
      position: relative;
      overflow: hidden;
      //禁止文本选择
      -webkit-user-select: none;
      -moz-user-select: none;
      -webkit-user-select:none;
      -o-user-select:none;
      user-select:none;
      .ripple--container {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        span {
          position: absolute;
          transform: scale(0);
          border-radius: 100%;
          opacity: .3;
          background-color: #333;
          animation: ripple .2s;
        }
        @keyframes ripple {
          to {
            opacity: 0;
            transform: scale(2);
          }
        }
      }
    }
    </style>
    
10-03 17:38