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>