345 lines
9.1 KiB
Vue
345 lines
9.1 KiB
Vue
<template lang="pug">
|
|
div
|
|
article.articleDetails
|
|
.articleTitle
|
|
| {{ Articels.post_title }}
|
|
.articalMeta
|
|
ul
|
|
li
|
|
Icon(:icon="['far', 'calendar-alt']")
|
|
| {{ Articels.post_date }}
|
|
li
|
|
Icon(:icon="['far', 'bookmark']")
|
|
nuxt-link(v-for='(relationships, index) in Articels.term_relationships', :key='index', v-if='relationships.term_taxonomy', :to="'/' + relationships.term_taxonomy.term.slug")
|
|
span
|
|
| {{ relationships.term_taxonomy.term.name }}
|
|
li(v-if='Articels.postmetum.meta_value !== 0')
|
|
Icon(:icon="['fas', 'thermometer-' + Articels.hotValue]")
|
|
| {{ Articels.postmetum.meta_value }}
|
|
#articelToc.articelToc(v-if="Articels.post_toc_show")
|
|
.articelTitle 目录
|
|
.articelTocList(v-html="Articels.post_toc")
|
|
.articelContent(v-html='Articels.post_content')
|
|
.articelRightToc(v-show="Articels.post_toc_show && showRightToc", @click="articelRightTocClick")
|
|
.articelTitle 目录
|
|
.articelTocList(v-html="Articels.post_toc")
|
|
nuxt-link(:to="Articels.last ? '/post/' + Articels.last.ID : ''")
|
|
.btnFooter.btnPrevt(:style="'color: ' + (Articels.last ? '#333' : '#ccc')")
|
|
Icon(:icon="['fas', 'chevron-left']")
|
|
| 上一篇 {{ Articels.last ? '(' + decodeURIComponent(Articels.last.post_name) + ')' : ''}}
|
|
nuxt-link(:to="Articels.next ? '/post/' + Articels.next.ID : ''")
|
|
.btnFooter.btnNext(:style="'color: ' + (Articels.next ? '#333' : '#ccc')")
|
|
| 下一篇 {{ Articels.next ? '(' + decodeURIComponent(Articels.next.post_name) + ')' : ''}}
|
|
Icon(:icon="['fas', 'chevron-right']")
|
|
.comment
|
|
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
async asyncData({ route, app, $axios }) {
|
|
const data = await $axios.$get(`/public/article/details?id=${route.params.id}`)
|
|
const result = data.result
|
|
result.post_date = app.$moment(result.post_date).utc().format('lll')// 格式化时间
|
|
// 热度值计算
|
|
if (result.postmetum !== null && result.postmetum !== '') {
|
|
result.hotValue = app.$getHatValue(result.postmetum.meta_value)
|
|
} else {
|
|
result.hotValue = 0
|
|
result.postmetum = {}
|
|
result.postmetum.meta_value = 0
|
|
}
|
|
|
|
return {
|
|
Articels: result,
|
|
showRightToc: false,
|
|
tocIds: result.post_toc_ids
|
|
}
|
|
},
|
|
head() {
|
|
return {
|
|
title: `${this.Articels.post_title} - 轶哥博客`
|
|
}
|
|
},
|
|
mounted() {
|
|
this.$finishLoad()
|
|
|
|
if (this.Articels.post_toc_show) {
|
|
const tocShow = () => {
|
|
if (window.addEvent) {
|
|
window.addEvent(window, 'scroll', () => {
|
|
const windowWidth = window.innerWidth || document.documentElement.clientWidth
|
|
if (document.getElementById('articelToc') && !this.isOnScreen(document.getElementById('articelToc'))) {
|
|
if (windowWidth < 768) {
|
|
this.showRightToc = false
|
|
document.getElementById('mobileToc').style.display = 'block'
|
|
} else {
|
|
this.showRightToc = true
|
|
}
|
|
} else {
|
|
this.showRightToc = false
|
|
if (windowWidth < 768) {
|
|
document.getElementById('mobileToc').style.display = 'none'
|
|
}
|
|
}
|
|
})
|
|
} else {
|
|
setTimeout(() => {
|
|
tocShow()
|
|
}, 50)
|
|
}
|
|
}
|
|
tocShow()
|
|
|
|
const tocIdsTop = []
|
|
const tocIdsTopMap = new Map()
|
|
for (const n in this.tocIds) {
|
|
const tTop = document.getElementById(this.tocIds[n]).offsetTop
|
|
tocIdsTop.push(tTop)
|
|
tocIdsTopMap.set(tTop, '#' + this.tocIds[n])
|
|
}
|
|
console.log(tocIdsTop)
|
|
|
|
const findInIds = (arr, num) => { for (let x = 0; x < arr.length; x++) { if (arr[x] > num) { return x - 1 } } }
|
|
|
|
let debounce = null
|
|
let lastIdInx = null
|
|
|
|
const scrollToc = () => {
|
|
let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop
|
|
const windowWidth = window.innerWidth || document.documentElement.clientWidth
|
|
if (windowWidth < 768) scrollTop = scrollTop * 2.7 + 175
|
|
const tocIdsInx = findInIds(tocIdsTop, scrollTop + 130)
|
|
if (tocIdsInx !== -1 && lastIdInx !== tocIdsInx && document.getElementsByClassName('articelRightToc')[0]) {
|
|
const tocAList = document.getElementsByClassName('articelRightToc')[0].getElementsByTagName('a')
|
|
const nowId = tocIdsTopMap.get(tocIdsTop[tocIdsInx])
|
|
for (const i in tocAList) {
|
|
if (tocAList[i] && tocAList[i].getAttribute && tocAList[i].getAttribute('href') === nowId) {
|
|
tocAList[i].style.color = '#ff8a8a'
|
|
} else if (tocAList[i] && tocAList[i].style) {
|
|
tocAList[i].style.color = '#bbb'
|
|
}
|
|
}
|
|
lastIdInx = tocIdsInx
|
|
}
|
|
}
|
|
window.addEvent(window, 'scroll', () => {
|
|
clearTimeout(debounce)
|
|
debounce = setTimeout(() => {
|
|
scrollToc()
|
|
}, 20)
|
|
})
|
|
|
|
document.getElementById('mobileToc').onclick = () => {
|
|
this.showRightToc = !this.showRightToc
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
articelRightTocClick() {
|
|
const windowWidth = window.innerWidth || document.documentElement.clientWidth
|
|
if (windowWidth < 768) {
|
|
this.showRightToc = false
|
|
}
|
|
},
|
|
isOnScreen(element) {
|
|
const ON_SCREEN_HEIGHT = 50
|
|
const ON_SCREEN_WIDTH = 50
|
|
|
|
const rect = element.getBoundingClientRect()
|
|
const windowHeight = window.innerHeight || document.documentElement.clientHeight
|
|
const windowWidth = window.innerWidth || document.documentElement.clientWidth
|
|
|
|
const elementHeight = element.offsetHeight
|
|
const elementWidth = element.offsetWidth
|
|
|
|
const onScreenHeight = ON_SCREEN_HEIGHT > elementHeight ? elementHeight : ON_SCREEN_HEIGHT
|
|
const onScreenWidth = ON_SCREEN_WIDTH > elementWidth ? elementWidth : ON_SCREEN_WIDTH
|
|
|
|
// 元素在屏幕上方
|
|
const elementBottomToWindowTop = rect.top + elementHeight
|
|
const bottomBoundingOnScreen = elementBottomToWindowTop >= onScreenHeight
|
|
|
|
// 元素在屏幕下方
|
|
const elementTopToWindowBottom = windowHeight - (rect.bottom - elementHeight)
|
|
const topBoundingOnScreen = elementTopToWindowBottom >= onScreenHeight
|
|
|
|
// 元素在屏幕左侧
|
|
const elementRightToWindowLeft = rect.left + elementWidth
|
|
const rightBoundingOnScreen = elementRightToWindowLeft >= onScreenWidth
|
|
|
|
// 元素在屏幕右侧
|
|
const elementLeftToWindowRight = windowWidth - (rect.right - elementWidth)
|
|
const leftBoundingOnScreen = elementLeftToWindowRight >= onScreenWidth
|
|
|
|
return bottomBoundingOnScreen && topBoundingOnScreen && rightBoundingOnScreen && leftBoundingOnScreen
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="stylus" socped>
|
|
.articleDetails
|
|
margin-top 30px
|
|
background-color #fff
|
|
padding 50px 10px
|
|
|
|
.articleTitle
|
|
text-align center
|
|
font-size 24px
|
|
|
|
.articalMeta
|
|
text-align center
|
|
padding 20px 0
|
|
font-size 12px
|
|
color #a1887f
|
|
|
|
ul
|
|
list-style none
|
|
padding-right 20px
|
|
|
|
> li
|
|
display inline-block
|
|
margin-left 20px
|
|
line-height 2
|
|
|
|
> i
|
|
margin-right 8px
|
|
|
|
> span a
|
|
color #a1887f
|
|
margin-left 10px
|
|
|
|
a span
|
|
color #a1887f
|
|
|
|
> span a:first-child
|
|
margin-left 0
|
|
|
|
> li :first-child
|
|
margin-left 0
|
|
|
|
.articelContent
|
|
margin-top 20px
|
|
line-height 2
|
|
font-weight 300
|
|
font-size responsive
|
|
|
|
pre
|
|
text-align 0.16rem
|
|
overflow-x auto
|
|
line-height 1
|
|
|
|
code
|
|
padding 16px
|
|
|
|
code
|
|
color #24292e
|
|
background-color rgba(27, 31, 35, 0.05)
|
|
border-radius 3px
|
|
font-size 85%
|
|
padding 2px 5px
|
|
|
|
.comment
|
|
width 100%
|
|
|
|
.btnFooter
|
|
font-size 12px
|
|
margin-top 50px
|
|
|
|
i
|
|
margin 10px
|
|
|
|
.btnPrevt
|
|
float left
|
|
|
|
.btnNext
|
|
float right
|
|
|
|
footer .footer
|
|
color #cccccc
|
|
text-align left
|
|
line-height 1.5
|
|
margin 20px 0
|
|
|
|
.anchor-fix
|
|
display block
|
|
height 70px /* same height as header */
|
|
margin-top -70px /* same height as header */
|
|
visibility hidden
|
|
|
|
.articelRightToc
|
|
position fixed
|
|
width 15%
|
|
top 0
|
|
right 0
|
|
overflow-y auto
|
|
background-color #000
|
|
padding 10px
|
|
box-shadow 0 0 8px #000
|
|
|
|
.articelToc
|
|
width 100%
|
|
|
|
.articelToc, .articelRightToc
|
|
color #bbb
|
|
user-select none
|
|
|
|
.articelTitle
|
|
font-weight 400
|
|
margin-bottom 10px
|
|
|
|
.articelTocList
|
|
color #bbb
|
|
|
|
a
|
|
color #bbb
|
|
|
|
&:visited
|
|
color #bbb
|
|
|
|
&:hover
|
|
color #d01c2e
|
|
|
|
ol.toc, ol.toc ol
|
|
counter-reset toc
|
|
list-style none
|
|
|
|
ol li
|
|
counter-increment toc
|
|
|
|
.toc li:before
|
|
content counters(toc, '.') ' '
|
|
|
|
ol
|
|
margin-left 20px
|
|
|
|
li
|
|
font-weight 400
|
|
|
|
ol
|
|
margin-left 20px
|
|
|
|
li
|
|
font-weight 300
|
|
|
|
@media (max-width: 768px)
|
|
.articleDetails
|
|
padding 20px
|
|
margin-top 50px
|
|
|
|
.articelRightToc
|
|
position fixed
|
|
width 80%
|
|
top 100px
|
|
bottom 95px
|
|
right 10px
|
|
background-color #000
|
|
padding 10px
|
|
overflow-y auto
|
|
box-shadow 0 0 8px #000
|
|
|
|
.mobileToc
|
|
bottom 48px
|
|
</style>
|