perf: 优化音频播放器

This commit is contained in:
jmal 2023-04-30 23:48:24 +08:00
parent 3b4a3236a3
commit 19e2fdbbb2
5 changed files with 96 additions and 123 deletions

View File

@ -15,7 +15,6 @@
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml" "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
}, },
"dependencies": { "dependencies": {
"@moefe/vue-aplayer": "^2.0.0-beta.5",
"ant-design-vue": "^1.6.5", "ant-design-vue": "^1.6.5",
"artplayer": "^4.5.4", "artplayer": "^4.5.4",
"clipboard": "^2.0.6", "clipboard": "^2.0.6",
@ -23,6 +22,7 @@
"e-vue-contextmenu": "^0.1.3", "e-vue-contextmenu": "^0.1.3",
"gsap": "^3.2.6", "gsap": "^3.2.6",
"highlightjs-line-numbers.js": "^2.7.0", "highlightjs-line-numbers.js": "^2.7.0",
"hls.js": "^1.4.0",
"htmlhint": "^0.13.0", "htmlhint": "^0.13.0",
"jquery": "^3.5.0", "jquery": "^3.5.0",
"jquery-contextmenu": "^2.9.1", "jquery-contextmenu": "^2.9.1",

View File

@ -1,22 +1,25 @@
<template> <template>
<div ref="audioPreview" v-if="show"> <div ref="asdfasdf">
<div class="audio-player" <div ref="audioPreview" v-if="show">
v-aplayerDrag="{ x: transformX, y: transformY }" <div class="audio-player"
@mouseenter="closeBarShow = true" @mouseleave="closeBarShow = false" @touchmove="closeBarShow = true" v-aplayerDrag="{ x: transformX, y: transformY }"
@touchend="touchend"> @mouseenter="closeBarShow = true" @mouseleave="closeBarShow = false" @touchmove="closeBarShow = true"
<a-player @touchend="touchend">
ref="audioPlayer" <vue-a-player
autoplay ref="audioPlayer"
listFolded listFolded
loop.sync="all" controls
order.sync="list" preload="auto"
:mini.sync="mini" :repeat="repeat"
:audio="list" :shuffle="shuffle"
:lrc-type="0" :music="currentMusic"
> :mini.sync="mini"
</a-player> :list="list"
<div v-show="closeBarShow" class="close-bar" @click="close"> >
<svg-icon class="audio-player-close" icon-class="close"/> </vue-a-player>
<div v-show="closeBarShow" class="close-bar" @click="close">
<svg-icon class="audio-player-close" icon-class="close"/>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -25,11 +28,13 @@
<script> <script>
import '@/utils/directives.js' import '@/utils/directives.js'
import Bus from '@/assets/js/bus' import Bus from '@/assets/js/bus'
import VueAPlayer from 'vue-aplayer'
VueAPlayer.disableVersionBadge = true
import fileConfig from '@/utils/file-config' import fileConfig from '@/utils/file-config'
export default { export default {
name: 'AudioPreview', name: 'AudioPreview',
components: {}, components: {VueAPlayer},
props: {}, props: {},
computed: {}, computed: {},
data() { data() {
@ -39,20 +44,11 @@ export default {
transformY: !this.$pc ? document.body.clientHeight / 2 - 100 : 0, transformY: !this.$pc ? document.body.clientHeight / 2 - 100 : 0,
show: false, show: false,
closeBarShow: false, closeBarShow: false,
// api ==> https://aplayer.netlify.app/docs/guide/options.html#volume currentMusic: {},
audios: [],
list: [], list: [],
mini: !this.$pc, mini: !this.$pc,
audioPlayerDoc: undefined repeat: 'no-repeat',
} shuffle: false
},
watch: {
show(val) {
if (val && !this.audioPlayerDoc) {
this.$nextTick(() => {
this.audioPlayerDoc = document.querySelector('.audio-player')
})
}
} }
}, },
mounted() { mounted() {
@ -60,46 +56,35 @@ export default {
if (!this.show) { if (!this.show) {
this.show = true this.show = true
} }
let url = fileConfig.previewUrl(this.$store.state.user.name, newFile, this.$store.getters.token) this.$nextTick(() => {
if (this.$store.getters.token === undefined) { console.log('this.$refs', this.$refs)
url = fileConfig.publicPreviewUrl(newFile.id, window.shareId, this.$store.getters.shareToken); let url = fileConfig.previewUrl(this.$store.state.user.name, newFile, this.$store.getters.token)
} if (this.$store.getters.token === undefined) {
let music = newFile.music url = fileConfig.publicPreviewUrl(newFile.id, window.shareId, this.$store.getters.shareToken);
let fileName = newFile.name.substring(0, newFile.name.length - newFile.suffix.length - 1)
let musicOperation = {
id: newFile.id,
url: url,
name: music ? music.songName || fileName : fileName,
artist: music ? music.singer || fileName : fileName,
cover: music ? audioCoverUrl + newFile.id : '',
type: newFile.contentType
}
let musicIndex = this.audios.findIndex(item => item.id === newFile.id)
if (musicIndex < 0) {
if (this.audios.length === 1) {
let loop = document.querySelector('.aplayer-icon.aplayer-icon-loop');
loop.style.display = 'inline'
let order = document.querySelector('.aplayer-icon.aplayer-icon-order');
order.style.display = 'inline'
} }
this.audios.push(musicOperation) let music = newFile.music
setTimeout(() => { let fileName = newFile.name.substring(0, newFile.name.length - newFile.suffix.length - 1)
this.list = this.audios this.currentMusic = {
setTimeout(() => { id: newFile.id,
this.$refs.audioPlayer.switch(this.audios.length - 1) src: url,
}, 0) title: music ? music.songName || fileName : fileName,
}, 0) artist: music ? music.singer || fileName : fileName,
} else { pic: music ? audioCoverUrl + newFile.id : '',
this.$refs.audioPlayer.switch(musicIndex) theme: 'pic'
} }
let musicIndex = this.list.findIndex(item => item.id === newFile.id)
if (musicIndex < 0) {
this.list.push(this.currentMusic)
}
this.$refs.audioPlayer.thenPlay()
console.log(this.$refs.audioPlayer.repeat, this.$refs.audioPlayer.shuffle);
})
}) })
}, },
methods: { methods: {
close() { close() {
this.show = false this.show = false
this.audioPlayerDoc = undefined
this.$refs.audioPlayer.pause() this.$refs.audioPlayer.pause()
this.audios.splice(0, this.audios.length)
}, },
touchend() { touchend() {
const that = this const that = this

View File

@ -16,7 +16,6 @@
<script> <script>
import fileConfig from '@/utils/file-config' import fileConfig from '@/utils/file-config'
import Artplayer from "@/components/preview/Artplayer.vue"; import Artplayer from "@/components/preview/Artplayer.vue";
export default { export default {
name: 'VideoPreview', name: 'VideoPreview',
components: { components: {
@ -72,6 +71,7 @@ export default {
{ {
name: 'nplayer', name: 'nplayer',
position: 'right', position: 'right',
tooltip: 'nPlayer',
style: { style: {
marginRight: '20px', marginRight: '20px',
}, },
@ -81,6 +81,7 @@ export default {
{ {
name: 'infuse', name: 'infuse',
position: 'right', position: 'right',
tooltip: 'Infuse',
style: { style: {
marginRight: '20px', marginRight: '20px',
}, },

View File

@ -41,12 +41,6 @@ Vue.use(vant.ImagePreview)
import Minder from '@/components/Minder' import Minder from '@/components/Minder'
Vue.use(Minder) Vue.use(Minder)
import APlayer from '@moefe/vue-aplayer';
Vue.use(APlayer, {
defaultCover: 'https://images.unsplash.com/photo-1511671782779-c97d3d27a1d4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=60',
productionTip: false, // 是否在控制台输出版本信息
});
new Vue({ new Vue({
el: '#app', el: '#app',
router, router,

View File

@ -1,10 +1,9 @@
// import Vue from 'vue' // import Vue from 'vue'
// v-draw-rectangle 画矩形选区 // v-draw-rectangle 画矩形选区
Vue.directive('drawRectangle',{ Vue.directive('drawRectangle', {
bind(el,binding,vnode,oldVnode){ bind(el, binding, vnode, oldVnode) {
let $$ = function(id){ let $$ = function (id) {
return document.getElementById(id) return document.getElementById(id)
} }
let draw = el let draw = el
@ -12,7 +11,7 @@ Vue.directive('drawRectangle',{
let startX = 0, startY = 0 let startX = 0, startY = 0
let flag = false let flag = false
let retcLeft = 0, retcTop = 0, retcHeight = 0, retcWidth = 0 let retcLeft = 0, retcTop = 0, retcHeight = 0, retcWidth = 0
draw.onmousedown = function(e){ draw.onmousedown = function (e) {
flag = true flag = true
let evt = window.event || e let evt = window.event || e
let scrollTop = draw.scrollTop || draw.scrollTop let scrollTop = draw.scrollTop || draw.scrollTop
@ -33,8 +32,8 @@ Vue.directive('drawRectangle',{
div.style.overflow = 'hidden' div.style.overflow = 'hidden'
draw.appendChild(div) draw.appendChild(div)
document.onmousemove = function(e){ document.onmousemove = function (e) {
if(flag){ if (flag) {
let evt = window.event || e let evt = window.event || e
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop let scrollTop = document.body.scrollTop || document.documentElement.scrollTop
let scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft let scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft
@ -52,11 +51,11 @@ Vue.directive('drawRectangle',{
} }
document.onmouseup = function(e){ document.onmouseup = function (e) {
flag = false flag = false
if($$(wId)){ if ($$(wId)) {
draw.removeChild($$(wId)) draw.removeChild($$(wId))
if(retcWidth > 1 && retcHeight > 1){ if (retcWidth > 1 && retcHeight > 1) {
} }
} }
return false return false
@ -70,28 +69,25 @@ Vue.directive('aplayerDrag', {
// 获取拖拽内容头部 // 获取拖拽内容头部
const dialogHeaderEl = el.querySelector('.aplayer-music'); const dialogHeaderEl = el.querySelector('.aplayer-music');
const dragDom = el; const dragDom = el;
dragDom.style.transform="translate("+binding.value.x+"px,"+binding.value.y+"px)"; // dragDom.style.transform = "translate(" + binding.value.x + "px," + binding.value.y + "px)";
dragDom.style.left = binding.value.x + "px"
dragDom.style.top = binding.value.y + "px"
dialogHeaderEl.style.cursor = 'move'; dialogHeaderEl.style.cursor = 'move';
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null); // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null); const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null);
// 鼠标按下事件 // 鼠标按下事件
dragDom.addEventListener('touchstart', touchstart, false); dragDom.addEventListener('touchstart', touchstart, false);
dragDom.addEventListener('touchmove', touchmove, false); dragDom.addEventListener('touchmove', touchmove, false);
let disX,disY,styL,styT; let disX, disY, styL, styT;
function touchstart(e) { function touchstart(e) {
// 鼠标按下,计算当前元素距离可视区的距离 (鼠标点击位置距离可视窗口的距离) // 鼠标按下,计算当前元素距离可视区的距离 (鼠标点击位置距离可视窗口的距离)
disX = e.touches[0].clientX - dialogHeaderEl.offsetLeft; disX = e.touches[0].clientX - dialogHeaderEl.offsetLeft;
disY = e.touches[0].clientY - dialogHeaderEl.offsetTop; disY = e.touches[0].clientY - dialogHeaderEl.offsetTop;
// 获取到的值带px 正则匹配替换 styL = binding.value.x
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px styT = binding.value.y
if (sty.left.includes('%')) {
styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100) + binding.value.x;
styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100) + binding.value.y;
} else {
styL = +sty.left.replace(/\px/g, '') + binding.value.x;
styT = +sty.top.replace(/\px/g, '') + binding.value.y;
}
} }
// 鼠标拖拽事件 // 鼠标拖拽事件
function touchmove(e) { function touchmove(e) {
e.preventDefault() e.preventDefault()
@ -106,32 +102,25 @@ Vue.directive('aplayerDrag', {
} else if (finallyL > document.body.clientWidth - dragDom.clientWidth) {///右边 } else if (finallyL > document.body.clientWidth - dragDom.clientWidth) {///右边
finallyL = document.body.clientWidth - dragDom.clientWidth finallyL = document.body.clientWidth - dragDom.clientWidth
} }
if (finallyT < 0) {////顶部 if (finallyT < 0) {////顶部
finallyT = 0 finallyT = 0
} else if (finallyT > document.body.clientHeight - dragDom.clientHeight) (///底部 } else if (finallyT > document.body.clientHeight - dragDom.clientHeight) (///底部
finallyT = document.body.clientHeight - dragDom.clientHeight finallyT = document.body.clientHeight - dragDom.clientHeight
) )
dragDom.style.transform = "translate(" + finallyL + "px," + finallyT + "px)"; dragDom.style.left = finallyL + "px"
dragDom.style.top = finallyT + "px"
//将此时的位置传出去 //将此时的位置传出去
binding.value.x = finallyL; binding.value.x = finallyL;
binding.value.y = finallyT; binding.value.y = finallyT;
} }
// 鼠标按下事件 // 鼠标按下事件
dialogHeaderEl.onmousedown = (e) => { dialogHeaderEl.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离 (鼠标点击位置距离可视窗口的距离) // 鼠标按下,计算当前元素距离可视区的距离 (鼠标点击位置距离可视窗口的距离)
const disX = e.clientX - dialogHeaderEl.offsetLeft + 81; const disX = e.clientX - dialogHeaderEl.offsetLeft + 81;
const disY = e.clientY - dialogHeaderEl.offsetTop + 14; const disY = e.clientY - dialogHeaderEl.offsetTop + 14;
// 获取到的值带px 正则匹配替换 styL = binding.value.x
let styL, styT; styT = binding.value.y
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (sty.left.includes('%')) {
styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100)+binding.value.x;
styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100)+binding.value.y;
} else {
styL = +sty.left.replace(/\px/g, '')+binding.value.x;
styT = +sty.top.replace(/\px/g, '')+binding.value.y;
};
// 鼠标拖拽事件 // 鼠标拖拽事件
document.onmousemove = function (e) { document.onmousemove = function (e) {
// 通过事件委托,计算移动的距离 (开始拖拽至结束拖拽的距离) // 通过事件委托,计算移动的距离 (开始拖拽至结束拖拽的距离)
@ -151,10 +140,11 @@ Vue.directive('aplayerDrag', {
} else if (finallyT > document.body.clientHeight - dragDom.clientHeight) (///底部 } else if (finallyT > document.body.clientHeight - dragDom.clientHeight) (///底部
finallyT = document.body.clientHeight - dragDom.clientHeight finallyT = document.body.clientHeight - dragDom.clientHeight
) )
dragDom.style.transform="translate("+finallyL+"px,"+finallyT+"px)"; dragDom.style.left = finallyL + "px"
dragDom.style.top = finallyT + "px"
//将此时的位置传出去 //将此时的位置传出去
binding.value.x=finallyL; binding.value.x = finallyL;
binding.value.y=finallyT; binding.value.y = finallyT;
}; };
document.onmouseup = function (e) { document.onmouseup = function (e) {
document.onmousemove = null; document.onmousemove = null;
@ -175,9 +165,9 @@ Vue.directive('dialogDrag', {
const dialogHeaderEl = el.querySelector('.el-dialog__header'); const dialogHeaderEl = el.querySelector('.el-dialog__header');
const dragDom = el.querySelector('.el-dialog'); const dragDom = el.querySelector('.el-dialog');
let dialogWidth = document.body.clientWidth * binding.value.dialogWidthPercent let dialogWidth = document.body.clientWidth * binding.value.dialogWidthPercent
let x = (document.body.clientWidth - dialogWidth)/2 let x = (document.body.clientWidth - dialogWidth) / 2
let y = (document.body.clientHeight - document.body.clientHeight * binding.value.dialogWidthPercent)/2 let y = (document.body.clientHeight - document.body.clientHeight * binding.value.dialogWidthPercent) / 2
dragDom.style.transform="translate("+x+"px,"+y+"px)"; dragDom.style.transform = "translate(" + x + "px," + y + "px)";
//dialogHeaderEl.style.cursor = 'move'; //dialogHeaderEl.style.cursor = 'move';
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null); // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null); const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null);
@ -190,16 +180,17 @@ Vue.directive('dialogDrag', {
let styL, styT; let styL, styT;
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (sty.left.includes('%')) { if (sty.left.includes('%')) {
styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100)+x; styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100) + x;
styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100)+y; styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100) + y;
} else { } else {
styL = +sty.left.replace(/\px/g, '')+x; styL = +sty.left.replace(/\px/g, '') + x;
styT = +sty.top.replace(/\px/g, '')+y; styT = +sty.top.replace(/\px/g, '') + y;
}; }
;
// 鼠标拖拽事件 // 鼠标拖拽事件
document.onmousemove = function (e) { document.onmousemove = function (e) {
// 全屏禁止拖动 // 全屏禁止拖动
if((dragDom.offsetParent.clientWidth - dragDom.clientWidth) === 0){ if ((dragDom.offsetParent.clientWidth - dragDom.clientWidth) === 0) {
return return
} }
// 通过事件委托,计算移动的距离 (开始拖拽至结束拖拽的距离) // 通过事件委托,计算移动的距离 (开始拖拽至结束拖拽的距离)
@ -219,9 +210,9 @@ Vue.directive('dialogDrag', {
} else if (finallyT > dragDom.offsetParent.clientHeight - dragDom.clientHeight) (///底部 } else if (finallyT > dragDom.offsetParent.clientHeight - dragDom.clientHeight) (///底部
finallyT = dragDom.offsetParent.clientHeight - dragDom.clientHeight finallyT = dragDom.offsetParent.clientHeight - dragDom.clientHeight
) )
x=finallyL; x = finallyL;
y=finallyT; y = finallyT;
dragDom.style.transform="translate("+finallyL+"px,"+finallyT+"px)"; dragDom.style.transform = "translate(" + finallyL + "px," + finallyT + "px)";
//将此时的位置传出去 //将此时的位置传出去
// binding.value({x:e.pageX,y:e.pageY}) // binding.value({x:e.pageX,y:e.pageY})
}; };
@ -242,7 +233,7 @@ Vue.directive('dialogDragWidth', {
// 鼠标按下,计算当前元素距离可视区的距离 // 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - el.offsetLeft const disX = e.clientX - el.offsetLeft
document.onmousemove = function(e) { document.onmousemove = function (e) {
e.preventDefault() // 移动时禁用默认事件 e.preventDefault() // 移动时禁用默认事件
// 通过事件委托,计算移动的距离 // 通过事件委托,计算移动的距离
@ -250,7 +241,7 @@ Vue.directive('dialogDragWidth', {
dragDom.style.width = `${l}px` dragDom.style.width = `${l}px`
} }
document.onmouseup = function(e) { document.onmouseup = function (e) {
document.onmousemove = null document.onmousemove = null
document.onmouseup = null document.onmouseup = null
} }
@ -272,11 +263,13 @@ Vue.directive('clickoutside', { // 初始化指令
binding.value(e); binding.value(e);
} }
} }
// 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听 // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
el.__vueClickOutside__ = documentHandler; el.__vueClickOutside__ = documentHandler;
document.addEventListener('click', documentHandler); document.addEventListener('click', documentHandler);
}, },
update() {}, update() {
},
unbind(el, binding) { // 解除事件监听 unbind(el, binding) { // 解除事件监听
document.removeEventListener('click', el.__vueClickOutside__); document.removeEventListener('click', el.__vueClickOutside__);
delete el.__vueClickOutside__; delete el.__vueClickOutside__;