把歌曲的热门评论与最新评论拆分成两个列表显示

pull/930/merge
lyswhut 2022-02-11 19:38:51 +08:00
parent 777551cb43
commit 055ab98d4c
3 changed files with 217 additions and 68 deletions

View File

@ -1,8 +1,12 @@
### 新增
- 新增“双击列表里的歌曲时自动切换到当前列表播放”设置,此功能仅对歌单、排行榜有效,默认关闭
- 新增打开收藏的在线列表的对应平台详情页功能,可以在我的列表-列表右键菜单中使用
### 优化 ### 优化
- 过滤tx源某些不支持播放的歌曲解决播放此类内容会导致意外的问题 - 过滤tx源某些不支持播放的歌曲解决播放此类内容会导致意外的问题
- 新增“双击列表里的歌曲时自动切换到当前列表播放”设置,此功能仅对歌单、排行榜有效,默认关闭 - 把歌曲的热门评论与最新评论拆分成两个列表显示
- 新增打开收藏的在线列表的对应平台详情页功能,可以在我的列表-列表右键菜单中使用
### 修复 ### 修复

View File

@ -10,26 +10,31 @@ div.comment(:class="$style.comment")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 24 24' space='preserve') svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 24 24' space='preserve')
use(xlink:href='#icon-close') use(xlink:href='#icon-close')
div.scroll(:class="$style.commentMain" ref="dom_comment") div(:class="$style.commentMain")
div(v-if="page == 1") header(:class="$style.tab_header")
h2(:class="$style.commentType") {{$t('comment__hot_title')}} button(type="button" @click="handleToggleTab('hot')" :class="[$style.commentType, { [$style.active]: tabActiveId == 'hot' }]") {{$t('comment__hot_title')}} ({{hotComment.total}})
p(:class="$style.commentLabel" style="cursor: pointer;" v-if="isHotLoadError" @click="handleGetHotComment(currentMusicInfo)") {{$t('comment__hot_load_error')}} button(type="button" @click="handleToggleTab('new')" :class="[$style.commentType, { [$style.active]: tabActiveId == 'new' }]") {{$t('comment__new_title')}} ({{newComment.total}})
p(:class="$style.commentLabel" v-else-if="isHotLoading && !hotComments.length") {{$t('comment__hot_loading')}} main(:class="$style.tab_main" ref="dom_tabMain")
comment-floor(v-if="!isHotLoadError && hotComments.length" :class="[$style.commentFloor, isHotLoading ? $style.loading : null]" :comments="hotComments") div(:class="$style.tab_container")
p(:class="$style.commentLabel" v-else-if="!isHotLoadError && !isHotLoading") {{$t('comment__no_content')}} div.scroll(:class="$style.tab_content" ref="dom_commentHot")
div p(:class="$style.commentLabel" style="cursor: pointer;" v-if="hotComment.isLoadError" @click="handleGetHotComment(currentMusicInfo, hotComment.nextPage, hotComment.limit)") {{$t('comment__hot_load_error')}}
h2(:class="$style.commentType") {{$t('comment__new_title')}} ({{total}}) p(:class="$style.commentLabel" v-else-if="hotComment.isLoading && !hotComment.list.length") {{$t('comment__hot_loading')}}
p(:class="$style.commentLabel" style="cursor: pointer;" v-if="isNewLoadError" @click="handleGetNewComment(currentMusicInfo, nextPage, limit)") {{$t('comment__new_load_error')}} comment-floor(v-if="!hotComment.isLoadError && hotComment.list.length" :class="[$style.commentFloor, hotComment.isLoading ? $style.loading : null]" :comments="hotComment.list")
p(:class="$style.commentLabel" v-else-if="isNewLoading && !newComments.length") {{$t('comment__new_loading')}} p(:class="$style.commentLabel" v-else-if="!hotComment.isLoadError && !hotComment.isLoading") {{$t('comment__no_content')}}
comment-floor(v-if="!isNewLoadError && newComments.length" :class="[$style.commentFloor, isNewLoading ? $style.loading : null]" :comments="newComments") div(:class="$style.pagination")
p(:class="$style.commentLabel" v-else-if="!isNewLoadError && !isNewLoading") {{$t('comment__no_content')}} material-pagination(:count="hotComment.total" :btnLength="5" :limit="hotComment.limit" :page="hotComment.page" @btn-click="handleToggleHotCommentPage")
div(:class="$style.pagination") div.scroll(:class="$style.tab_content" ref="dom_commentNew")
material-pagination(:count="total" :btnLength="5" :limit="limit" :page="page" @btn-click="handleToggleCommentPage") p(:class="$style.commentLabel" style="cursor: pointer;" v-if="newComment.isLoadError" @click="handleGetNewComment(currentMusicInfo, newComment.nextPage, newComment.limit)") {{$t('comment__new_load_error')}}
p(:class="$style.commentLabel" v-else-if="newComment.isLoading && !newComment.list.length") {{$t('comment__new_loading')}}
comment-floor(v-if="!newComment.isLoadError && newComment.list.length" :class="[$style.commentFloor, newComment.isLoading ? $style.loading : null]" :comments="newComment.list")
p(:class="$style.commentLabel" v-else-if="!newComment.isLoadError && !newComment.isLoading") {{$t('comment__no_content')}}
div(:class="$style.pagination")
material-pagination(:count="newComment.total" :btnLength="5" :limit="newComment.limit" :page="newComment.page" @btn-click="handleToggleCommentPage")
</template> </template>
<script> <script>
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { scrollTo } from '@renderer/utils' import { scrollTo, scrollXTo } from '@renderer/utils'
import music from '@renderer/utils/music' import music from '@renderer/utils/music'
import CommentFloor from './CommentFloor' import CommentFloor from './CommentFloor'
@ -52,16 +57,16 @@ export default {
name: '', name: '',
singer: '', singer: '',
}, },
page: 1, tabActiveId: 'hot',
total: 0, newComment: {
maxPage: 1, isLoading: false,
limit: 20, isLoadError: false,
isHotLoading: true, page: 1,
isNewLoading: false, total: 0,
isHotLoadError: true, maxPage: 1,
isNewLoadError: false, nextPage: 1,
nextPage: 1, limit: 20,
newComments: [ list: [
// { // {
// text: ['123123hhh'], // text: ['123123hhh'],
// userName: 'dsads', // userName: 'dsads',
@ -71,8 +76,17 @@ export default {
// likedCount: 100, // likedCount: 100,
// reply: [], // reply: [],
// }, // },
], ],
hotComments: [ },
hotComment: {
isLoading: true,
isLoadError: true,
page: 1,
total: 0,
maxPage: 1,
nextPage: 1,
limit: 20,
list: [
// { // {
// text: ['123123hhh'], // text: ['123123hhh'],
// userName: 'dsads', // userName: 'dsads',
@ -91,7 +105,8 @@ export default {
// }, // },
// ], // ],
// }, // },
], ],
},
} }
}, },
computed: { computed: {
@ -118,65 +133,92 @@ export default {
} }
return resp return resp
}, },
async getHotComment(musicInfo, retryNum = 0) { async getHotComment(musicInfo, page, limit, retryNum = 0) {
let resp let resp
try { try {
resp = await music[musicInfo.source].comment.getHotComment(musicInfo) resp = await music[musicInfo.source].comment.getHotComment(musicInfo, page, limit)
} catch (error) { } catch (error) {
if (error.message == '取消请求' || ++retryNum > 2) throw error if (error.message == '取消请求' || ++retryNum > 2) throw error
resp = await this.getHotComment(musicInfo, retryNum) resp = await this.getHotComment(musicInfo, page, limit, retryNum)
} }
return resp return resp
}, },
handleGetNewComment(musicInfo, page, limit) { handleGetNewComment(musicInfo, page, limit) {
this.isNewLoadError = false this.newComment.isLoadError = false
this.isNewLoading = true this.newComment.isLoading = true
this.getComment(musicInfo, page, limit).then(comment => { this.getComment(musicInfo, page, limit).then(comment => {
this.isNewLoading = false this.newComment.isLoading = false
this.total = comment.total this.newComment.total = comment.total
this.maxPage = comment.maxPage this.newComment.maxPage = comment.maxPage
this.page = page this.newComment.page = page
this.newComments = comment.comments this.newComment.list = comment.comments
this.$nextTick(() => { this.$nextTick(() => {
scrollTo(this.$refs.dom_comment, 0, 300) scrollTo(this.$refs.dom_commentNew, 0, 300)
}) })
}).catch(err => { }).catch(err => {
console.log(err) console.log(err)
if (err.message == '取消请求') return if (err.message == '取消请求') return
this.isNewLoadError = true this.newComment.isLoadError = true
this.isNewLoading = false this.newComment.isLoading = false
}) })
}, },
handleGetHotComment(musicInfo) { handleGetHotComment(musicInfo, page, limit) {
this.isHotLoadError = false this.hotComment.isLoadError = false
this.isHotLoading = true this.hotComment.isLoading = true
this.getHotComment(musicInfo).then(hotComment => { this.getHotComment(musicInfo, page, limit).then(hotComment => {
this.isHotLoading = false this.hotComment.isLoading = false
this.hotComments = hotComment.comments this.hotComment.total = hotComment.total
this.hotComment.maxPage = hotComment.maxPage
this.hotComment.page = page
this.hotComment.list = hotComment.comments
this.$nextTick(() => {
scrollTo(this.$refs.dom_commentHot, 0, 300)
})
}).catch(err => { }).catch(err => {
console.log(err) console.log(err)
if (err.message == '取消请求') return if (err.message == '取消请求') return
this.isHotLoadError = true this.hotComment.isLoadError = true
this.isHotLoading = false this.hotComment.isLoading = false
}) })
}, },
handleShowComment() { handleShowComment() {
if (!this.musicInfo.songmid || !music[this.musicInfo.source].comment) return if (!this.musicInfo.songmid || !music[this.musicInfo.source].comment) return
// if (this.musicInfo.songmid != this.currentMusicInfo.songmid) { // if (this.musicInfo.songmid != this.currentMusicInfo.songmid) {
this.page = 1 this.hotComment.page = 1
this.total = 0 this.hotComment.total = 0
this.maxPage = 1 this.hotComment.maxPage = 1
this.nextPage = 1 this.hotComment.nextPage = 1
this.newComment.page = 1
this.newComment.total = 0
this.newComment.maxPage = 1
this.newComment.nextPage = 1
// } // }
this.isShowComment = true this.isShowComment = true
this.currentMusicInfo = this.musicInfo this.currentMusicInfo = this.musicInfo
if (this.page == 1) this.handleGetHotComment(this.currentMusicInfo) this.handleGetHotComment(this.currentMusicInfo, this.hotComment.page, this.hotComment.limit)
this.handleGetNewComment(this.currentMusicInfo, this.page, this.limit) this.handleGetNewComment(this.currentMusicInfo, this.newComment.page, this.newComment.limit)
},
handleToggleHotCommentPage(page) {
this.hotComment.nextPage = page
this.handleGetHotComment(this.currentMusicInfo, page, this.hotComment.limit)
}, },
handleToggleCommentPage(page) { handleToggleCommentPage(page) {
this.nextPage = page this.newComment.nextPage = page
this.handleGetNewComment(this.currentMusicInfo, page, this.limit) this.handleGetNewComment(this.currentMusicInfo, page, this.newComment.limit)
},
handleToggleTab(id) {
if (this.tabActiveId == id) return
switch (id) {
case 'hot':
scrollXTo(this.$refs.dom_tabMain, 0)
break
case 'new':
scrollXTo(this.$refs.dom_tabMain, this.$refs.dom_tabMain.clientWidth)
break
}
this.tabActiveId = id
}, },
}, },
} }
@ -229,10 +271,38 @@ export default {
} }
.commentMain { .commentMain {
flex: auto; flex: auto;
padding-left: 15px;
padding-right: 10px;
background-color: @color-reply-floor; background-color: @color-reply-floor;
border-radius: 4px; border-radius: 4px;
display: flex;
flex-direction: column;
}
.tab_header {
display: flex;
flex-flow: row nowrap;
gap: 15px;
padding-left: 15px;
padding-right: 10px;
}
.tab_main {
flex: auto;
// display: flex;
// flex-flow: row nowrap;
position: relative;
overflow: hidden;
}
.tab_container {
position: absolute;
left: 0;
top: 0;
width: 200%;
height: 100%;
display: flex;
flex-flow: row nowrap;
}
.tab_content {
width: 100%;
padding-left: 15px;
padding-right: 10px;
} }
.commentLabel { .commentLabel {
padding: 15px; padding: 15px;
@ -240,9 +310,20 @@ export default {
font-size: 14px; font-size: 14px;
} }
.commentType { .commentType {
padding: 10px 0; padding: 5px;
margin: 5px 0;
font-size: 13px; font-size: 13px;
color: @color-theme; background: none;
border: none;
cursor: pointer;
transition: @transition-theme;
transition-property: opacity, color;
&:hover {
opacity: .7;
}
&.active {
color: @color-theme;
}
} }
.commentFloor { .commentFloor {
opacity: 1; opacity: 1;
@ -268,7 +349,9 @@ each(@themes, {
color: ~'@{color-@{value}-theme_2-font-label}'; color: ~'@{color-@{value}-theme_2-font-label}';
} }
.commentType { .commentType {
color: ~'@{color-@{value}-theme}'; &.active {
color: ~'@{color-@{value}-theme}';
}
} }
} }
}) })

View File

@ -93,7 +93,7 @@ const easeInOutQuad = (t, b, c, d) => {
t-- t--
return (-c / 2) * (t * (t - 2) - 1) + b return (-c / 2) * (t * (t - 2) - 1) + b
} }
const handleScroll = (element, to, duration = 300, fn = () => {}) => { const handleScrollY = (element, to, duration = 300, fn = () => {}) => {
if (!element) return fn() if (!element) return fn()
const start = element.scrollTop || element.scrollY || 0 const start = element.scrollTop || element.scrollY || 0
let cancel = false let cancel = false
@ -148,10 +148,72 @@ export const scrollTo = (element, to, duration = 300, fn = () => {}, delay = 0)
} }
timeout = setTimeout(() => { timeout = setTimeout(() => {
timeout = null timeout = null
scrollCancelFn = handleScroll(element, to, duration, fn, delay) scrollCancelFn = handleScrollY(element, to, duration, fn, delay)
}, delay) }, delay)
} else { } else {
cancelFn = handleScroll(element, to, duration, fn, delay) cancelFn = handleScrollY(element, to, duration, fn, delay)
}
return cancelFn
}
const handleScrollX = (element, to, duration = 300, fn = () => {}) => {
if (!element) return fn()
const start = element.scrollLeft || element.scrollX || 0
let cancel = false
if (to > start) {
let maxScrollLeft = element.scrollWidth - element.clientWidth
if (to > maxScrollLeft) to = maxScrollLeft
} else if (to < start) {
if (to < 0) to = 0
} else return fn()
const change = to - start
const increment = 10
if (!change) return fn()
let currentTime = 0
let val
const animateScroll = () => {
currentTime += increment
val = parseInt(easeInOutQuad(currentTime, start, change, duration))
if (element.scrollTo) {
element.scrollTo(val, 0)
} else {
element.scrollLeft = val
}
if (currentTime < duration) {
if (cancel) return fn()
setTimeout(animateScroll, increment)
} else {
fn()
}
}
animateScroll()
return () => {
cancel = true
}
}
/**
* 设置滚动条位置
* @param {*} element 要设置滚动的容器 dom
* @param {*} to 滚动的目标位置
* @param {*} duration 滚动完成时间 ms
* @param {*} fn 滚动完成后的回调
* @param {*} delay 延迟执行时间
*/
export const scrollXTo = (element, to, duration = 300, fn = () => {}, delay = 0) => {
let cancelFn
let timeout
if (delay) {
let scrollCancelFn
cancelFn = () => {
timeout == null ? scrollCancelFn && scrollCancelFn() : clearTimeout(timeout)
}
timeout = setTimeout(() => {
timeout = null
scrollCancelFn = handleScrollX(element, to, duration, fn, delay)
}, delay)
} else {
cancelFn = handleScrollX(element, to, duration, fn, delay)
} }
return cancelFn return cancelFn
} }