Files
hcframe-doc/theme-vdoing/components/Buttons.vue
2021-02-03 17:01:33 +08:00

263 lines
6.9 KiB
Vue

<template>
<div class="buttons">
<transition name="fade">
<div
title="返回顶部"
class="button blur go-to-top iconfont icon-fanhuidingbu"
v-show="showToTop"
@click="scrollToTop"
/>
</transition>
<div
title="去评论"
class="button blur go-to-comment iconfont icon-pinglun"
v-show="showCommentBut"
@click="scrollToComment"
/>
<div
title="主题模式"
class="button blur 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
@touchstart.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_1: '#vuepress-plugin-comment', // 评论区元素的选择器1
COMMENT_SELECTOR_2: '#valine-vuepress-comment', // 评论区元素的选择器2
COMMENT_SELECTOR_3: '.vssue' // 评论区元素的选择器3
}
},
mounted () {
this.currentMode = storage.get('mode') || 'auto'
this.scrollTop = this.getScrollTop()
window.addEventListener('scroll', debounce(() => {
this.scrollTop = this.getScrollTop()
}, 100))
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))
}
// 移动端对类似:hover效果的处理
const buttons = document.querySelectorAll('.buttons .button')
for (let i = 0; i < buttons.length; i++) {
const button = buttons[i]
button.addEventListener('touchstart', function () {
button.classList.add('hover')
})
button.addEventListener('touchend', function () {
setTimeout(() => {
button.classList.remove('hover')
}, 150)
})
}
},
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(() => {
let commentEl = document.querySelector(this.COMMENT_SELECTOR_1) || document.querySelector(this.COMMENT_SELECTOR_2) || document.querySelector(this.COMMENT_SELECTOR_3)
if (commentEl) {
this.showCommentBut = this.$frontmatter.comment !== false && this.$frontmatter.home !== true
this.commentTop = commentEl.offsetTop - 58
}
}, 500)
},
scrollToComment () {
window.scrollTo({ top: this.commentTop, behavior: 'smooth' })
this._textareaEl = document.querySelector(this.COMMENT_SELECTOR_1 + ' textarea') || document.querySelector(this.COMMENT_SELECTOR_2 + ' input') || document.querySelector(this.COMMENT_SELECTOR_3 + ' 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.path' () {
this.showCommentBut = false
this.getCommentTop()
}
}
}
</script>
<style lang='stylus'>
.yellowBorder
// border: #FFE089 1px solid!important
border-radius 5px
box-shadow 0 0 15px #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, 0.15)
margin-top 0.9rem
text-align center
cursor pointer
transition all 0.5s
background var(--blurBg)
&.hover
background $accentColor
box-shadow 0 0 15px $accentColor
&:before
color #fff
@media (any-hover hover)
&:hover
background $accentColor
box-shadow 0 0 15px $accentColor
&:before
color #fff
.select-box
margin 0
padding 0.8rem 0
position absolute
bottom 0rem
right 1.5rem
background var(--mainBg)
border 1px solid var(--borderColor)
width 120px
border-radius 6px
box-shadow 0 0 15px rgba(255, 255, 255, 0.2)
li
list-style none
line-height 2rem
font-size 0.95rem
&:hover
color $accentColor
&.active
background-color rgba(150, 150, 150, 0.2)
color $accentColor
.mode-enter-active, .mode-leave-active
transition all 0.3s
.mode-enter, .mode-leave-to
opacity 0
transform scale(0.8)
.fade-enter-active, .fade-leave-active
transition opacity 0.2s
.fade-enter, .fade-leave-to
opacity 0
</style>