完成我的音乐页面
This commit is contained in:
parent
4724c209e8
commit
c2d105a0f2
@ -24,9 +24,9 @@
|
||||
-- 粉丝|0
|
||||
-- 编辑资料|☑
|
||||
-- 添加朋友|☑
|
||||
-- 我的音乐|50%
|
||||
-- 收藏视频\音乐|50%
|
||||
-- 我的音乐|☑
|
||||
-- 抖音商城|0
|
||||
-- 收藏视频\音乐|50%
|
||||
-- 右侧菜单子页面|10%
|
||||
-- 设置|☑
|
||||
-- -- 子页面|☑
|
||||
|
||||
27
src/App.vue
27
src/App.vue
@ -1,8 +1,5 @@
|
||||
<template>
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition name="fade">
|
||||
<Mask v-if="maskDialog" @click="hideMaskDialog" :mode="maskDialogMode"></Mask>
|
||||
</transition>
|
||||
<transition :name="transitionName">
|
||||
<!-- <keep-alive>-->
|
||||
<!-- </keep-alive>-->
|
||||
@ -19,26 +16,22 @@
|
||||
* try {navigator.control.gesture(false);} catch (e) {} //UC浏览器关闭默认手势事件
|
||||
try {navigator.control.longpressMenu(false);} catch (e) {} //关闭长按弹出菜单
|
||||
* */
|
||||
import * as Vue from "vue";
|
||||
import Loading from "./components/Loading";
|
||||
import Mask from "./components/Mask";
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
Mask
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
transitionName: 'go',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
maskDialog() {
|
||||
return this.$store.state.maskDialog
|
||||
},
|
||||
maskDialogMode() {
|
||||
return this.$store.state.maskDialogMode
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
hideMaskDialog() {
|
||||
this.$store.commit('setMaskDialog', {state: false, mode: this.maskDialogMode})
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
methods: {},
|
||||
// watch $route 决定使用哪种过渡
|
||||
watch: {
|
||||
'$route'(to, from) {
|
||||
@ -107,7 +100,7 @@ export default {
|
||||
const toDepth = routeDeep.indexOf(to.path)
|
||||
const fromDepth = routeDeep.indexOf(from.path)
|
||||
this.transitionName = toDepth > fromDepth ? 'go' : 'back'
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// this.$store.dispatch('getFriends')
|
||||
|
||||
BIN
src/assets/img/icon/me/float-play.png
Normal file
BIN
src/assets/img/icon/me/float-play.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<from-bottom-dialog
|
||||
page-id="home-index"
|
||||
v-model="modelValue"
|
||||
@cancel="cancel"
|
||||
:show-heng-gang="false"
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
></div>
|
||||
</template>
|
||||
<script>
|
||||
//未以组件的方式使用,FromBottomDialog.vue里面是用js append到dom里面去的,
|
||||
//以组件的方式使用,不好随意插位置,插到app下面,又会出现定位覆盖的问题
|
||||
export default {
|
||||
name: "Mask",
|
||||
props: {
|
||||
@ -15,7 +17,7 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
<style lang="less">
|
||||
|
||||
.Mask {
|
||||
z-index: 3;
|
||||
@ -35,7 +37,7 @@ export default {
|
||||
}
|
||||
|
||||
&.lightgray {
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
&.white {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<from-bottom-dialog
|
||||
:page-id="pageId"
|
||||
v-model="modelValue"
|
||||
@cancel="closeShare"
|
||||
:show-heng-gang="false"
|
||||
@ -24,34 +25,32 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="shares ">
|
||||
<div class="shares">
|
||||
<template v-if="mode === 'video'">
|
||||
<div class="share-to" @click="$no">
|
||||
<img src="../assets/img/icon/components/video/torichang.png" alt="">
|
||||
<span>分享日常</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="share-to" @click="closeShare($emit('ShareToFriend'))">
|
||||
<img src="../assets/img/icon/components/video/tofriend.webp" alt="">
|
||||
<span>私信朋友</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('showShare2WeChatZone'))">
|
||||
<img src="../assets/img/icon/components/video/towechat.webp" alt="">
|
||||
<span>朋友圈</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('share2WeChat'))">
|
||||
<img src="../assets/img/icon/components/video/towechatchat.webp" alt="">
|
||||
<span>微信好友</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('share2QQZone'))">
|
||||
<img src="../assets/img/icon/components/video/tozone.webp" alt="">
|
||||
<span>QQ空间</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('share2QQ'))">
|
||||
<img src="../assets/img/icon/components/video/toqq.webp" alt="">
|
||||
<span>QQ好友</span>
|
||||
</div>
|
||||
<template v-if="mode === 'video'">
|
||||
<div class="share-to" @click="closeShare($emit('ShareToFriend'))">
|
||||
<img src="../assets/img/icon/components/video/tofriend.webp" alt="">
|
||||
<span>私信朋友</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('showShare2WeChatZone'))">
|
||||
<img src="../assets/img/icon/components/video/towechat.webp" alt="">
|
||||
<span>朋友圈</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('share2WeChat'))">
|
||||
<img src="../assets/img/icon/components/video/towechatchat.webp" alt="">
|
||||
<span>微信好友</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('share2QQZone'))">
|
||||
<img src="../assets/img/icon/components/video/tozone.webp" alt="">
|
||||
<span>QQ空间</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('share2QQ'))">
|
||||
<img src="../assets/img/icon/components/video/toqq.webp" alt="">
|
||||
<span>QQ好友</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('showShareDuoshan'))">
|
||||
<img src="../assets/img/icon/components/video/duoshan.png" alt="">
|
||||
<span>多闪</span>
|
||||
@ -60,11 +59,47 @@
|
||||
<img src="../assets/img/icon/components/video/totoutiao.webp" alt="">
|
||||
<span>今日头条</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('share2Webo'))">
|
||||
<img src="../assets/img/icon/components/video/toweibo.webp" alt="">
|
||||
<span>微博</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="mode === 'music'">
|
||||
<div class="share-to" @click="closeShare($emit('ShareToFriend'))">
|
||||
<img src="../assets/img/icon/components/video/tofriend.webp" alt="">
|
||||
<span>私信朋友</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('showShare2WeChatZone'))">
|
||||
<img src="../assets/img/icon/components/video/towechat.webp" alt="">
|
||||
<span>朋友圈</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('share2WeChat'))">
|
||||
<img src="../assets/img/icon/components/video/towechatchat.webp" alt="">
|
||||
<span>微信好友</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('share2QQZone'))">
|
||||
<img src="../assets/img/icon/components/video/tozone.webp" alt="">
|
||||
<span>QQ空间</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('share2QQ'))">
|
||||
<img src="../assets/img/icon/components/video/toqq.webp" alt="">
|
||||
<span>QQ好友</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('share2Webo'))">
|
||||
<img src="../assets/img/icon/components/video/toweibo.webp" alt="">
|
||||
<span>微博</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="mode === 'my-music'">
|
||||
<div class="share-to" @click="$no">
|
||||
<img src="../assets/img/icon/components/video/torichang.png" alt="">
|
||||
<span>转发到日常</span>
|
||||
</div>
|
||||
<div class="share-to" @click="closeShare($emit('ShareToFriend'))">
|
||||
<img src="../assets/img/icon/components/video/tofriend.webp" alt="">
|
||||
<span>私信朋友</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="share-to" @click="closeShare($emit('share2Webo'))">
|
||||
<img src="../assets/img/icon/components/video/toweibo.webp" alt="">
|
||||
<span>微博</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toolbar ">
|
||||
<template v-if="mode === 'qrcode'">
|
||||
@ -174,6 +209,10 @@ export default {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
pageId: {
|
||||
type: String,
|
||||
default: 'home-index'
|
||||
},
|
||||
canDownload: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
|
||||
@ -42,11 +42,6 @@ export default {
|
||||
// default: 'light'
|
||||
// default: 'white'
|
||||
},
|
||||
//触摸,是否可以滑动
|
||||
touchMoved: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
maskMode: {
|
||||
type: String,
|
||||
default: 'dark'
|
||||
@ -61,41 +56,40 @@ export default {
|
||||
},
|
||||
pageId: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
default: null,
|
||||
required: true
|
||||
},
|
||||
borderRadius: {
|
||||
type: String,
|
||||
default: '.5rem .5rem 0 0'
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
modelValue(newVal) {
|
||||
let app = document.getElementById('app')
|
||||
let page = document.getElementById(this.pageId)
|
||||
if (newVal) {
|
||||
if (this.pageId) {
|
||||
let page = document.getElementById(this.pageId)
|
||||
this.pagePosition = this.$getCss2(page, 'position')
|
||||
page.style.position = 'absolute'
|
||||
} else {
|
||||
this.pagePosition = this.$getCss2(app.children[0], 'position')
|
||||
app.children[0].style.position = 'absolute'
|
||||
}
|
||||
this.pagePosition = this.$getCss2(page, 'position')
|
||||
page.style.position = 'absolute'
|
||||
this.scroll = document.documentElement.scrollTop
|
||||
document.body.style.position = 'fixed'
|
||||
document.body.style.top = -this.scroll + 'px'
|
||||
|
||||
let maskTemplate = `<div class="Mask fade-in ${this.maskMode}"></div>`
|
||||
let mask = new Dom().create(maskTemplate)
|
||||
mask.on('click', () => this.hide(false))
|
||||
page.appendChild(mask.els[0])
|
||||
} else {
|
||||
if (this.pageId) {
|
||||
let page = document.getElementById(this.pageId)
|
||||
page.style.position = this.pagePosition || 'fixed'
|
||||
} else {
|
||||
app.children[1].style.position = this.pagePosition || 'fixed'
|
||||
}
|
||||
let page = document.getElementById(this.pageId)
|
||||
page.style.position = this.pagePosition || 'fixed'
|
||||
document.body.style.position = 'static'
|
||||
document.documentElement.scrollTop = this.scroll
|
||||
|
||||
let mask = new Dom('.Mask').replaceClass('fade-in', 'fade-out')
|
||||
setTimeout(() => {
|
||||
mask.remove()
|
||||
}, 300)
|
||||
}
|
||||
this.$store.commit('setMaskDialog', {state: newVal, mode: this.maskMode})
|
||||
},
|
||||
maskDialog(newVal) {
|
||||
if (!newVal) {
|
||||
this.hide(newVal)
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -106,11 +100,7 @@ export default {
|
||||
pagePosition: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
maskDialog() {
|
||||
return this.$store.state.maskDialog
|
||||
},
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
},
|
||||
methods: {
|
||||
@ -149,13 +139,11 @@ export default {
|
||||
this.$emit('cancel')
|
||||
},
|
||||
start(e) {
|
||||
if (!this.touchMoved) return;
|
||||
if (this.$refs.dialog.scrollTop !== 0) return
|
||||
this.startLocationY = e.touches[0].pageY
|
||||
this.startTime = Date.now()
|
||||
},
|
||||
move(e) {
|
||||
if (!this.touchMoved) return;
|
||||
if (this.$refs.dialog.scrollTop !== 0) return
|
||||
this.moveYDistance = e.touches[0].pageY - this.startLocationY
|
||||
if (this.moveYDistance > 0) {
|
||||
@ -164,7 +152,6 @@ export default {
|
||||
}
|
||||
},
|
||||
end(e) {
|
||||
if (!this.touchMoved) return;
|
||||
|
||||
//点击
|
||||
if (Date.now() - this.startTime < 150 && Math.abs(this.moveYDistance) < 30) {
|
||||
@ -203,7 +190,7 @@ export default {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
box-sizing: border-box;
|
||||
border-radius: .5rem .5rem 0 0;
|
||||
border-radius: v-bind(borderRadius);
|
||||
transition: all .3s;
|
||||
|
||||
&.dark {
|
||||
|
||||
@ -10,6 +10,8 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {nextTick} from "vue";
|
||||
|
||||
export default {
|
||||
name: "BaseSlideList",
|
||||
props: {
|
||||
@ -17,6 +19,15 @@ export default {
|
||||
type: Number,
|
||||
default: () => 0
|
||||
},
|
||||
//改变index,是否使用动画
|
||||
changeActiveIndexUseAnim: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
canMove: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -42,8 +53,7 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
activeIndex() {
|
||||
// console.log('activeIndex')
|
||||
activeIndex(newVal) {
|
||||
this.changeIndex()
|
||||
},
|
||||
},
|
||||
@ -52,14 +62,29 @@ export default {
|
||||
await this.checkChildren()
|
||||
},
|
||||
methods: {
|
||||
checkChildren() {
|
||||
this.slideList = this.$refs.slideList
|
||||
this.slideItems = this.slideList.children
|
||||
this.wrapperHeight = this.$getCss(this.slideList, 'height')
|
||||
for (let i = 0; i < this.slideItems.length; i++) {
|
||||
let el = this.slideItems[i]
|
||||
this.slideItemsHeights.push(this.$getCss(el, 'height'))
|
||||
async changeIndex() {
|
||||
await this.checkChildren()
|
||||
this.currentSlideItemIndex = this.activeIndex
|
||||
if (this.changeActiveIndexUseAnim) {
|
||||
this.$setCss(this.slideList, 'transition-duration', `300ms`)
|
||||
}
|
||||
this.$setCss(this.slideList, 'transform', `translate3d(0px, ${-this.getHeight(this.currentSlideItemIndex) + this.moveYDistance}px, 0px)`)
|
||||
this.$attrs['onUpdate:active-index'] && this.$emit('update:active-index', this.currentSlideItemIndex)
|
||||
},
|
||||
checkChildren() {
|
||||
return new Promise(resolve => {
|
||||
nextTick(() => {
|
||||
this.slideList = this.$refs.slideList
|
||||
this.slideItems = this.slideList.children
|
||||
this.wrapperHeight = this.$getCss(this.slideList, 'height')
|
||||
this.slideItemsHeights = []
|
||||
for (let i = 0; i < this.slideItems.length; i++) {
|
||||
let el = this.slideItems[i]
|
||||
this.slideItemsHeights.push(this.$getCss(el, 'height'))
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
},
|
||||
touchStart(e) {
|
||||
this.checkChildren()
|
||||
@ -70,6 +95,7 @@ export default {
|
||||
this.startTime = Date.now()
|
||||
},
|
||||
touchMove(e) {
|
||||
if (!this.canMove) return;
|
||||
this.moveXDistance = e.touches[0].pageX - this.startLocationX
|
||||
this.moveYDistance = e.touches[0].pageY - this.startLocationY
|
||||
|
||||
@ -90,6 +116,7 @@ export default {
|
||||
}
|
||||
},
|
||||
touchEnd(e) {
|
||||
if (!this.canMove) return;
|
||||
if (this.isCanDownWiping) {
|
||||
if (this.currentSlideItemIndex === 0 && !this.isDrawDown) return
|
||||
if (this.currentSlideItemIndex === this.slideItems.length - 1 && this.isDrawDown) return this.$attrs['onEnd'] && this.$emit('end')
|
||||
|
||||
@ -60,6 +60,7 @@
|
||||
<Share v-model="isSharing"
|
||||
mode="music"
|
||||
ref="share"
|
||||
pageId="Music"
|
||||
@showDouyinCode="showDouyinCode = true"
|
||||
@showShare2WeChatZone="shareType = 2"
|
||||
@share2WeChat="shareType = 3"
|
||||
@ -85,7 +86,7 @@
|
||||
</template>
|
||||
</ConfirmDialog>
|
||||
|
||||
<ShareToFriend v-model="shareToFriend"/>
|
||||
<ShareToFriend pageId="Music" v-model="shareToFriend"/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<from-bottom-dialog
|
||||
page-id="home-index"
|
||||
v-model="modelValue"
|
||||
:show-heng-gang="false"
|
||||
maskMode="dark"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<from-bottom-dialog
|
||||
page-id="home-index"
|
||||
v-model="modelValue"
|
||||
:show-heng-gang="false"
|
||||
maskMode="dark"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<from-bottom-dialog
|
||||
:page-id="pageId"
|
||||
v-model="modelValue"
|
||||
@cancel="cancel"
|
||||
maskMode="light"
|
||||
@ -108,7 +109,11 @@ export default {
|
||||
Check
|
||||
},
|
||||
props: {
|
||||
modelValue: false
|
||||
modelValue: false,
|
||||
pageId: {
|
||||
type: String,
|
||||
default: 'home-index'
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -167,7 +172,7 @@ export default {
|
||||
|
||||
.button {
|
||||
width: 6.4rem;
|
||||
height: 2.6rem!important;
|
||||
height: 2.6rem !important;
|
||||
}
|
||||
|
||||
@avatar-width: 3.8rem;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="other-login">
|
||||
<div class="other-login" id="other-login">
|
||||
<BaseHeader mode="light" backMode="dark" backImg="back">
|
||||
<template v-slot:right>
|
||||
<span class="f16">帮助</span>
|
||||
@ -41,6 +41,7 @@
|
||||
</div>
|
||||
|
||||
<from-bottom-dialog
|
||||
page-id="other-login"
|
||||
v-model="isOtherLogin"
|
||||
:show-heng-gang="false"
|
||||
height="27rem"
|
||||
|
||||
@ -9,13 +9,9 @@
|
||||
</IndicatorLight>
|
||||
<back style="opacity: 0;" mode="light" img="back"/>
|
||||
</div>
|
||||
<SlideRowList
|
||||
name="myMusicList"
|
||||
v-model:active-index="slideIndex">
|
||||
<SlideRowList name="myMusicList" v-model:active-index="slideIndex">
|
||||
<SlideItem>
|
||||
<SlideColumnList>
|
||||
<SlideItemMusic v-model="guessMusic[index]" v-for="(item,index) in guessMusic "/>
|
||||
</SlideColumnList>
|
||||
<GuessMusic :list="guessMusic"/>
|
||||
</SlideItem>
|
||||
<SlideItem style="overflow: auto;">
|
||||
<div class="my-collect">
|
||||
@ -29,7 +25,7 @@
|
||||
<img class="menu" src="../../assets/img/icon/menu-white.png" alt="">
|
||||
</div>
|
||||
<div class="collect-list">
|
||||
<div class="item" v-for="item in collectMusic" @click="playMusic(item)">
|
||||
<div class="item" v-for="(item,index) in collectMusic" @click="page2PlayMusic(item)">
|
||||
<div class="left">
|
||||
<div class="cover-wrapper">
|
||||
<img v-lazy="$imgPreview(item.cover)" alt="" class="cover">
|
||||
@ -44,7 +40,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<img v-if="item.is_play" class="playing-icon" src="../../assets/img/icon/me/pinlv.gif">
|
||||
<img v-if="page2SlideIndex === index" class="playing-icon"
|
||||
src="../../assets/img/icon/me/pinlv.gif">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -56,7 +53,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="recommend-list">
|
||||
<div class="item" v-for="item in recommendMusic" @click="playMusic(item)">
|
||||
<div class="item" v-for="(item,index) in recommendMusic" @click="page2PlayMusic(item)">
|
||||
<div class="left">
|
||||
<div class="cover-wrapper">
|
||||
<img v-lazy="$imgPreview(item.cover)" alt="" class="cover">
|
||||
@ -71,39 +68,46 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<img v-if="item.is_play" class="playing-icon" src="../../assets/img/icon/me/pinlv.gif">
|
||||
<img v-if="page2SlideIndex - collectMusic.length === index" class="playing-icon"
|
||||
src="../../assets/img/icon/me/pinlv.gif">
|
||||
<div class="collect-icon">
|
||||
<img src="../../assets/img/icon/star-white.png" v-show="!isCollect" @click="isCollect = !isCollect">
|
||||
<img src="../../assets/img/icon/star-yellow.png" v-show="isCollect" @click="isCollect = !isCollect">
|
||||
<img src="../../assets/img/icon/star-white.png" v-show="!item.isCollect"
|
||||
@click.stop="item.isCollect = !item.isCollect">
|
||||
<img src="../../assets/img/icon/star-yellow.png" v-show="item.isCollect"
|
||||
@click.stop="item.isCollect = !item.isCollect">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="playing" @click="isShowCollectDialog = true">
|
||||
<div class="playing-wrapper">
|
||||
<div class="cover-wrapper">
|
||||
<img v-lazy="$imgPreview(currentMusic.cover)" alt="" class="cover">
|
||||
<transition name="float-play">
|
||||
<div v-if="isShowFloatPlay" class="playing" @click="isShowCollectDialog = true">
|
||||
<div class="playing-wrapper">
|
||||
<div class="cover-wrapper">
|
||||
<img v-lazy="$imgPreview(currentMusic.cover)" alt="" class="cover">
|
||||
</div>
|
||||
<div class="name">{{ currentMusic.name }}</div>
|
||||
<img v-show="page2IsPlay" @click.stop="togglePage2Play" class="option"
|
||||
src="../../assets/img/icon/me/float-pause-one.png" alt="">
|
||||
<img v-show="!page2IsPlay" @click.stop="togglePage2Play" class="option"
|
||||
src="../../assets/img/icon/me/float-play.png" alt="">
|
||||
<img @click.stop="$no" class="menu-list" src="../../assets/img/icon/me/music-list.png" alt="">
|
||||
</div>
|
||||
<div class="name">{{ currentMusic.name }}</div>
|
||||
<img class="option" src="../../assets/img/icon/me/float-pause-one.png" alt="">
|
||||
<img class="menu-list" src="../../assets/img/icon/me/music-list.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</SlideItem>
|
||||
</SlideRowList>
|
||||
|
||||
|
||||
<transition name="my-collect-dialog">
|
||||
<div class="my-collect-dialog" v-if="isShowCollectDialog">
|
||||
<div class="my-collect-dialog" v-show="isShowCollectDialog">
|
||||
<div class="dialog-header">
|
||||
<back class="close" mode="light" img="back" @click="isShowCollectDialog = false"/>
|
||||
<span>我的收藏</span>
|
||||
<back style="opacity: 0;" mode="light" img="back"/>
|
||||
</div>
|
||||
<SlideColumnList>
|
||||
<SlideItemMusic v-model="guessMusic[index]" v-for="(item,index) in guessMusic "/>
|
||||
</SlideColumnList>
|
||||
<CollectMusic ref="CollectMusic" :list="page2Music" v-model:page2SlideIndex="page2SlideIndex"/>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
@ -116,17 +120,24 @@ import gaobaiqiqiu from '../../assets/data/lyrics/gaobaiqiqiu.lrc'
|
||||
import Switches from "../message/components/swtich/switches";
|
||||
import SlideItemMusic from "./components/SlideItemMusic";
|
||||
import IndicatorLight from "../../components/slide/IndicatorLight";
|
||||
import FromBottomDialog from "../../components/dialog/FromBottomDialog";
|
||||
import GuessMusic from "./components/GuessMusic";
|
||||
import CollectMusic from "./components/CollectMusic";
|
||||
|
||||
//TODO 两个page页面的播放冲突未做
|
||||
export default {
|
||||
name: "MyMusic",
|
||||
components: {
|
||||
FromBottomDialog,
|
||||
Switches,
|
||||
SlideItemMusic,
|
||||
IndicatorLight
|
||||
IndicatorLight,
|
||||
GuessMusic,
|
||||
CollectMusic
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
slideIndex: 0,
|
||||
slideIndex: 1,
|
||||
currentMusic: {
|
||||
name: '告白气球',
|
||||
mp3: 'https://mp32.9ku.com/upload/128/2017/02/05/858423.mp3',
|
||||
@ -140,99 +151,43 @@ export default {
|
||||
collectMusic: [],
|
||||
recommendMusic: [],
|
||||
guessMusic: [],
|
||||
lyricsTexts: [],
|
||||
lyricsFullTexts: [],
|
||||
|
||||
isShowCollectDialog: false,
|
||||
isPlay: false,
|
||||
isShowFloatPlay: false,
|
||||
|
||||
isAutoPlay: true,
|
||||
isLoop: false,
|
||||
isMove: false,
|
||||
isCollect: false,
|
||||
isFullLyrics: false,
|
||||
lastPageX: 0,
|
||||
pageX: 0,
|
||||
audio: new Audio(),
|
||||
duration: 0,
|
||||
currentTime: 0,
|
||||
step: 0,
|
||||
startX: 0,
|
||||
slideBarWidth: 0
|
||||
|
||||
page2SlideIndex: -1,
|
||||
page2IsPlay: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['bodyWidth'])
|
||||
...mapState(['bodyWidth']),
|
||||
page2Music() {
|
||||
return this.collectMusic.concat(this.recommendMusic)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getCollectMusic()
|
||||
},
|
||||
mounted() {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
this.audio.volume = .2
|
||||
}
|
||||
this.audio.addEventListener('loadedmetadata', e => {
|
||||
this.duration = this.audio.duration
|
||||
this.slideBarWidth = this.$refs.slideBar.clientWidth
|
||||
this.step = this.slideBarWidth / Math.floor(this.duration)
|
||||
})
|
||||
let lrcObj = this.createLrcObj(gaobaiqiqiu);
|
||||
this.lyricsTexts.push(lrcObj.ms[0])
|
||||
this.lyricsTexts.push(lrcObj.ms[1])
|
||||
lrcObj.ms.map(v => {
|
||||
if (v.c) this.lyricsFullTexts.push(v)
|
||||
})
|
||||
console.log(lrcObj.ms)
|
||||
this.audio.addEventListener('timeupdate', e => {
|
||||
let currentTime = Math.ceil(e.target.currentTime)
|
||||
// let lastLyricsText = this.lyricsTexts[this.lyricsTexts.length - 1]
|
||||
// if (Number(lastLyricsText.t) < currentTime) {
|
||||
// for (let i = 0; i < lrcObj.ms.length; i++) {
|
||||
// let item = lrcObj.ms[i]
|
||||
// if (Number(item.t) > currentTime) {
|
||||
// if (item.c) {
|
||||
// console.log(item)
|
||||
// this.t(item)
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if (!this.isMove) {
|
||||
this.currentTime = currentTime
|
||||
if (Math.ceil(e.target.currentTime) * this.step > this.slideBarWidth - 5) {
|
||||
this.pageX = this.slideBarWidth - 5
|
||||
} else {
|
||||
this.pageX = Math.ceil(e.target.currentTime) * this.step
|
||||
}
|
||||
}
|
||||
})
|
||||
this.audio.addEventListener('play', e => this.isPlay = true)
|
||||
this.audio.addEventListener('ended', e => {
|
||||
if (this.isLoop) {
|
||||
this.lastPageX = 0
|
||||
this.audio.currentTime = 0
|
||||
this.audio.play()
|
||||
} else {
|
||||
this.isPlay = false
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
playMusic(item) {
|
||||
this.collectMusic.map(v => v.is_play = false)
|
||||
this.recommendMusic.map(v => v.is_play = false)
|
||||
item.is_play = true
|
||||
this.currentMusic = item
|
||||
this.audio.src = this.currentMusic.mp3
|
||||
this.togglePlay(true)
|
||||
},
|
||||
togglePlay(state) {
|
||||
this.currentMusic.is_play = state || !this.currentMusic.is_play
|
||||
if (this.currentMusic.is_play) {
|
||||
this.audio.play()
|
||||
togglePage2Play() {
|
||||
this.page2IsPlay = !this.page2IsPlay
|
||||
if (this.page2IsPlay) {
|
||||
this.$refs.CollectMusic.play(this.page2SlideIndex)
|
||||
} else {
|
||||
this.audio.pause()
|
||||
this.$refs.CollectMusic.pause()
|
||||
}
|
||||
},
|
||||
page2PlayMusic(item) {
|
||||
this.currentMusic = item
|
||||
this.isShowFloatPlay = true
|
||||
this.page2IsPlay = true
|
||||
this.page2SlideIndex = this.page2Music.findIndex(v => v.name === item.name)
|
||||
this.isShowCollectDialog = true
|
||||
this.$refs.CollectMusic.play(this.page2SlideIndex)
|
||||
},
|
||||
async getCollectMusic() {
|
||||
this.loading = true
|
||||
let res = await this.$api.videos.collect()
|
||||
@ -242,93 +197,6 @@ export default {
|
||||
this.guessMusic = this.recommendMusic = res.data.music.list.slice(2, -1)
|
||||
}
|
||||
},
|
||||
createLrcObj(lrc) {
|
||||
let oLRC = {
|
||||
ti: "", //歌曲名
|
||||
ar: "", //演唱者
|
||||
al: "", //专辑名
|
||||
by: "", //歌词制作人
|
||||
offset: 0, //时间补偿值,单位毫秒,用于调整歌词整体位置
|
||||
ms: [] //歌词数组{t:时间,c:歌词}
|
||||
};
|
||||
if (lrc.length === 0) return;
|
||||
let lrcs = lrc.split('\n');//用回车拆分成数组
|
||||
for (let i in lrcs) {//遍历歌词数组
|
||||
lrcs[i] = lrcs[i].replace(/(^\s*)|(\s*$)/g, ""); //去除前后空格
|
||||
let t = lrcs[i].substring(lrcs[i].indexOf("[") + 1, lrcs[i].indexOf("]"));//取[]间的内容
|
||||
let s = t.split(":");//分离:前后文字
|
||||
if (isNaN(parseInt(s[0]))) { //不是数值
|
||||
for (let i in oLRC) {
|
||||
if (i != "ms" && i == s[0].toLowerCase()) {
|
||||
oLRC[i] = s[1];
|
||||
}
|
||||
}
|
||||
} else { //是数值
|
||||
let arr = lrcs[i].match(/\[(\d+:.+?)\]/g);//提取时间字段,可能有多个
|
||||
let start = 0;
|
||||
for (let k in arr) {
|
||||
start += arr[k].length; //计算歌词位置
|
||||
}
|
||||
let content = lrcs[i].substring(start);//获取歌词内容
|
||||
for (let k in arr) {
|
||||
let t = arr[k].substring(1, arr[k].length - 1);//取[]间的内容
|
||||
let s = t.split(":");//分离:前后文字
|
||||
oLRC.ms.push({//对象{t:时间,c:歌词}加入ms数组
|
||||
t: (parseFloat(s[0]) * 60 + parseFloat(s[1])).toFixed(3),
|
||||
c: content
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
oLRC.ms.sort(function (a, b) {//按时间顺序排序
|
||||
return a.t - b.t;
|
||||
});
|
||||
return oLRC
|
||||
/*
|
||||
for(let i in oLRC){ //查看解析结果
|
||||
console.log(i,":",oLRC[i]);
|
||||
}*/
|
||||
},
|
||||
t(txt) {
|
||||
// if (this.test.length === 2) return
|
||||
this.lyricsTexts.push(txt)
|
||||
nextTick(() => {
|
||||
let comments = this.$refs['lyrics-wrapper']
|
||||
comments.scrollTo({top: comments.scrollHeight - comments.clientHeight, behavior: 'smooth'})
|
||||
})
|
||||
},
|
||||
start(e) {
|
||||
this.startX = e.touches[0].pageX
|
||||
},
|
||||
move(e) {
|
||||
this.isMove = true
|
||||
this.pageX = this.lastPageX + (e.touches[0].pageX - this.startX)
|
||||
if (this.pageX < 0) this.pageX = 0
|
||||
if (this.pageX > this.slideBarWidth) this.pageX = this.slideBarWidth - 5
|
||||
this.currentTime = Math.ceil(this.pageX / this.step)
|
||||
globalMethods.$stopPropagation(e)
|
||||
},
|
||||
end(e) {
|
||||
this.lastPageX = this.pageX
|
||||
this.currentTime = Math.ceil(this.pageX / this.step)
|
||||
this.audio.currentTime = this.currentTime
|
||||
this.audio.play()
|
||||
this.isMove = false
|
||||
globalMethods.$stopPropagation(e)
|
||||
},
|
||||
$durationTime(time) {
|
||||
if (time === 0) return '00:00'
|
||||
else {
|
||||
return this.$duration(time)
|
||||
}
|
||||
},
|
||||
durationStyle(type) {
|
||||
// return {}
|
||||
if (type === 1) {
|
||||
return {width: this.pageX + 'px'}
|
||||
}
|
||||
return {left: this.pageX + 'px'}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -383,6 +251,7 @@ export default {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: white;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
@ -394,6 +263,7 @@ export default {
|
||||
}
|
||||
|
||||
.num {
|
||||
font-size: 1.3rem;
|
||||
color: gray;
|
||||
margin-left: .5rem;
|
||||
}
|
||||
@ -406,6 +276,7 @@ export default {
|
||||
|
||||
.collect-list, .recommend-list {
|
||||
.item {
|
||||
color: white;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1.5rem;
|
||||
@ -584,7 +455,6 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.my-collect-dialog-enter-active,
|
||||
.my-collect-dialog-leave-active {
|
||||
transition-duration: 300ms;
|
||||
@ -596,5 +466,17 @@ export default {
|
||||
transition-duration: 300ms;
|
||||
transform: translateY(100vh);
|
||||
}
|
||||
|
||||
.float-play-enter-active,
|
||||
.float-play-leave-active {
|
||||
transition-duration: 200ms;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.float-play-enter-from,
|
||||
.float-play-leave-to {
|
||||
transition-duration: 200ms;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="RequestUpdate">
|
||||
<div class="RequestUpdate" id="RequestUpdate">
|
||||
<BaseHeader>
|
||||
<template v-slot:center>
|
||||
<span class="f16">求更新</span>
|
||||
@ -37,6 +37,7 @@
|
||||
</div>
|
||||
|
||||
<from-bottom-dialog
|
||||
page-id="RequestUpdate"
|
||||
height="16rem"
|
||||
:show-heng-gang="false"
|
||||
mode="white"
|
||||
|
||||
269
src/pages/me/components/CollectMusic.vue
Normal file
269
src/pages/me/components/CollectMusic.vue
Normal file
@ -0,0 +1,269 @@
|
||||
<template>
|
||||
<div id="CollectMusic">
|
||||
<SlideColumnList
|
||||
:changeActiveIndexUseAnim="false"
|
||||
v-model:active-index="activeIndex"
|
||||
:canMove="slideCanMove">
|
||||
<SlideItemMusic
|
||||
:ref="setItemRef"
|
||||
@showList="isShowList = true"
|
||||
@showShare="isSharing = true"
|
||||
@previous="previous"
|
||||
@next="next"
|
||||
@slideCanMove="e => this.slideCanMove = e"
|
||||
v-model="list[index]"
|
||||
v-model:isLoop="isLoop"
|
||||
v-for="(item,index) in list "/>
|
||||
</SlideColumnList>
|
||||
<from-bottom-dialog
|
||||
mask-mode="lightgray"
|
||||
page-id="CollectMusic"
|
||||
border-radius="1.5rem 1.5rem 0 0"
|
||||
:show-heng-gang="false"
|
||||
height="70vh"
|
||||
v-model="isShowList">
|
||||
<div class="music-list-dialog">
|
||||
<div class="music-list-header">
|
||||
<div class="left">待播清单</div>
|
||||
<div class="right" @click="isLoop = !isLoop">
|
||||
<img v-show="isLoop" src="@/assets/img/icon/me/loop.png" alt="">
|
||||
<img v-show="!isLoop" src="@/assets/img/icon/me/play-normal.png" alt="">
|
||||
<span>{{ isLoop ? '单曲循环' : '顺序播放' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
<div class="l-row"
|
||||
@click="play(index)"
|
||||
:class="{active:activeIndex === index}"
|
||||
v-for="(item,index) in list">
|
||||
<div class="left">
|
||||
<img v-if="activeIndex === index" src="@/assets/img/icon/me/pinlv.gif" alt="" class="play-icon">
|
||||
<div class="name">{{ item.name }}</div>
|
||||
<div class="author">{{ item.author }}</div>
|
||||
</div>
|
||||
<back class="right" mode="gray" img="close"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer" @click="isShowList = false">取消</div>
|
||||
</div>
|
||||
</from-bottom-dialog>
|
||||
|
||||
<Share v-model="isSharing"
|
||||
mode="my-music"
|
||||
ref="share"
|
||||
pageId="GuessMusic"
|
||||
@ShareToFriend="delayShowDialog( e => this.isShowShareToFriend = true)"
|
||||
/>
|
||||
|
||||
<ShareToFriend pageId="GuessMusic" v-model="isShowShareToFriend"/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import FromBottomDialog from "../../../components/dialog/FromBottomDialog";
|
||||
import Switches from "../../message/components/swtich/switches";
|
||||
import SlideItemMusic from "./SlideItemMusic";
|
||||
import IndicatorLight from "../../../components/slide/IndicatorLight";
|
||||
import SlideColumnList from "../../../components/slide/SlideColumnList";
|
||||
import Share from "../../../components/Share";
|
||||
import ShareToFriend from "../../home/components/ShareToFriend";
|
||||
|
||||
export default {
|
||||
name: "GuessMusic",
|
||||
components: {
|
||||
FromBottomDialog,
|
||||
Switches,
|
||||
SlideItemMusic,
|
||||
IndicatorLight,
|
||||
SlideColumnList,
|
||||
Share,
|
||||
ShareToFriend
|
||||
},
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
page2SlideIndex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
slideCanMove: true,
|
||||
isShowShareToFriend: false,
|
||||
isShowList: false,
|
||||
isSharing: false,
|
||||
isLoop: false,
|
||||
collectSlideIndex: 0,
|
||||
isShowCollectDialog: false,
|
||||
itemRefs: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
activeIndex: {
|
||||
get() {
|
||||
return this.page2SlideIndex
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:page2SlideIndex', val)
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
watch: {
|
||||
activeIndex(newVal, oldVal) {
|
||||
this.itemRefs.map(ref => {
|
||||
ref.togglePlay(false)
|
||||
})
|
||||
this.itemRefs[newVal].togglePlay(true, true)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
previous() {
|
||||
if (this.activeIndex > 0) {
|
||||
this.play(this.activeIndex - 1)
|
||||
}
|
||||
},
|
||||
next() {
|
||||
if (this.activeIndex < this.list.length - 1) {
|
||||
this.play(this.activeIndex + 1)
|
||||
}
|
||||
},
|
||||
delayShowDialog(cb) {
|
||||
setTimeout(() => {
|
||||
cb()
|
||||
}, 100)
|
||||
},
|
||||
setItemRef(el) {
|
||||
if (el) {
|
||||
this.itemRefs.push(el)
|
||||
}
|
||||
},
|
||||
play(index) {
|
||||
this.activeIndex = index
|
||||
this.itemRefs.map(ref => {
|
||||
ref.togglePlay(false)
|
||||
})
|
||||
this.itemRefs[index].togglePlay(true, true)
|
||||
},
|
||||
pause() {
|
||||
this.itemRefs.map(ref => {
|
||||
ref.togglePlay(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
@import "@/assets/less/index";
|
||||
|
||||
#CollectMusic {
|
||||
//width: 100vw;
|
||||
//height: 100vh;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
overflow: auto;
|
||||
color: white;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.music-list-dialog {
|
||||
height: 70vh;
|
||||
@bg-color: #1e1d1d;
|
||||
background: @bg-color;
|
||||
|
||||
.music-list-header {
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
background: @bg-color;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 1px solid #2a2828;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 5rem;
|
||||
padding: 0 @padding-page;
|
||||
border-radius: 1.5rem 1.5rem 0 0;
|
||||
z-index: 9;
|
||||
|
||||
.left {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.2rem;
|
||||
|
||||
img {
|
||||
width: 2rem;
|
||||
margin-right: .5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
padding-top: 5rem;
|
||||
}
|
||||
|
||||
.l-row {
|
||||
background: @bg-color;
|
||||
height: 5rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 @padding-page;
|
||||
|
||||
&.active {
|
||||
color: @primary-btn-color;
|
||||
}
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.author {
|
||||
font-size: 1.2rem;
|
||||
color: @second-text-color;
|
||||
margin-left: 2rem;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
width: .6rem;
|
||||
height: .5px;
|
||||
background: @second-text-color;
|
||||
position: absolute;
|
||||
left: -1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.play-icon {
|
||||
width: 1.5rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
width: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
background: @bg-color;
|
||||
border-top: 1px solid #2a2828;
|
||||
height: 6rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
251
src/pages/me/components/GuessMusic.vue
Normal file
251
src/pages/me/components/GuessMusic.vue
Normal file
@ -0,0 +1,251 @@
|
||||
<template>
|
||||
<div id="GuessMusic">
|
||||
<SlideColumnList
|
||||
:changeActiveIndexUseAnim="false"
|
||||
v-model:active-index="guessSlideIndex"
|
||||
:canMove="slideCanMove">
|
||||
<SlideItemMusic
|
||||
:ref="setItemRef"
|
||||
@showList="isShowList = true"
|
||||
@showShare="isSharing = true"
|
||||
@previous="previous"
|
||||
@next="next"
|
||||
@slideCanMove="e => this.slideCanMove = e"
|
||||
v-model="list[index]"
|
||||
v-model:isLoop="isLoop"
|
||||
v-for="(item,index) in list "/>
|
||||
</SlideColumnList>
|
||||
<from-bottom-dialog
|
||||
mask-mode="lightgray"
|
||||
page-id="GuessMusic"
|
||||
border-radius="1.5rem 1.5rem 0 0"
|
||||
:show-heng-gang="false"
|
||||
height="70vh"
|
||||
v-model="isShowList">
|
||||
<div class="music-list-dialog">
|
||||
<div class="music-list-header">
|
||||
<div class="left">待播清单</div>
|
||||
<div class="right" @click="isLoop = !isLoop">
|
||||
<img v-show="isLoop" src="@/assets/img/icon/me/loop.png" alt="">
|
||||
<img v-show="!isLoop" src="@/assets/img/icon/me/play-normal.png" alt="">
|
||||
<span>{{ isLoop ? '单曲循环' : '顺序播放' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
<div class="l-row"
|
||||
@click="play(index)"
|
||||
:class="{active:guessSlideIndex === index}"
|
||||
v-for="(item,index) in list">
|
||||
<div class="left">
|
||||
<img v-if="guessSlideIndex === index" src="@/assets/img/icon/me/pinlv.gif" alt="" class="play-icon">
|
||||
<div class="name">{{ item.name }}</div>
|
||||
<div class="author">{{ item.author }}</div>
|
||||
</div>
|
||||
<back class="right" mode="gray" img="close"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer" @click="isShowList = false">取消</div>
|
||||
</div>
|
||||
</from-bottom-dialog>
|
||||
|
||||
<Share v-model="isSharing"
|
||||
mode="my-music"
|
||||
ref="share"
|
||||
pageId="GuessMusic"
|
||||
@ShareToFriend="delayShowDialog( e => this.isShowShareToFriend = true)"
|
||||
/>
|
||||
|
||||
<ShareToFriend pageId="GuessMusic" v-model="isShowShareToFriend"/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import FromBottomDialog from "../../../components/dialog/FromBottomDialog";
|
||||
import Switches from "../../message/components/swtich/switches";
|
||||
import SlideItemMusic from "./SlideItemMusic";
|
||||
import IndicatorLight from "../../../components/slide/IndicatorLight";
|
||||
import SlideColumnList from "../../../components/slide/SlideColumnList";
|
||||
import Share from "../../../components/Share";
|
||||
import ShareToFriend from "../../home/components/ShareToFriend";
|
||||
|
||||
export default {
|
||||
name: "GuessMusic",
|
||||
components: {
|
||||
FromBottomDialog,
|
||||
Switches,
|
||||
SlideItemMusic,
|
||||
IndicatorLight,
|
||||
SlideColumnList,
|
||||
Share,
|
||||
ShareToFriend
|
||||
},
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
slideCanMove: true,
|
||||
isShowShareToFriend: false,
|
||||
isShowList: false,
|
||||
isSharing: false,
|
||||
isLoop: false,
|
||||
guessSlideIndex: 0,
|
||||
isShowCollectDialog: false,
|
||||
itemRefs: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
guessSlideIndex(newVal, oldVal) {
|
||||
this.itemRefs.map(ref => {
|
||||
ref.togglePlay(false)
|
||||
})
|
||||
this.itemRefs[newVal].togglePlay(true, true)
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
},
|
||||
methods: {
|
||||
previous() {
|
||||
if (this.guessSlideIndex > 0) {
|
||||
this.play(this.guessSlideIndex - 1)
|
||||
}
|
||||
},
|
||||
next() {
|
||||
if (this.guessSlideIndex < this.list.length - 1) {
|
||||
this.play(this.guessSlideIndex + 1)
|
||||
}
|
||||
},
|
||||
delayShowDialog(cb) {
|
||||
setTimeout(() => {
|
||||
cb()
|
||||
}, 100)
|
||||
},
|
||||
setItemRef(el) {
|
||||
if (el) {
|
||||
this.itemRefs.push(el)
|
||||
}
|
||||
},
|
||||
play(index) {
|
||||
this.guessSlideIndex = index
|
||||
this.itemRefs.map(ref => {
|
||||
ref.togglePlay(false)
|
||||
})
|
||||
this.itemRefs[index].togglePlay(true, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
@import "@/assets/less/index";
|
||||
|
||||
#GuessMusic {
|
||||
//width: 100vw;
|
||||
//height: 100vh;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
overflow: auto;
|
||||
color: white;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.music-list-dialog {
|
||||
height: 70vh;
|
||||
@bg-color: #1e1d1d;
|
||||
background: @bg-color;
|
||||
|
||||
.music-list-header {
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
background: @bg-color;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 1px solid #2a2828;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 5rem;
|
||||
padding: 0 @padding-page;
|
||||
border-radius: 1.5rem 1.5rem 0 0;
|
||||
z-index: 9;
|
||||
|
||||
.left {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.2rem;
|
||||
|
||||
img {
|
||||
width: 2rem;
|
||||
margin-right: .5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
padding-top: 5rem;
|
||||
}
|
||||
|
||||
.l-row {
|
||||
background: @bg-color;
|
||||
height: 5rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 @padding-page;
|
||||
|
||||
&.active {
|
||||
color: @primary-btn-color;
|
||||
}
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.author {
|
||||
font-size: 1.2rem;
|
||||
color: @second-text-color;
|
||||
margin-left: 2rem;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
width: .6rem;
|
||||
height: .5px;
|
||||
background: @second-text-color;
|
||||
position: absolute;
|
||||
left: -1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.play-icon {
|
||||
width: 1.5rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
width: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
background: @bg-color;
|
||||
border-top: 1px solid #2a2828;
|
||||
height: 6rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -12,7 +12,10 @@
|
||||
<!-- <div class="lyrics-mask" @click="isFullLyrics = true"></div>-->
|
||||
</div>
|
||||
<div class="lyrics-full" v-show="isFullLyrics" @click="isFullLyrics = false">
|
||||
<div class="list" style="overflow:auto;">
|
||||
<div class="list" style="overflow:auto;"
|
||||
@touchmove="$emit('slideCanMove', false)"
|
||||
@touchend="$emit('slideCanMove', true)"
|
||||
>
|
||||
<div class="item" v-for="item in lyricsFullTexts">{{ item.c }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -28,7 +31,7 @@
|
||||
<img src="@/assets/img/icon/star-yellow.png" v-show="isCollect" @click="isCollect = !isCollect">
|
||||
<span>收藏</span>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<div class="btn" @click="$emit('showShare')">
|
||||
<img src="@/assets/img/icon/share-white-full.png" alt="">
|
||||
<span>分享</span>
|
||||
</div>
|
||||
@ -48,17 +51,17 @@
|
||||
<div class="end">{{ $durationTime(duration) }}</div>
|
||||
</div>
|
||||
<div class="options">
|
||||
<img v-show="isLoop" src="@/assets/img/icon/me/loop.png" @click="isLoop = !isLoop">
|
||||
<img v-show="!isLoop" src="@/assets/img/icon/me/play-normal.png" @click="isLoop = !isLoop">
|
||||
<img v-show="isLoop" src="@/assets/img/icon/me/loop.png" @click="$emit('update:isLoop',false)">
|
||||
<img v-show="!isLoop" src="@/assets/img/icon/me/play-normal.png" @click="$emit('update:isLoop',true)">
|
||||
<div class="center">
|
||||
<img src="@/assets/img/icon/me/previous.png" @click="t">
|
||||
<img v-show="modelValue.is_play" class="control" src="@/assets/img/icon/me/pause.png"
|
||||
<img src="@/assets/img/icon/me/previous.png" @click="slide('previous')">
|
||||
<img v-show="isPlay" class="control" src="@/assets/img/icon/me/pause.png"
|
||||
@click="togglePlay()">
|
||||
<img v-show="!modelValue.is_play" class="control" src="@/assets/img/icon/me/play.png"
|
||||
<img v-show="!isPlay" class="control" src="@/assets/img/icon/me/play.png"
|
||||
@click="togglePlay()">
|
||||
<img src="@/assets/img/icon/me/next.png">
|
||||
<img src="@/assets/img/icon/me/next.png" @click="slide('next')">
|
||||
</div>
|
||||
<img src="@/assets/img/icon/me/music-list.png">
|
||||
<img src="@/assets/img/icon/me/music-list.png" @click="$emit('showList')">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -77,30 +80,19 @@ export default {
|
||||
default: function () {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
isLoop: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
slideIndex: 1,
|
||||
currentMusic: {
|
||||
name: '告白气球',
|
||||
mp3: 'https://mp32.9ku.com/upload/128/2017/02/05/858423.mp3',
|
||||
cover: require('../../../assets/img/music-cover/7.png'),
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false,
|
||||
},
|
||||
collectMusic: [],
|
||||
recommendMusic: [],
|
||||
guessMusic: [],
|
||||
lyricsTexts: [],
|
||||
lyricsFullTexts: [],
|
||||
isShowCollectDialog: false,
|
||||
isPlay: false,
|
||||
isAutoPlay: true,
|
||||
isLoop: false,
|
||||
isMove: false,
|
||||
isCollect: false,
|
||||
isFullLyrics: false,
|
||||
@ -127,12 +119,14 @@ export default {
|
||||
this.slideBarWidth = this.$refs.slideBar.clientWidth
|
||||
this.step = this.slideBarWidth / Math.floor(this.duration)
|
||||
})
|
||||
|
||||
let lrcObj = this.createLrcObj(gaobaiqiqiu);
|
||||
this.lyricsTexts.push(lrcObj.ms[0])
|
||||
this.lyricsTexts.push(lrcObj.ms[1])
|
||||
lrcObj.ms.map(v => {
|
||||
if (v.c) this.lyricsFullTexts.push(v)
|
||||
})
|
||||
|
||||
// console.log(lrcObj.ms)
|
||||
this.audio.addEventListener('timeupdate', e => {
|
||||
let currentTime = Math.ceil(e.target.currentTime)
|
||||
@ -170,10 +164,19 @@ export default {
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
togglePlay(state) {
|
||||
this.modelValue.is_play = state || !this.modelValue.is_play
|
||||
if (this.modelValue.is_play) {
|
||||
this.audio.play()
|
||||
slide(state) {
|
||||
this.togglePlay(false)
|
||||
this.$emit(state)
|
||||
},
|
||||
//TODO DOMException: The play() request was interrupted by a call to pause()
|
||||
//TODO page2会报错,能放歌但是进度条不动
|
||||
async togglePlay(state, reStart = false) {
|
||||
this.isPlay = state !== undefined ? state : !this.isPlay
|
||||
if (reStart) {
|
||||
this.audio.currentTime = 0
|
||||
}
|
||||
if (this.isPlay) {
|
||||
await this.audio.play()
|
||||
} else {
|
||||
this.audio.pause()
|
||||
}
|
||||
@ -303,6 +306,7 @@ export default {
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-shadow: 0 0 1.5rem .5rem #514f4f;
|
||||
}
|
||||
|
||||
}
|
||||
@ -412,11 +416,11 @@ export default {
|
||||
height: 2rem;
|
||||
width: 100%;
|
||||
top: -1rem;
|
||||
z-index: 11;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
&:before {
|
||||
z-index: 9;
|
||||
z-index: 8;
|
||||
content: ' ';
|
||||
height: 1.5px;
|
||||
width: 100%;
|
||||
@ -426,7 +430,7 @@ export default {
|
||||
}
|
||||
|
||||
.bar-line {
|
||||
z-index: 10;
|
||||
z-index: 9;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@ -436,7 +440,7 @@ export default {
|
||||
}
|
||||
|
||||
.bar-point {
|
||||
z-index: 10;
|
||||
z-index: 9;
|
||||
position: absolute;
|
||||
left: 50vw;
|
||||
top: -3px;
|
||||
|
||||
@ -57,7 +57,7 @@
|
||||
</div>
|
||||
<Footer v-bind:init-tab="4"/>
|
||||
|
||||
<from-bottom-dialog v-model="createChatDialog">
|
||||
<from-bottom-dialog page-id="Message" v-model="createChatDialog">
|
||||
<div class="create-chat-wrapper" v-show="!showJoinedChat">
|
||||
<Search :isShowText="isShowText"
|
||||
@click="isShowText = true"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<from-bottom-dialog
|
||||
page-id="home-index"
|
||||
v-model="modelValue"
|
||||
:show-heng-gang="false"
|
||||
height="20rem"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="FindAcquaintance">
|
||||
<div class="FindAcquaintance" id="FindAcquaintance">
|
||||
<div class="header">
|
||||
<back mode="light" @click="back"></back>
|
||||
<Indicator
|
||||
@ -80,6 +80,7 @@
|
||||
</transition>
|
||||
|
||||
<from-bottom-dialog
|
||||
page-id="FindAcquaintance"
|
||||
v-model="moreOptionDialog"
|
||||
:show-heng-gang="false"
|
||||
height="21rem"
|
||||
|
||||
@ -16,6 +16,27 @@ export default class Dom {
|
||||
return this
|
||||
}
|
||||
|
||||
addClass(class1) {
|
||||
if (typeof class1 === 'string') {
|
||||
this.els.forEach(el => {
|
||||
el.classList.add(class1)
|
||||
})
|
||||
} else {
|
||||
this.els.forEach(el => {
|
||||
el.classList.add(...class1)
|
||||
})
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
replaceClass(class1, class2) {
|
||||
this.els.forEach(el => {
|
||||
el.classList.replace(class1, class2)
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
find(tag) {
|
||||
let els = []
|
||||
if (this.els.length) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user