239 lines
6.0 KiB
Vue
239 lines
6.0 KiB
Vue
<template>
|
|
<div class="buttons">
|
|
<transition name="fade">
|
|
<div
|
|
title="返回顶部"
|
|
class="button go-to-top iconfont icon-fanhuidingbu"
|
|
v-show="showToTop"
|
|
@click="scrollToTop"
|
|
/>
|
|
</transition>
|
|
<div
|
|
title="去评论"
|
|
class="button go-to-comment iconfont icon-pinglun"
|
|
v-show="showCommentBut"
|
|
@click="scrollToComment"
|
|
/>
|
|
<div
|
|
title="主题模式"
|
|
class="button theme-mode-but iconfont icon-zhuti"
|
|
@mouseenter="showModeBox = true"
|
|
@mouseleave="showModeBox = false"
|
|
@click="showModeBox = true"
|
|
>
|
|
<transition name="mode">
|
|
<ul class="select-box" ref="modeBox" v-show="showModeBox" @click.stop>
|
|
<li
|
|
v-for="item in modeList"
|
|
:key="item.KEY"
|
|
class="iconfont"
|
|
:class="[item.icon, {active: item.KEY === currentMode}]"
|
|
@click="toggleMode(item.KEY)"
|
|
>
|
|
{{item.name}}
|
|
</li>
|
|
</ul>
|
|
</transition>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import debounce from 'lodash.debounce'
|
|
import storage from 'good-storage' // 本地存储
|
|
const MOBILE_DESKTOP_BREAKPOINT = 719 // refer to config.styl
|
|
|
|
export default {
|
|
data() {
|
|
return {
|
|
threshold: 100,
|
|
scrollTop: null,
|
|
showCommentBut: false,
|
|
commentTop: null,
|
|
currentMode: null,
|
|
showModeBox: false,
|
|
modeList: [
|
|
{
|
|
name: '跟随系统',
|
|
icon: 'icon-zidong',
|
|
KEY: 'auto'
|
|
},
|
|
{
|
|
name: '浅色模式',
|
|
icon: 'icon-rijianmoshi',
|
|
KEY: 'light'
|
|
},
|
|
{
|
|
name: '深色模式',
|
|
icon: 'icon-yejianmoshi',
|
|
KEY: 'dark'
|
|
},
|
|
{
|
|
name: '阅读模式',
|
|
icon: 'icon-yuedu',
|
|
KEY: 'read'
|
|
}
|
|
],
|
|
_scrollTimer: null,
|
|
_textareaEl: null,
|
|
_recordScrollTop: null,
|
|
COMMENT_SELECTOR: '#vuepress-plugin-comment' // 评论区元素的选择器
|
|
}
|
|
},
|
|
mounted () {
|
|
this.currentMode = storage.get('mode') || 'auto'
|
|
|
|
this.scrollTop = this.getScrollTop()
|
|
window.addEventListener('scroll', debounce(() => {
|
|
this.scrollTop = this.getScrollTop()
|
|
}, 100))
|
|
|
|
this.handleShowCommentBut()
|
|
window.addEventListener('load', () => {
|
|
this.getCommentTop()
|
|
})
|
|
|
|
// 小屏时选择主题模式后关闭选择框
|
|
if (document.documentElement.clientWidth < MOBILE_DESKTOP_BREAKPOINT) {
|
|
const modeBox = this.$refs.modeBox
|
|
modeBox.onclick = () => {
|
|
this.showModeBox = false
|
|
}
|
|
window.addEventListener('scroll', debounce(() => {
|
|
if(this.showModeBox) {
|
|
this.showModeBox = false
|
|
}
|
|
}, 100))
|
|
}
|
|
},
|
|
computed: {
|
|
showToTop () {
|
|
return this.scrollTop > this.threshold
|
|
}
|
|
},
|
|
methods: {
|
|
toggleMode(key){
|
|
this.currentMode = key
|
|
this.$emit('toggle-theme-mode', key)
|
|
},
|
|
getScrollTop () {
|
|
return window.pageYOffset
|
|
|| document.documentElement.scrollTop
|
|
|| document.body.scrollTop || 0
|
|
},
|
|
|
|
scrollToTop () {
|
|
window.scrollTo({ top: 0, behavior: 'smooth' })
|
|
this.scrollTop = 0
|
|
},
|
|
|
|
getCommentTop () {
|
|
setTimeout(() => {
|
|
const commentEl = document.querySelector(this.COMMENT_SELECTOR)
|
|
if (commentEl) {
|
|
this.commentTop = commentEl.offsetTop
|
|
} else {
|
|
this.showCommentBut = false
|
|
}
|
|
},500)
|
|
},
|
|
|
|
handleShowCommentBut() {
|
|
this.showCommentBut = this.$frontmatter.comment !== false && this.$frontmatter.home !== true
|
|
},
|
|
|
|
scrollToComment() {
|
|
window.scrollTo({ top: this.commentTop, behavior: 'smooth' })
|
|
this._textareaEl = document.querySelector(this.COMMENT_SELECTOR + ' textarea')
|
|
if( this._textareaEl && this.getScrollTop() !== this._recordScrollTop) {
|
|
document.addEventListener("scroll", this._handleListener)
|
|
} else if (this._textareaEl && this.getScrollTop() === this._recordScrollTop) {
|
|
this._handleFocus()
|
|
}
|
|
},
|
|
|
|
_handleListener() {
|
|
clearTimeout(this._scrollTimer)
|
|
this._scrollTimer = setTimeout(() => {
|
|
document.removeEventListener('scroll', this._handleListener)
|
|
this._recordScrollTop = this.getScrollTop()
|
|
this._handleFocus()
|
|
}, 30)
|
|
},
|
|
|
|
_handleFocus() {
|
|
this._textareaEl.focus()
|
|
this._textareaEl.classList.add('yellowBorder')
|
|
setTimeout(() => {
|
|
this._textareaEl.classList.remove('yellowBorder')
|
|
}, 500)
|
|
}
|
|
},
|
|
watch: {
|
|
$route() {
|
|
this.handleShowCommentBut()
|
|
this.getCommentTop()
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang='stylus'>
|
|
.yellowBorder
|
|
border: #FFE089 1px solid!important
|
|
box-shadow 0 0 10px #FFE089!important
|
|
.buttons
|
|
position fixed
|
|
right 2rem
|
|
bottom 2.5rem
|
|
z-index 11
|
|
@media (max-width: $MQNarrow)
|
|
right 1rem
|
|
bottom 1.5rem
|
|
.button
|
|
width 2.2rem
|
|
height 2.2rem
|
|
line-height 2.2rem
|
|
border-radius 50%
|
|
box-shadow 0 2px 6px rgba(0,0,0,.25)
|
|
margin-top .9rem
|
|
text-align center
|
|
cursor pointer
|
|
// color var(--textLightenColor)
|
|
background rgba(255,255,255,.1)
|
|
&:hover
|
|
&:before
|
|
color $accentColor
|
|
.select-box
|
|
margin 0
|
|
padding .5rem 0
|
|
position absolute
|
|
bottom 0rem
|
|
right 1.5rem
|
|
background var(--bg)
|
|
border 1px solid var(--borderColor)
|
|
width 100px
|
|
border-radius 3px
|
|
box-shadow 0 2px 6px rgba(0,0,0,.25)
|
|
li
|
|
list-style none
|
|
line-height 1.8rem
|
|
font-size .95rem
|
|
&:hover
|
|
color $accentColor
|
|
&.active
|
|
background-color rgba(150,150,150,.2)
|
|
color $accentColor
|
|
|
|
.mode-enter-active, .mode-leave-active
|
|
transition all .3s
|
|
.mode-enter, .mode-leave-to
|
|
opacity 0
|
|
transform scale(.8)
|
|
|
|
.fade-enter-active, .fade-leave-active
|
|
transition opacity .2s
|
|
.fade-enter, .fade-leave-to
|
|
opacity 0
|
|
</style>
|