1.src/components/common/player/variable.scss
// 颜色定义规范
$color-background: #F2F3F4;
$color-background-d: rgba(0, 0, 0, 0.3);
$color-highlight-background: rgb(253, 108, 98);
$color-dialog-background: rgb(204, 204, 204);
$color-theme: rgb(212, 68, 57);
$color-theme-l: rgba(185, 9, 1, 0.2);
$color-theme-g: rgb(219, 219, 219);
$color-theme-d: rgba(19, 19, 19, 0.6);
$color-sub-theme: rgb(240, 116, 107);
$color-text: #2E3030;
$color-text-g: #757575;
$color-text-ggg: #c7c7c7;
$color-text-gg: rgb(219, 219, 219);
$color-text-l: rgb(241, 241, 241);
$color-text-lm: rgb(228, 228, 228);
$color-text-ll: rgba(255, 255, 255, 0.8);
//字体定义规范
$font-size-small-ss: 9px;
$font-size-small-s: 10px;
$font-size-small: 11px;
$font-size-small-x: 12px;
$font-size-medium: 14px;
$font-size-medium-x: 16px;
$font-size-large-s: 17px;
$font-size-large: 18px;
$font-size-large-x: 22px;
2.src/components/common/player/dom.js
export function addClass (el, className) {
if (hasClass(el, className)) {
return
}
let newClass = el.className.split(' ')
newClass.push(className)
el.className = newClass.join(' ')
}
export function hasClass (el, className) {
let reg = new RegExp('(^|\\s)' + className + '(\\s|$)')
return reg.test(el.className)
}
export function getData (el, name, val) {
const prefix = 'data-'
name = prefix + name
if (val) {
// 如果有 val 就添加这个 val 到 dom 中
// name="val"
return el.setAttribute(name, val)
} else {
// 没有 val ,就获取 dom 中的 name
return el.getAttribute(name)
}
}
// 能力检测
let elementStyle = document.createElement('div').style
let vendor = (() => {
// 定义游览器前缀
let transformNames = {
webkit: 'webkitTransform',
Moz: 'MozTransform',
O: 'OTransform',
ms: 'msTransform',
standard: 'transform'
}
// 遍历前缀,如果游览器支持的话,就返回对应 key
for (let key in transformNames) {
if (elementStyle[transformNames[key]] !== undefined) {
return key
}
}
// 如果都不支持,那肯定是有问题的,返回 false
return false
})()
export function prefixStyle (style) {
if (vendor === false) {
return false
}
// 如果 vendor 为标准,就不改变 style
if (vendor === 'standard') {
return style
}
// 否则返回 vender(也就是 webkit Moz O ms 中的一个) + 样式首字母大写
// 例如:webkit + transform ---> webkitTransform
return vendor + style.charAt(0).toUpperCase() + style.substr(1)
}
3.components/common/progress-bar.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 class="inner-play-btn"></div>
</div>
</div>
</div>
</div>
</template>
<script>
import {prefixStyle} from './dom'
const progressBtnWidth = 15
const transform = prefixStyle('transform')
export default {
name: 'progressBar',
data () {
return {
newPercent: 0
}
},
props: {
percent: {
type: Number,
default: 0
}
},
created () {
this.touch = {}
},
methods: {
progressClick (e) {
// 这个有 bug
// this._offset(e.offsetX)
const rect = this.$refs.progressBar.getBoundingClientRect()
// rect.left 元素距离左边的距离
// e.pageX 点击距离左边的距离
const offsetWidth = e.pageX - rect.left
// console.log(rect, e.pageX)
this._offset(offsetWidth)
const barWidth = this.$refs.progressBar.clientWidth - progressBtnWidth
const percent = this.$refs.progress.clientWidth / barWidth
this.$emit('percentChangeEnd', percent)
},
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
}
this._triggerPercent()
const deltaX = e.touches[0].pageX - this.touch.startX
const offsetWidth = Math.min(Math.min(this.$refs.progressBar.clientWidth - progressBtnWidth, Math.max(0, this.touch.left + deltaX)))
this._offset(offsetWidth)
},
progressTouchEnd (e) {
this.touch.initiated = false
const barWidth = this.$refs.progressBar.clientWidth - progressBtnWidth
const percent = this.$refs.progress.clientWidth / barWidth
this.$emit('percentChangeEnd', percent)
},
_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) {
if (newPercent >= 0 && !this.touch.initiated) {
const barWidth = this.$refs.progressBar.clientWidth - progressBtnWidth
if(newPercent<=1){
const offsetWidth = newPercent * barWidth;
var u = navigator.userAgent;
if (u.indexOf("Android") > -1 || u.indexOf("Adr") > -1) {
this._offset(offsetWidth+5);
}else{
this._offset(offsetWidth);
}
}
}
}
}
}
</script>
<style scoped lang="scss">
@import "./variable";
.progress-bar {
height: 20px;
width: 100%;
.bar-inner {
position: relative;
top: 10px;
height: 3px;
background: rgba(0, 0, 0, 0.3);
width: 245px;
.progress {
position: absolute;
height: 100%;
background: $color-theme;
}
.progress-btn-wrapper {
position: absolute;
left: -8px;
top: -13px;
width: 30px;
height: 30px;
.progress-btn {
position: relative;
top: 7px;
left: 5px;
box-sizing: border-box;
width: 15px;
height: 15px;
border: 4px solid $color-theme-l;
border-radius: 50%;
.inner-play-btn{
position: absolute;
top: -1px;
left: -1px;
height: 9px;
width: 9px;
border-radius: 50%;
background: $color-theme;
}
}
}
}
}
</style>
4.use.vue
<style lang="scss" scoped>
.evening-broadcasting{
background: #f7f7f7;
padding: 10px 14px;
.broadcasting{
background: #fff;
padding: 11px 14px 18px 15.5px;
.broadcasting-top{
border-bottom: 1px solid #eee;
.play-box{
border-radius: 50%;
width: 42px;
height: 42px;
margin-top: 15px;
.play-button{
width: 42px;
height: 42px;
}
}
.play-content{
box-sizing: border-box;
padding-left: 19px;
width: 270px;
overflow: hidden;
.play-date{
font-size: 16px;
}
.play-title{
font-size: 12px;
color: #999999;
padding-top: 2px;
}
.play-control{
// width: 270px;
width: 100%;
#play-audio{
width: 100%;
}
.timingLength{
padding-top: 3px;
padding-bottom: 12px;
.time-l{
font-size: 11px;
color:#666;
}
.time-r{
font-size: 11px;
color:#999;
}
}
}
}
}
.broadcasting-bottom{
padding-top: 13px;
.broadcasting-bottom-title{
color: #383838;
font-size: 16px;
}
.broadcasting-bottom-image{
height: 20px;
width: 25px;
padding:0 5px 5px 5px;
}
.broadcasting-bottom-abs{
padding-top: 13px;
.broadcasting-bottom-abs-item{
font-size: 13px;
color: #666;
line-height: 1.4;
}
}
}
}
}
</style>
<template>
<div class="evening-broadcasting">
<div class="broadcasting">
<div class="broadcasting-top clearfix">
<div class="play-box left" @click="transPlayStatus">
<img src="../image/播放.png" class="play-button" @touchstart="play" v-if="!isPlay">
<img src="../image/暂停.png" class="play-button" @touchstart="pause" v-else>
</div>
<div class="play-content left">
<div class="play-date">
{{broadTitle}}
</div>
<div class="play-title">
晚间播报
</div>
<div class="play-control">
<audio id="audio" :src="audioUrl" ref="audio" @timeupdate="updateTime">该浏览器不支持audio属性</audio>
<progress-bar id="play-audio" :percent="percent" @percentChangeEnd="percentChangeEnd" @percentChange="percentChange"></progress-bar>
<div class="clearfix timingLength">
<span class="time time-l left" v-if="timeLoading">{{format(currentTime)}}</span>
<span class="time time-l left" v-else>-:--</span>
<span class="time time-r right" v-if="timeLoading">{{format(duration)}}</span>
<span class="time time-r right" v-else>-:--</span>
</div>
</div>
</div>
</div>
<div class="broadcasting-bottom">
<div class="clearfix">
<div class="left broadcasting-bottom-title">新闻概览</div>
<div class="right broadcasting-bottom-image" @click="onCopyAbsList" v-if="!isWeixin">
<img src="../image/矢量智能对象.png" alt="">
</div>
</div>
<div class="broadcasting-bottom-abs">
<div v-for="(item,index) in newSList" class="broadcasting-bottom-abs-item word-wrap">
{{item|formatPoint|formatAbstractNumber}}
</div>
</div>
</div>
</div>
</div>
</template>
<script>
//Vuex公共状态辅助函数
import { mapState } from 'vuex'
//Vuex公共状态动作
import {mapActions} from 'vuex'
import ProgressBar from './progressBar'
import wx from 'weixin-js-sdk'
//执行成功
const ERROR_CODE = "ERRORCODE0000";
export default {
name: 'player',
props:{
//晚间播报ID
fieldid:{
type:String,
},
//理财经理ID
userid:{
type:String,
},
//时间戳
todaytime:{
type:String
},
},
data() {
return {
playStatus:true,
audioUrl:'',
isPlay: false, // 是否播放
width: 0, // 视频音频的总时间的长度条
percent: 0,
currentTime: 0,// 播放时间
duration: 0,// 视频音频的总时长
playing: false,
timeLoading:true,
newSList:[],
waitingTime:700,
broadTitle:'',
//微信端显示
isWeixin:false,
};
},
components: {
ProgressBar,
},
computed:{
//Vuex辅助函数,将公共状态中的属性映射成当前的computed中
...mapState(['newBroadCast']),
},
watch: {
newBroadCast:{
deep:true,
handler:function(newV,oldV){
//时长
this.duration = this.newBroadCast.audioDuration;
this.broadTitle=this.newBroadCast.broadTitle;
if(this.duration>220){
this.waitingTime=2200;
}
else if(this.duration>200){
this.waitingTime=2000;
}
else if(this.duration>180){
this.waitingTime=1800;
}
else if(this.duration>120){
this.waitingTime=1200;
}
else if(this.duration>60){
this.waitingTime=1000;
}else{
this.waitingTime=700;
}
this.audioUrl= this.newBroadCast.audioUrl;
//摘要列表
var getNewSList=this.newBroadCast.broadAbstract.split('。').filter(item => item);
var getAbsList=[];
for (var i = 0; i < getNewSList.length; i++) {
if(getAbsList.join().length+getNewSList[i].length<200){
getAbsList.push(getNewSList[i]);
}
}
this.newSList=getAbsList;
}
},
currentTime () {
this.percent = this.currentTime / this.duration;
},
},
methods: {
//Vuex辅助函数,将公共状态中的方法映射成当前的this方法
...mapActions(['SET_NEWBROADCAST']),
//拷贝摘要
onCopyAbsList() {
var u = navigator.userAgent;
if (!!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)) {
var titleSummaryParame={
title:'新闻概览',
summary:this.newSList.join('。')
}
window.webkit.messageHandlers.executeTitleSummary.postMessage(titleSummaryParame);
app.executeTitleSummary('新闻概览',this.newSList.join('。'));
}
else if (u.indexOf("Android") > -1 || u.indexOf("Adr") > -1) {
Android.goNewsOverview('新闻概览',this.newSList.join('。'));
}
},
format (interval) {
interval = interval | 0
let minute = interval / 60 | 0
let second = interval % 60
if (second < 10) {
second = '0' + second
}
return minute + ':' + second
},
percentChange (percent) {
const currentTime = this.duration * percent
this.currentTime = currentTime
},
percentChangeEnd (percent) {
const currentTime = this.duration * percent
this.$refs.audio.currentTime = currentTime
if (!this.playing) {
this.$refs.audio.play()
this.playing=true;
this.isPlay=true;
}
},
updateTime (e) {
this.currentTime = e.target.currentTime;
if (this.audio.ended) {
this.isPlay = false
}
},
transPlayStatus(){
this.playStatus=!this.playStatus;
},
// 播放
play () {
if(this.currentTime==0){
var u = navigator.userAgent;
if (!!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)) {
this.audio.load();
this.timeLoading=false;
setTimeout(() => {
this.timeLoading=true;
}, this.waitingTime);
this.audio.play();
this.isPlay = true
}
else if (u.indexOf("Android") > -1 || u.indexOf("Adr") > -1) {
this.audio.load()
this.timeLoading=false;
this.isPlay = true
setTimeout(() => {
this.timeLoading=true;
this.audio.play();
}, this.waitingTime);
}
}else{
this.isPlay = true;
this.audio.currentTime = this.currentTime;//重新播放
this.audio.play();
}
},
// 暂停
pause () {
this.audio.pause()
this.isPlay = false
},
},
created(){
//判断微信环境
var ua = navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) == "micromessenger" && this.isWXApplet!=1) {
this.isWeixin=true;
}
let parame1 = {
"functionName": "newBroadCastService",
"methodName": "selectDetailById",
"data": {
"interfaceType":"1",
"id":this.fieldid
}
};
this.$post(JSON.stringify(parame1)).then(result => {
if (result.errorCode == ERROR_CODE && result.data.codeType == 200) {
console.log('晚间播报',result);
this.SET_NEWBROADCAST(result.data.newBroadCase[0]);
//时长
this.duration = result.data.newBroadCase[0].audioDuration;
this.broadTitle=result.data.newBroadCase[0].broadTitle;
if(this.duration>180){
this.waitingTime=1600;
}
if(this.duration>120){
this.waitingTime=1300;
}
else if(this.duration>60){
this.waitingTime=1000;
}else{
this.waitingTime=700;
}
this.audioUrl= result.data.newBroadCase[0].audioUrl;
//摘要列表
var getNewSList=result.data.newBroadCase[0].broadAbstract.split('。').filter(item => item);
var getAbsList=[];
for (var i = 0; i < getNewSList.length; i++) {
if(getAbsList.join().length+getNewSList[i].length<200){
getAbsList.push(getNewSList[i]);
}
}
this.newSList=getAbsList;
}
});
},
mounted(){
this.audio = this.$refs.audio;
this.audio.load();
},
}
</script>