vue 拖拽进度条滑动组件(二) 横向滑动插件

 progress.js

//是否有指定class存在
export function hasClass(el, className) {
    let reg = new RegExp('(^|\\s)' + className + '(\\s|$)')
    return reg.test(el.className)
  }
  //如果存在什么都不做,否则就设置添加
  export function addClass(el, className) {
    if (hasClass(el, className)) {
      return
    }
  
    let newClass = el.className.split(' ')
    newClass.push(className)
    el.className = newClass.join(' ')
  }
  
  export function getData(el, name, val) {
    const prefix = 'data-'
    if (val) {
      return el.setAttribute(prefix + name, val)
    }
    return el.getAttribute(prefix + name)
  }
  
  let elementStyle = document.createElement('div').style
  
  let vendor = (() => {
    let transformNames = {
      webkit: 'webkitTransform',
      Moz: 'MozTransform',
      O: 'OTransform',
      ms: 'msTransform',
      standard: 'transform'  //以上前缀都不满足,就用这个
    }
  
    for (let key in transformNames) {
      if (elementStyle[transformNames[key]] !== undefined) {
        return key
      }
    }
  
    return false
  })()
  
  export function prefixStyle(style) {
    if (vendor === false) {
      return false
    }
  
    if (vendor === 'standard') {
      return style
    }
  
    return vendor + style.charAt(0).toUpperCase() + style.substr(1)
  }
  

横向滑动子组件horizontalprogress.vue:

<template>
  <div class="progress-bar" ref="progressBar" @click="progressClick">
    <div class="bar-inner">
      <!-- 背景 -->
      <div class="progress" ref="progress"></div>
      <!-- 小圆点 -->
      <div class="progress-btn-wrapper" ref="progressBtn" @touchstart.prevent="progressTouchStart" @touchmove.prevent="progressTouchMove" @touchend.prevent="progressTouchEnd">
        <div class="progress-btn"></div>
      </div>
    </div>
  </div>
</template>

<script>
import { prefixStyle } from './progress'

const progressBtnWidth = 16
const transform = prefixStyle('transform')

export default {
  props: {
    percent: {
      type: Number,
      default: 0
    }
  },
  created() {
    this.touch = {}  //创建一个touch对象
  },
  methods: {
    progressTouchStart(e) {
      //创建一个标志,意思它已经初始化完
      this.touch.initiated = true
      //手指的位置
      this.touch.startX = e.touches[0].pageX
      //当前滚动,滚动条的位置
      this.touch.left = this.$refs.progress.clientWidth
    },
    progressTouchMove(e) {
      //如果初始化完则什么都不做
      if (!this.touch.initiated) {
        return
      }
      const deltaX = e.touches[0].pageX - this.touch.startX //计算差值 
      //max 的0  意思不能小于0 、、、、min,不能超过整个滚动条的宽度
      const offsetWidth = Math.min(this.$refs.progressBar.clientWidth - progressBtnWidth, Math.max(0, this.touch.left + deltaX))
      this._offset(offsetWidth)
    },
    progressTouchEnd() {
      this.touch.initiated = false
      //滚动完后要给父组件派发一个事件
      this._triggerPercent()
    },
    //点击改变歌曲播放进度
    progressClick(e) {
      const rect = this.$refs.progressBar.getBoundingClientRect() //是一个获取距离的方法
      const offsetWidth = e.pageX - rect.left
      this._offset(offsetWidth)
      // 这里当我们点击 progressBtn 的时候,e.offsetX 获取不对
      this._triggerPercent()
    },
    _triggerPercent() {
      const barWidth = this.$refs.progressBar.clientWidth - progressBtnWidth
      const percent = this.$refs.progress.clientWidth / barWidth
      this.$emit('percentChange', percent)
    },
    //偏移方法
    _offset(offsetWidth) {
      this.$refs.progress.style.width = `${offsetWidth}px`  //获取进度条的位置,距离左右的距离
      this.$refs.progressBtn.style[transform] = `translate3d(${offsetWidth}px,0,0)`  //小球的偏移
    }
  },
  watch: {
    //它是不断改变的
    percent(newPercent) {
      //大于0 而且不是在拖动的状态下,拖动的时候不要改变
      if (newPercent >= 0 && !this.touch.initiated) {
        const barWidth = this.$refs.progressBar.clientWidth - progressBtnWidth  //进度条的总宽度 内容-按钮的宽度
        const offsetWidth = newPercent * barWidth //应该偏移的宽度
        this._offset(offsetWidth)
      }
    }
  }
}
</script>

<style scoped lang="less">
.progress-bar {
  height: 30px;
  .bar-inner {
    position: relative;
    top: 13px;
    height: 10px;
    background: rgba(0, 0, 0, 0.3);
    .progress {
      position: absolute;
      height: 100%;
      background: #ffcd32;
    }
    .progress-btn-wrapper {
      position: absolute;
      left: -8px;
      top: -10px;
      width: 30px;
      height: 30px;
      .progress-btn {
        position: relative;
        top: 7px;
        left: 7px;
        box-sizing: border-box;
        width: 16px;
        height: 16px;
        border: 3px solid #333;
        border-radius: 50%;
        background: #ffcd32;
      }
    }
  }
}
</style>

 父级调用子组件代码:

<template>
  <div>
    <div class="my-progress">
      <my-progress @percentChange="percentChange" :percent="currentRate"></my-progress>
      <div class="btn">
        <div id="startV" @click="playVideo()">{
   
   {isStart?'暂停播放':'开始播放'}}</div>
        <div id="endV" @click="endVideo()">结束播放</div>
      </div>
      <audio :src="bgm" controls="controls" ref="myAudio" style="display:none;" @timeupdate="updateTime"> </audio>

    </div>
  </div>
</template>

<script>
import MyProgress from "../components/progress/horizontalprogress";

export default {
  data() {
    return {
      isStart: false,
      currentRate: 0,
      currentTime: 0,
      durationTime: 0, //总时长
      bgm: 'http://img11.dangdang.com/default/newimages/danpinye/zhejiushiai11.mp3'
      
    };
  },

  components: {
    MyProgress
  },
  destroyed() {
    this.$nextTick(() => {
      this.$refs.myAudio.pause();
    })
  },

  mounted() {
    var audio = this.$refs.myAudio;
    // 获取总时长
    audio.addEventListener("canplay", () => {
      this.durationTime = this.$refs.myAudio.duration;
    });
  },
  watch: {
    currentTime(val) {
      this.currentRate = this.currentTime / this.durationTime;
    }
  },

  methods: {
    percentChange(val) {
      var audio = this.$refs.myAudio;
      audio.currentTime = val * this.durationTime;
      this.isStart = true;
      audio.play();
    },
    updateTime(e) {
      this.currentTime = e.target.currentTime;
      this.currentRate = this.currentTime / this.$refs.myAudio.duration;
    },
    // 开始/暂停播放
    playVideo() {
      this.currentTime = this.$refs.myAudio.currentTime;
      var audio = this.$refs.myAudio;
      if (audio.paused) {
        audio.play();
        this.isStart = true;
      } else {
        audio.pause();
        this.isStart = false;
      }
    },
    // 结束播放
    endVideo() {
      this.isStart = false;
      this.currentTime = 0;
      this.currentRate = 0;
      this.$refs.myAudio.pause();
      this.$refs.myAudio.currentTime = 0;
    }
  },

  computed: {}
}

</script>
<style lang='less' scoped>
.fl {
  float: left;
}
.fr {
  float: right;
}
.my-progress {
  height: 600px;
  margin: 3%;
  padding: 3%;
  box-sizing: border-box;
  .btn {
    width: 100%;
    overflow: hidden;
    text-align: center;
    margin: 8% auto 0;
    div {
      width: 45%;
      display: inline-block;
      text-align: center;
      background: rgb(166, 228, 161);
      color: #ffffff;
      border-radius: 4px;
      padding: 5px 0;
    }
    div:first-child {
      margin-right: 10px;
    }
  }
}
</style>

猜你喜欢

转载自blog.csdn.net/yuan_jlj/article/details/111523464