blog-client/pages/post/_id.vue

1456 lines
41 KiB
Vue
Raw Normal View History

2019-02-07 16:26:17 +08:00
<template lang="pug">
2020-07-12 16:32:48 +08:00
.postPage
2019-02-07 16:26:17 +08:00
article.articleDetails
.articleTitle
2020-07-08 18:13:20 +08:00
| {{ articels.post_title }}
2019-02-07 16:26:17 +08:00
.articalMeta
ul
li
2020-08-21 21:12:37 +08:00
Icon(:icon='["far", "calendar-alt"]')
2020-07-08 18:13:20 +08:00
| &nbsp; {{ articels.post_date }}
2019-02-07 16:26:17 +08:00
li
2020-08-21 21:12:37 +08:00
Icon(:icon='["far", "bookmark"]')
nuxt-link(
v-for='(relationships, index) in articels.term_relationships',
:key='index',
v-if='relationships.term_taxonomy && relationships.term_taxonomy.term && relationships.term_taxonomy.taxonomy === "category"',
:to='"/" + relationships.term_taxonomy.term.slug'
)
2019-02-07 16:26:17 +08:00
span
| &nbsp; {{ relationships.term_taxonomy.term.name }}
2020-07-08 18:13:20 +08:00
li(v-if='articels.postmetum.meta_value !== 0')
2020-08-21 21:12:37 +08:00
Icon(:icon='["fas", "thermometer-" + articels.hotValue]')
2020-07-08 18:13:20 +08:00
| &nbsp; {{ articels.postmetum.meta_value }}
2020-08-21 21:12:37 +08:00
#articelToc.articelToc(v-if='articels.post_toc_show')
2019-02-07 16:26:17 +08:00
.articelTitle 目录
2020-08-21 21:12:37 +08:00
.articelTocList(v-html='articels.post_toc')
2020-07-19 20:13:07 +08:00
.articelContent(v-html='articels.post_content', v-viewer)
2020-07-08 18:13:20 +08:00
.tools
2020-08-21 21:12:37 +08:00
.reward(@click='reward') 打赏
#comment.comment
2020-07-08 22:36:46 +08:00
.comment-title 交流区
2020-08-21 21:12:37 +08:00
span(v-if='comments.length') ({{ commentAmount }})
.comment-item(
v-for='(item, index) in comments',
:id='"comment_ID_" + item.comment_ID',
:key='index'
)
2020-07-08 18:13:20 +08:00
.comment-avatar
2020-08-21 21:12:37 +08:00
img(
:src='item.comment_author_avatar_url ? item.comment_author_avatar_url : "https://picsum.photos/100/100/?blur=" + item.user_id'
)
2020-07-08 18:13:20 +08:00
.comment-area
.comment-author {{ item.comment_author }}
2020-08-21 21:12:37 +08:00
span.comment-status(v-if='item.comment_approved === "0"') &nbsp; 此内容正在审核中...
.comment-content(v-html='item.comment_content_html', v-viewer)
2020-07-08 18:13:20 +08:00
.comment-info {{ item.comment_date }}
2020-08-21 21:12:37 +08:00
span.reply(
@click='reply(item.comment_ID, null, true)',
v-if='replyLastID === null && item.comment_ID === replyID'
) 取消回复
span.reply(@click='reply(item.comment_ID, null)', v-else) 回复
span.reply(
@click='check(item.comment_ID)',
v-if='item.comment_approved === "0" && visitorInfo.manage'
) 通过审核
span.reply(
@click='check(item.comment_ID, 2)',
v-else-if='visitorInfo.manage'
) 设为垃圾评论
.comment-item(
v-for='(i, inx) in item.children',
:id='"comment_ID_" + i.comment_ID',
:key='inx',
style='margin-top: 15px; margin-left: 50px; background-color: #eeeeee; border-radius: 4px;'
)
2020-07-08 23:44:33 +08:00
.comment-avatar
2020-08-21 21:12:37 +08:00
img(
:src='i.comment_author_avatar_url ? i.comment_author_avatar_url : "https://picsum.photos/100/100/?blur=" + i.user_id'
)
2020-07-08 23:44:33 +08:00
.comment-area
.comment-author {{ i.comment_author }}
2020-08-21 21:12:37 +08:00
span.comment-status(v-if='i.comment_approved === "0"') &nbsp; 此内容正在审核中...
.comment-content(v-html='i.comment_content_html')
2020-07-08 23:44:33 +08:00
.comment-info {{ i.comment_date }}
2020-08-21 21:12:37 +08:00
span.reply(
@click='reply(item.comment_ID, i.comment_ID)',
v-if='replyLastID !== i.comment_ID'
) 回复
span.reply(
@click='reply(item.comment_ID, i.comment_ID, true)',
v-else
) 取消回复
span.reply(
@click='check(i.comment_ID)',
v-if='i.comment_approved === "0" && visitorInfo.manage'
) 通过审核
span.reply(
@click='check(i.comment_ID, 2)',
v-else-if='visitorInfo.manage'
) 设为垃圾评论
p(
v-if='!comments.length',
style='color: #cecece; text-align: center; margin-top: 40px'
) 暂无内容
2020-07-08 23:44:33 +08:00
.comment-default-commit
2020-08-21 21:12:37 +08:00
.login(v-show='!visitorToken')
.item(v-for='(item, index) in loginPlatform', :key='index')
transition(name='qrcode')
img.qrcode(
v-show='!commentLoading && useWeixinLogin && currentLoginType === item.type',
:src='weixinLoginQrcode'
)
img.logo(
:class='{ active: currentLoginType === item.type && useWeixinLogin && !commentLoading, loading: commentLoading && currentLoginType === item.type }',
:src='item.logo',
@click.stop='login(item.type)'
)
2020-07-08 23:44:33 +08:00
#editor
.comment-toolbar
2020-08-21 21:12:37 +08:00
.comment-no-userinfo(v-if='!visitorToken') 尚未登陆
.comment-userinfo(v-else)
.comment-avatar
2020-08-21 21:12:37 +08:00
img(:src='visitorInfo.avatarURL')
.comment-nickname {{ visitorInfo.nickname ? visitorInfo.nickname : visitorInfo.username || "匿名" }}
.comment-setting(@click='commentSetting') 设置
.comment-logout(@click='commentLogout') 退出
.comment-btn(@click='commentCommit("editor")') 发布
#comment-reply-commit.comment-reply-commit(, v-show='replyID')
.login(v-show='!visitorToken')
.item(v-for='(item, index) in loginPlatform', :key='index')
transition(name='qrcode')
img.qrcode(
v-show='!commentLoading && useWeixinLogin && currentLoginType === item.type',
:src='weixinLoginQrcode'
)
img.logo(
:class='{ active: currentLoginType === item.type && useWeixinLogin && !commentLoading, loading: commentLoading && currentLoginType === item.type }',
:src='item.logo',
@click.stop='login(item.type)'
)
2020-07-08 23:44:33 +08:00
#editor-reply
.comment-toolbar
2020-08-21 21:12:37 +08:00
.comment-no-userinfo(v-if='!visitorToken') 尚未登陆
.comment-userinfo(v-else)
.comment-avatar
2020-08-21 21:12:37 +08:00
img(:src='visitorInfo.avatarURL')
.comment-nickname {{ visitorInfo.nickname ? visitorInfo.nickname : visitorInfo.username || "匿名" }}
.comment-setting(@click='commentSetting') 设置
.comment-logout(@click='commentLogout') 退出
.comment-btn(@click='commentCommit("editor-reply")') 发布
ins.adsbygoogle(
style='display:block; text-align:center; margin-top:20px;',
data-ad-layout='in-article',
data-ad-format='fluid',
data-ad-client='ca-pub-2143583075951360',
data-ad-slot='4741804954'
)
.articelRightToc(
v-show='articels.post_toc_show && showRightToc',
@click='articelRightTocClick'
)
2019-02-07 16:26:17 +08:00
.articelTitle 目录
2020-08-21 21:12:37 +08:00
.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"]')
| &nbsp; 上一篇 {{ articels.last ? "(" + decodeTitle(articels.last.post_name) + ")" : "" }}
nuxt-link(:to='articels.next ? "/post/" + articels.next.ID : ""')
.btnFooter.btnNext(:style='"color: " + (articels.next ? "#333" : "#ccc")')
| 下一篇 {{ articels.next ? "(" + decodeTitle(articels.next.post_name) + ")" : "" }} &nbsp;
Icon(:icon='["fas", "chevron-right"]')
2020-09-17 21:07:07 +08:00
modal.modal-setting(name='setting')
2020-09-19 14:32:07 +08:00
.vue-modal-content(v-loading='form.loading')
p.vue-modal-title
| 评论回复提醒
2020-09-17 21:07:07 +08:00
Form(ref='form', :model='form', label-width='130px')
FormItem(label='手机号')
2020-09-19 14:32:07 +08:00
Input(v-model='form.phone', size='small')
2020-09-17 21:07:07 +08:00
FormItem(label='发送提醒到手机')
2020-09-19 14:32:07 +08:00
VueSwitch(v-model='form.sendPhone')
2020-09-17 21:07:07 +08:00
FormItem(label='邮箱')
2020-09-19 14:32:07 +08:00
Input(v-model='form.email', size='small')
2020-09-17 21:07:07 +08:00
FormItem(label='发送提醒到邮箱')
2020-09-19 14:32:07 +08:00
VueSwitch(v-model='form.sendEmail')
2020-09-17 21:07:07 +08:00
.vue-modal-buttons
2020-09-19 14:32:07 +08:00
button.vue-modal-button(type='button', @click.stop='hideSettings')
| 关闭
2020-09-17 21:07:07 +08:00
button.vue-modal-button(
2020-08-21 21:12:37 +08:00
type='button',
2020-09-19 14:32:07 +08:00
@click.stop='saveSettings',
style='background-color: #409eff;color: #fff;'
2020-08-21 21:12:37 +08:00
)
2020-09-19 14:32:07 +08:00
| 保存
2019-02-07 16:26:17 +08:00
</template>
<script>
2020-07-20 21:30:22 +08:00
import remark from 'remark'
import strip from 'strip-markdown'
2020-09-17 21:07:07 +08:00
import { Form, FormItem, Input, Switch } from 'element-ui'
2020-07-20 21:30:22 +08:00
2019-02-07 16:26:17 +08:00
export default {
2020-09-17 21:07:07 +08:00
components: {
2020-09-19 14:32:07 +08:00
Form, FormItem, Input, VueSwitch: Switch
2020-09-17 21:07:07 +08:00
},
2020-09-16 23:35:24 +08:00
async asyncData ({ route, app, $axios, redirect }) {
let draftStr = ''
if (route.query && route.query.draft === 'true') {
draftStr = '&draft=true'
}
const data = await $axios.$get(`/public/article/details?id=${route.params.id}${draftStr}`)
if (data.status === 404) {
redirect('/404')
return
}
2019-02-07 16:26:17 +08:00
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
}
2020-07-20 21:30:22 +08:00
const truncated = (str, num) => {
return Array.from(str).slice(0, num).join('')
}
const removeMarkdownFormat = (str) => {
return new Promise((resolve, reject) => {
remark()
.use(strip)
.process(str, function (err, file) {
if (err) {
reject(err)
return
}
resolve(String(file))
})
})
}
2020-07-06 18:13:28 +08:00
// 获取评论
const tmp = await $axios.$get(`/public/comments/post?ID=${route.params.id}`)
2020-07-08 18:13:20 +08:00
const comments = tmp.result.list || []
const commentAmount = tmp.result.amount || 0
2020-07-20 21:30:22 +08:00
const markdownToText = await removeMarkdownFormat(result.post_excerpt)
const description = truncated(markdownToText.replace(/[\r\n]/g, '').replace(/\s+/g, '').trim(), 200)
2020-07-06 18:13:28 +08:00
2019-02-07 16:26:17 +08:00
return {
2020-07-16 23:14:41 +08:00
postID: route.params.id,
2020-07-08 18:13:20 +08:00
articels: result,
2020-07-20 21:30:22 +08:00
description,
2020-07-08 18:13:20 +08:00
comments,
2020-07-09 18:16:27 +08:00
commentsMap: new Map(),
2020-07-08 18:13:20 +08:00
commentAmount,
2019-02-07 16:26:17 +08:00
showRightToc: false,
2020-07-08 23:44:33 +08:00
tocIds: result.post_toc_ids,
2020-07-09 00:01:48 +08:00
replyLastID: null,
2020-07-10 17:49:51 +08:00
replyID: null,
2020-07-16 22:51:18 +08:00
visitorToken: null,
visitorInfo: {
nickname: null,
avatarURL: null,
email: null,
blog: null
2020-07-21 15:39:59 +08:00
},
editorObj: null,
2020-07-22 14:07:07 +08:00
editorReplyObj: null,
commentLoading: false,
useWeixinLogin: false,
2020-07-22 18:02:37 +08:00
weixinLoginQrcode: null,
currentLoginType: null,
loginPlatform: [
{
type: 'github',
logo: 'https://cdn.wyr.me/imgs/GitHub-Login.png'
},
{
type: 'weixin',
logo: 'https://cdn.wyr.me/imgs/Weixin-Login.png'
},
{
type: 'qq',
logo: 'https://cdn.wyr.me/imgs/QQ-Login.png'
},
{
type: 'weibo',
logo: 'https://cdn.wyr.me/imgs/Weibo-Login.png'
}
2020-09-17 21:07:07 +08:00
],
form: {
2020-09-19 14:32:07 +08:00
loading: true,
2020-09-17 21:07:07 +08:00
phone: '',
sendPhone: true,
email: '',
sendEmail: true
}
2019-02-07 16:26:17 +08:00
}
},
2019-12-13 11:46:15 +08:00
mounted () {
2020-07-08 18:13:20 +08:00
// 创建编辑器
if (process.client) {
2020-07-17 14:00:01 +08:00
this.visitorToken = window.localStorage.visitorToken
if (this.visitorToken && window.localStorage.visitorInfo) {
try {
this.visitorInfo = JSON.parse(window.localStorage.visitorInfo)
this.getCommentWithVisitorInfo(this.postID)
2020-09-19 14:32:07 +08:00
this.checkSettings()
2020-07-17 14:00:01 +08:00
} catch (_) { }
}
2020-07-16 22:51:18 +08:00
window.setAuthToken = (visitorToken, visitorInfo) => {
window.localStorage.visitorToken = visitorToken
window.localStorage.visitorInfo = JSON.stringify(visitorInfo)
this.visitorToken = visitorToken
this.visitorInfo = visitorInfo
2020-07-21 15:39:59 +08:00
this.editorObj.vditor.options.upload.headers = {
2020-07-17 10:32:06 +08:00
Authorization: 'Bearer ' + this.visitorToken
}
2020-07-21 15:39:59 +08:00
this.editorReplyObj.vditor.options.upload.headers = {
2020-07-17 10:32:06 +08:00
Authorization: 'Bearer ' + this.visitorToken
}
2020-09-19 14:32:07 +08:00
this.checkSettings()
2020-07-16 22:51:18 +08:00
}
2020-07-21 15:39:59 +08:00
this.$nextTick(() => {
if (this.$route.query.hash) {
setTimeout(() => {
window.location.hash = '#' + this.$route.query.hash
}, 50)
}
if (!this.editorObj && window.Vditor) {
this.initEditor()
}
})
2020-07-09 18:16:27 +08:00
2020-07-16 23:14:41 +08:00
this.setCommentMap()
2020-07-08 18:13:20 +08:00
}
2019-02-07 16:26:17 +08:00
this.$finishLoad()
2020-07-08 18:13:20 +08:00
if (this.articels.post_toc_show) {
2019-02-07 16:26:17 +08:00
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])
}
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
2019-12-13 11:46:15 +08:00
if (windowWidth < 768) { scrollTop = scrollTop * 2.7 + 175 }
2019-02-07 16:26:17 +08:00
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
}
}
2019-12-14 12:06:07 +08:00
2020-07-06 18:13:28 +08:00
try {
(adsbygoogle = window.adsbygoogle || []).push({}) // eslint-disable-line
} catch (_) { }
2019-02-07 16:26:17 +08:00
},
methods: {
2020-07-17 10:32:06 +08:00
initEditor () {
const upload = {
accept: 'image/*, video/*, audio/*, text/*, application/*, .rar, .zip, .php, .pptx, .ppt, .doc, .docx, .txt, .xls, .xlsx',
url: process.env.baseURL + '/visitor/file/upload',
max: 10485760, // 10 MB
linkToImgUrl: process.env.baseURL + '/visitor/file/fetch',
headers: {
Authorization: 'Bearer ' + this.visitorToken
},
filename: name => encodeURIComponent(name.replace(/[^(a-zA-Z0-9\u4E00-\u9FA5\.)]/g, '') // eslint-disable-line
.replace(/[\?\\/:|<>\*\[\]\(\)\$%\{\}@~]/g, '') // eslint-disable-line
.replace('/\\s/g', '')),
format (files, responseText) {
return responseText
},
error: (_) => {
this.$modal.show('dialog', {
title: '提示',
text: '上传失败,请检查网络稍后重试。<br>允许上传的文件类型图片、视频、压缩文件、文本文件、Office文件、各类代码文件。'
})
}
}
2020-07-19 01:03:30 +08:00
2020-07-21 15:39:59 +08:00
this.editorObj = new window.Vditor('editor', {
2020-07-17 10:32:06 +08:00
toolbar: [
'emoji',
'headings',
'bold',
'italic',
'strike',
'link',
'list',
'ordered-list',
'outdent',
'indent',
'quote',
'line',
'code',
'inline-code',
'upload',
'table',
'insert-before',
'insert-after',
'undo',
'redo',
'fullscreen',
{
name: 'more',
toolbar: [
'edit-mode',
'check',
'both',
'code-theme',
'content-theme',
'export',
'outline',
'preview',
'devtools'
]
}],
minHeight: 250,
toolbarConfig: {
pin: true
},
cache: {
enable: true
},
upload,
placeholder: '我们书写的不是代码,而是人生'
})
2020-07-21 15:39:59 +08:00
this.editorReplyObj = new window.Vditor('editor-reply', {
2020-07-17 10:32:06 +08:00
toolbar: [
'emoji',
'headings',
'bold',
'italic',
'strike',
'link',
'list',
'ordered-list',
'outdent',
'indent',
'quote',
'line',
'code',
'inline-code',
'upload',
'insert-before',
'insert-after',
'undo',
'redo',
{
name: 'more',
toolbar: [
'table',
'fullscreen',
'edit-mode',
'check',
'both',
'code-theme',
'content-theme',
'export',
'outline',
'preview',
'devtools'
]
}],
minHeight: 220,
toolbarConfig: {
pin: true
},
cache: {
enable: false
},
upload,
placeholder: '我们书写的不是代码,而是人生'
})
},
2019-12-13 11:46:15 +08:00
decodeTitle (name) {
2019-03-23 22:11:40 +08:00
try {
2019-03-24 00:15:54 +08:00
return this.urldecode(name)
2019-03-23 22:11:40 +08:00
} catch (err) {
console.log(err)
return name
}
},
2019-12-13 11:46:15 +08:00
urldecode (encodedString) {
2019-03-24 00:15:54 +08:00
let output = encodedString
let binVal, thisString
const myregexp = /(%[^%]{2})/
2019-12-13 11:46:15 +08:00
function utf8to16 (str) {
2019-03-24 00:15:54 +08:00
let c
let char2, char3
let out = ''
const len = str.length
let i = 0
while (i < len) {
c = str.charCodeAt(i++)
switch (c >> 4) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
out += str.charAt(i - 1)
break
case 12: case 13:
char2 = str.charCodeAt(i++)
out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F))
break
case 14:
char2 = str.charCodeAt(i++)
char3 = str.charCodeAt(i++)
out += String.fromCharCode(((c & 0x0F) << 12) |
((char2 & 0x3F) << 6) |
((char3 & 0x3F) << 0))
break
}
}
return out
}
let match = null
while ((match = myregexp.exec(output)) != null &&
match.length > 1 &&
match[1] !== '') {
binVal = parseInt(match[1].substr(1), 16)
thisString = String.fromCharCode(binVal)
output = output.replace(match[1], thisString)
}
output = output.replace(/\\+/g, ' ')
output = utf8to16(output)
return output
},
2019-12-13 11:46:15 +08:00
articelRightTocClick () {
2019-02-07 16:26:17 +08:00
const windowWidth = window.innerWidth || document.documentElement.clientWidth
if (windowWidth < 768) {
this.showRightToc = false
}
},
2019-12-13 11:46:15 +08:00
isOnScreen (element) {
2019-02-07 16:26:17 +08:00
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
2020-07-08 18:13:20 +08:00
},
reward () {
this.$modal.show('dialog', {
title: '感谢支持',
text: '<img src="https://cdn.wyr.me/imgs/reward.jpg" style="max-width: 100%; width: 400px"/>'
})
2020-07-08 23:44:33 +08:00
},
2020-07-09 00:01:48 +08:00
reply (id, replyLastID, cancel) {
2020-07-10 17:49:51 +08:00
const editorReplyObject = document.getElementById('comment-reply-commit')
2020-07-09 00:01:48 +08:00
if (cancel) {
this.replyID = null
this.replyLastID = null
2020-07-10 10:03:49 +08:00
window.location.hash = '_'
2020-07-09 00:01:48 +08:00
} else {
this.replyID = id
this.replyLastID = replyLastID
2020-07-09 18:16:27 +08:00
document.getElementById('comment_ID_' + id).appendChild(editorReplyObject)
const comment = this.commentsMap.get(replyLastID)
2020-07-21 15:39:59 +08:00
this.editorReplyObj.setValue('', true)
2020-07-10 10:03:49 +08:00
this.$nextTick(() => {
2020-07-21 15:39:59 +08:00
this.editorReplyObj.focus()
2020-07-10 10:03:49 +08:00
if (replyLastID !== null) {
2020-07-21 15:39:59 +08:00
this.editorReplyObj.insertValue('> ' + comment.comment_content + ' \n\n\n', true)
2020-07-10 10:03:49 +08:00
} else {
2020-07-21 15:39:59 +08:00
this.editorReplyObj.insertValue('', true)
2020-07-10 10:03:49 +08:00
}
window.location.hash = '#comment_ID_' + id
})
2020-07-09 00:01:48 +08:00
}
2020-07-10 17:49:51 +08:00
},
2020-07-16 23:14:41 +08:00
async commentCommit (type) {
const parentID = this.replyID || 0
const lastID = this.replyLastID || 0
const postID = this.postID
if (!postID) {
alert('致命错误')
return
}
2020-07-21 15:39:59 +08:00
const editorObj = type === 'editor-reply' ? this.editorReplyObj : this.editorObj
2020-07-18 17:46:34 +08:00
const content = editorObj.getValue()
if (!content || content === '\n') {
this.$toasted.show('请输入内容', {
position: 'top-center',
duration: 5000
})
return
}
2020-07-16 23:38:24 +08:00
const { data } = await this.$axios({
method: 'post',
url: process.env.baseURL + '/comments/commit',
headers: {
2020-07-17 14:00:01 +08:00
Authorization: 'Bearer ' + this.visitorToken
2020-07-16 23:38:24 +08:00
},
data: {
postID,
lastID,
parentID,
2020-07-18 17:46:34 +08:00
content
2020-07-16 23:38:24 +08:00
}
2020-07-16 23:14:41 +08:00
})
2020-07-16 23:14:41 +08:00
if (data.status === 1) {
2020-07-17 12:04:14 +08:00
this.replyID = null
this.replyLastID = null
window.location.hash = '_'
2020-07-17 14:00:01 +08:00
this.getCommentWithVisitorInfo(postID)
2020-07-16 23:38:24 +08:00
editorObj.setValue('', true)
this.$nextTick(() => {
editorObj.focus()
editorObj.insertValue('', true)
})
2020-07-16 23:14:41 +08:00
}
},
2020-07-17 18:10:55 +08:00
async check (ID, type) {
const { data } = await this.$axios({
method: 'post',
url: process.env.baseURL + '/comments/check',
headers: {
Authorization: 'Bearer ' + this.visitorToken
},
data: {
ID,
type
}
})
if (data.status === 1) {
this.getCommentWithVisitorInfo(this.postID)
this.$toasted.show(type === 2 ? '已删除' : '已通过', {
position: 'top-center',
duration: 5000
})
}
},
2020-07-17 14:00:01 +08:00
async getCommentWithVisitorInfo (postID) {
// 获取评论
const tmp = await this.$axios({
method: 'get',
url: process.env.baseURL + `/public/comments/post?ID=${postID}`,
headers: {
Authorization: 'Bearer ' + this.visitorToken
}
})
const comments = tmp.data.result.list || []
const commentAmount = tmp.data.result.amount || 0
this.comments = comments
this.commentAmount = commentAmount
this.setCommentMap()
},
commentLogout () {
2020-07-16 22:51:18 +08:00
window.localStorage.removeItem('visitorToken')
this.visitorToken = null
},
2020-07-21 23:47:38 +08:00
getCode (uuid, last) {
2020-07-22 14:07:07 +08:00
try {
this.$axios({
type: 'get',
url: 'https://weixin.openapi.site/check?uuid=' + uuid + (last ? '&last=' + last : ''),
timeout: 6e4
2020-07-22 22:48:29 +08:00
}).then(async (res) => {
2020-07-22 18:02:37 +08:00
if (res.data.status === 405) {
2020-07-22 22:48:29 +08:00
const { data } = await this.$axios.post(`${process.env.baseURL}/visitor/user/weixin`, {
code: res.data.result.code
})
if (data.status !== 1) {
this.$toasted.show('微信登录失败,请重试或换用其它登录方式。', {
position: 'top-center',
duration: 5000
})
return
}
window.authSuccess(data)
2020-07-22 18:02:37 +08:00
} else if (res.data.status === 404) {
this.getCode(uuid, res.data.result.wxErrCode)
} else if (res.data.status === 403) {
this.getCode(uuid, res.data.result.wxErrCode)
} else if (res.data.status === 500) {
2020-07-22 14:07:07 +08:00
this.login('weixin')
} else {
setTimeout(() => {
this.getCode(uuid)
}, 2000)
}
})
} catch (err) {
setTimeout(function () {
this.getCode(uuid)
}, 2000)
}
2020-07-21 23:47:38 +08:00
},
async login (type) {
2020-07-22 18:02:37 +08:00
this.currentLoginType = type
this.useWeixinLogin = false
2020-07-21 23:47:38 +08:00
if (type === 'github') {
window.open('https://github.com/login/oauth/authorize?client_id=ce1673a37333e47e482d&redirect_uri=https://www.wyr.me/auth', 'Github授权', 'scrollbars=yes,resizable=yes,status=no,location=yes,toolbar=no,menubar=no,width=800,height=600,left=0,top=0')
} else if (type === 'weixin') {
2020-07-22 14:07:07 +08:00
this.useWeixinLogin = true
this.commentLoading = true
try {
2020-07-22 23:53:37 +08:00
if (navigator.userAgent.toLowerCase().includes('micromessenger')) { // 如果在微信中打开
2020-07-22 14:07:07 +08:00
this.commentLoading = false
2020-07-22 18:02:37 +08:00
this.currentLoginType = null
2020-07-22 23:53:37 +08:00
this.useWeixinLogin = false
2020-07-23 08:25:24 +08:00
window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx9d5e677f533d1e84&redirect_uri=${encodeURIComponent('https://tool.sercretcore.com/auth.php')}&response_type=code&scope=snsapi_userinfo&state=blog-${this.postID}#wechat_redirect`
2020-07-22 23:53:37 +08:00
} else {
const { data } = await this.$axios.get('https://weixin.openapi.site/img?appid=wx2d1d6aa2f86768d7&redirect_uri=https://wyr.me')
if (data.status === 1) {
const uuid = data.result.wxUUID
this.weixinLoginQrcode = data.result.imgData
this.getCode(uuid)
this.commentLoading = false
} else {
this.commentLoading = false
this.currentLoginType = null
this.$toasted.show('获取微信登录所需参数错误,请重试或换用其它登录方式。', {
position: 'top-center',
duration: 5000
})
}
2020-07-22 14:07:07 +08:00
}
} catch (err) {
this.commentLoading = false
2020-07-22 18:02:37 +08:00
this.currentLoginType = null
2020-07-22 14:07:07 +08:00
this.useWeixinLogin = false
2020-07-22 23:53:37 +08:00
this.$toasted.show('暂时无法使用微信登录,请重试或换用其它登录方式。', {
2020-07-21 23:47:38 +08:00
position: 'top-center',
duration: 5000
})
}
2020-07-23 14:37:59 +08:00
} else if (type === 'qq') {
window.location.href = 'https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=101000700&redirect_uri=' + decodeURIComponent('https://www.wyr.me/auth') + '&state=qq-' + this.postID
2020-07-23 14:28:58 +08:00
} else if (type === 'weibo') {
window.location.href = 'https://api.weibo.com/oauth2/authorize?client_id=4159322735&redirect_uri=https://wyr.me/auth&response_type=code&state=weibo-' + this.postID
2020-07-21 23:47:38 +08:00
} else {
this.$toasted.show('敬请期待', {
position: 'top-center',
duration: 5000
})
}
2020-07-16 23:14:41 +08:00
},
setCommentMap () {
const comments = this.comments
for (let i = 0; i < comments.length; i++) {
this.commentsMap.set(comments[i].comment_ID, comments[i])
if (comments[i].children) {
for (let j = 0; j < comments[i].children.length; j++) {
this.commentsMap.set(comments[i].children[j].comment_ID, comments[i].children[j])
}
}
}
2020-08-21 21:12:37 +08:00
},
commentSetting () {
2020-09-19 14:32:07 +08:00
this.form.loading = true
2020-08-21 21:12:37 +08:00
this.$modal.show('setting')
2020-09-19 14:32:07 +08:00
this.getSettings()
},
hideSettings () {
this.$modal.hide('setting')
this.form.loading = true
if (!localStorage.checkSetting) {
localStorage.checkSetting = new Date().getTime().toString()
}
},
async checkSettings () {
if (!localStorage.checkSetting) {
// 获取设置信息
const tmp = await this.$axios({
method: 'get',
url: process.env.baseURL + '/user/settings',
headers: {
Authorization: 'Bearer ' + this.visitorToken
}
})
if (tmp.status === 200 && tmp.data.status === 1 && tmp.data.result && tmp.data.result.sendPhone && tmp.data.result.sendEmail && (!tmp.data.result.phone || !tmp.data.result.email)) {
this.commentSetting()
this.$toasted.show('温馨提示:设置手机号或邮箱,可及时收到回复提醒', {
position: 'top-center',
duration: 5000
})
}
}
},
async getSettings () {
// 获取设置信息
const tmp = await this.$axios({
method: 'get',
url: process.env.baseURL + '/user/settings',
headers: {
Authorization: 'Bearer ' + this.visitorToken
}
})
if (tmp.status === 200 && tmp.data.status === 1 && tmp.data.result) {
this.form.phone = tmp.data.result.phone
this.form.sendPhone = tmp.data.result.sendPhone
this.form.email = tmp.data.result.email
this.form.sendEmail = tmp.data.result.sendEmail
this.form.loading = false
} else {
this.$toasted.show('获取设置内容失败,请重试', {
position: 'top-center',
duration: 5000
})
}
},
async saveSettings () {
// 获取设置信息
const tmp = await this.$axios({
method: 'post',
url: process.env.baseURL + '/user/settings',
headers: {
Authorization: 'Bearer ' + this.visitorToken
},
data: this.form
})
if (tmp.status === 200 && tmp.data.status === 1) {
this.hideSettings()
this.$toasted.show('保存成功', {
position: 'top-center',
duration: 5000
})
} else {
this.$toasted.show('保存设置失败,请重试', {
position: 'top-center',
duration: 5000
})
}
if (!localStorage.checkSetting) {
localStorage.checkSetting = new Date().getTime().toString()
}
2019-02-07 16:26:17 +08:00
}
2019-12-13 11:46:15 +08:00
},
head () {
2020-07-20 18:28:58 +08:00
const keywords = []
for (let i = 0; i < this.articels.term_relationships.length; i++) {
2020-07-20 21:30:22 +08:00
if (this.articels.term_relationships[i].term_taxonomy && this.articels.term_relationships[i].term_taxonomy.term && this.articels.term_relationships[i].term_taxonomy.taxonomy === 'post_tag') {
2020-07-20 18:28:58 +08:00
keywords.push(this.articels.term_relationships[i].term_taxonomy.term.name)
}
}
2020-07-20 21:30:22 +08:00
2019-12-13 11:46:15 +08:00
return {
2020-07-20 18:28:58 +08:00
title: `${this.articels.post_title} - 轶哥`,
meta: [
{
hid: 'description',
name: 'description',
2020-07-20 21:30:22 +08:00
content: this.description
2020-07-20 18:28:58 +08:00
},
{
hid: 'keywords',
name: 'keywords',
2020-07-20 21:30:22 +08:00
content: keywords.join(',')
2020-07-20 18:28:58 +08:00
}
]
2019-12-13 11:46:15 +08:00
}
2019-02-07 16:26:17 +08:00
}
}
</script>
2020-07-12 16:32:48 +08:00
<style lang="stylus">
2020-07-22 18:02:37 +08:00
$qrcode-width = 96px
$qrcode-height = 96px
$logo-width = 64px
2020-09-20 16:57:04 +08:00
modal
display none
2020-07-12 16:32:48 +08:00
.postPage
.articleDetails
margin-top 30px
background-color #fff
padding 50px 10px
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
.articleTitle
text-align center
font-size 24px
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
.articalMeta
text-align center
padding 20px 0
font-size 12px
color #a1887f
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
ul
list-style none
padding-right 20px
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
> li
display inline-block
margin-left 20px
line-height 2
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
> i
margin-right 8px
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
> span a
color #a1887f
margin-left 10px
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
a span
color #a1887f
> span a:first-child
margin-left 0
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
> li :first-child
2019-02-07 16:26:17 +08:00
margin-left 0
2020-07-12 16:32:48 +08:00
.articelContent
margin-top 20px
margin-bottom 30px
line-height 2
font-weight 300
font-size responsive
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
pre
text-align 0.16rem
overflow-x auto
line-height 1
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
code
padding 16px
2019-02-07 16:26:17 +08:00
code
2020-07-12 16:32:48 +08:00
color #24292e
background-color rgba(27, 31, 35, 0.05)
border-radius 3px
font-size 85%
padding 2px 5px
.comment
width 100%
margin-top 60px
.comment-title
color #777
margin-bottom 30px
.comment-item
margin-top 10px
padding 10px 8px
.comment-avatar
float left
margin-top 3px
img
border-radius 50%
width 40px
border-style none
cursor pointer
box-sizing border-box
margin 0
2020-07-08 18:13:20 +08:00
2020-07-12 16:32:48 +08:00
.comment-area
margin-left 50px
2020-07-08 18:13:20 +08:00
2020-07-12 16:32:48 +08:00
.comment-author, .comment-info
font-size 10px
2020-07-08 18:13:20 +08:00
2020-07-12 16:32:48 +08:00
.comment-author
color #a1887f
2020-07-08 18:13:20 +08:00
2020-07-12 16:32:48 +08:00
.comment-info
color #777
2020-07-08 18:13:20 +08:00
2020-07-12 16:32:48 +08:00
.reply
color #a1887f
cursor pointer
user-select none
margin-left 10px
2019-02-07 16:26:17 +08:00
.comment-no-userinfo
float left
font-size 12px
line-height 50px
margin-left 10px
2020-07-12 16:32:48 +08:00
.comment-userinfo
width 200px
position relative
cursor pointer
user-select none
margin-top 10px
margin-left 10px
display inline-block
height 30px
2020-07-08 22:36:46 +08:00
2020-07-12 16:32:48 +08:00
.comment-avatar
position absolute
left 0
top 0
width 30px
height 30px
overflow hidden
2020-07-08 22:36:46 +08:00
2020-07-12 16:32:48 +08:00
img
border-radius 50%
width 30px
height 30px
2020-07-12 16:32:48 +08:00
border-style none
box-sizing border-box
margin 0
2020-07-08 22:36:46 +08:00
2020-07-12 16:32:48 +08:00
.comment-nickname
color #a1887f
margin-left 50px
height 30px
line-height 30px
font-size 12px
width 150px
overflow hidden
text-overflow ellipsis
white-space nowrap
2020-07-17 10:41:02 +08:00
.comment-content
width 100%
2020-07-17 12:04:14 +08:00
padding 5px 0
2020-07-17 10:41:02 +08:00
img
max-width 100%
2020-07-17 14:00:01 +08:00
.comment-status
color #ca7474
2020-08-21 21:12:37 +08:00
.comment-logout, .comment-setting
width 51px
height 100%
line-height 30px
border 1px solid #586069
font-size 12px
border-radius 2px
box-sizing border-box
display none
text-align center
2020-08-21 21:12:37 +08:00
float left
.comment-logout
margin-left 10px
.comment-userinfo:hover
.comment-avatar, .comment-nickname
display none
2020-08-21 21:12:37 +08:00
.comment-logout, .comment-setting
display block
.comment-userinfo:active
2020-08-21 21:12:37 +08:00
.comment-logout, .comment-setting
background-color #586069
color #fff
2020-07-08 22:36:46 +08:00
2020-07-12 16:32:48 +08:00
#editor
margin-top 10px
border-bottom-color #e6e5e5
border-bottom-style dotted
border-bottom-left-radius 0
border-bottom-right-radius 0
.comment-toolbar
width 100%
height 50px
flex-direction column
border 1px solid #d1d5da
border-radius 3px
box-sizing border-box
border-top none
border-top-left-radius 0
border-top-right-radius 0
color #586069
.comment-btn
color #586069
float right
line-height 12px
margin-top 12px
margin-right 10px
padding 6px 12px
border 1px solid #586069
box-sizing border-box
font-size 12px
cursor pointer
user-select none
border-radius 2px
.comment-btn:active
background-color #586069
color #fff
2020-07-08 22:36:46 +08:00
2020-07-12 16:32:48 +08:00
.comment-reply-commit
margin 10px 0 10px 50px
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
.comment-default-commit
margin-top 125px
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
.comment-default-commit, .comment-reply-commit
position relative
2020-07-10 17:49:51 +08:00
2020-07-12 16:32:48 +08:00
.login
position absolute
left 0
top 0
width 100%
height 100%
text-align center
line-height 1
margin auto
z-index 99
cursor pointer
user-select none
2020-07-22 18:02:37 +08:00
display flex
align-items center
justify-content center
2020-07-10 17:49:51 +08:00
2020-07-22 18:02:37 +08:00
.item
flex 1
display flex
width 100%
height 100%
flex-direction column
align-items center
position relative
.qrcode
width $qrcode-width
height $qrcode-height
display flex
align-items center
justify-content center
background blue
border-radius 12px
margin-bottom 10px
color #fff
overflow hidden
cursor pointer
position absolute
z-index 1000
top 'calc(50% - %s / 2)' % $qrcode-height
2020-07-22 14:07:07 +08:00
2020-07-22 18:02:37 +08:00
.logo
background-color #f5f4f4
width 64px
height 64px
border-radius 50%
color #fff
user-select none
cursor pointer
display flex
align-items center
justify-content center
2020-07-21 23:47:38 +08:00
position absolute
2020-07-22 18:02:37 +08:00
z-index 1000
top 'calc(50% - %s / 2)' % $logo-width
transition transform 0.2s cubic-bezier(0.075, 0.82, 0.165, 1), top 0.2s cubic-bezier(0.075, 0.82, 0.165, 1)
2020-07-21 23:47:38 +08:00
2020-07-22 18:02:37 +08:00
&.active
top 'calc(50% + %s / 2 - %s / 4 + 5px)' % ($qrcode-height $logo-width)
transform scale(0.5)
2020-07-22 14:07:07 +08:00
2020-07-22 18:02:37 +08:00
&.loading
animation spin 1s linear infinite
2020-07-22 14:07:07 +08:00
2020-07-22 18:02:37 +08:00
&:hover
2020-07-22 14:07:07 +08:00
background-color #fff
2020-07-22 18:02:37 +08:00
.qrcode-enter, .qrcode-leave-to
transform scale(0)
.qrcode-enter-active, .qrcode-leave-active
transition transform 0.5s cubic-bezier(0.075, 0.82, 0.165, 1)
.qrcode-enter-to
transform scale(1)
@keyframes spin
from
transform rotate(0)
to
transform rotate(360deg)
2020-07-10 17:49:51 +08:00
2020-07-12 16:32:48 +08:00
.login:hover
background-color #fff
2020-07-10 17:49:51 +08:00
2020-07-12 16:32:48 +08:00
.login:before
content ''
position absolute
background rgba(0, 0, 0, 0.1)
top 0
left 0
width 100%
height 100%
filter blur(5px)
z-index 9
2020-07-10 17:49:51 +08:00
2020-07-12 16:32:48 +08:00
#editor-reply
margin 0
2020-07-10 17:49:51 +08:00
2020-07-12 16:32:48 +08:00
.btnFooter
font-size 12px
margin-top 25px
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
font-size 12px
2020-07-12 16:32:48 +08:00
position fixed
width 15%
top 0
right 0
overflow-y auto
background-color #000
padding 10px
box-shadow 0 0 8px #000
2020-07-19 21:18:44 +08:00
z-index 999
padding-bottom 20px
min-width 240px
max-width 300px
2020-07-12 16:32:48 +08:00
.articelToc
width 100%
.articelToc, .articelRightToc
color #bbb
user-select none
.articelTitle
font-weight 400
margin-bottom 10px
2020-07-10 17:49:51 +08:00
2020-07-12 16:32:48 +08:00
.articelTocList
color #bbb
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
a
2019-02-07 16:26:17 +08:00
color #bbb
2020-07-12 16:32:48 +08:00
&:visited
2020-07-10 17:49:51 +08:00
color #bbb
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
&:hover
color #d01c2e
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
ol.toc, ol.toc ol
counter-reset toc
list-style none
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
ol li
counter-increment toc
margin-top 6px
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
.toc li:before
content counters(toc, '.') ' '
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
ol
margin-left 20px
2019-02-07 16:26:17 +08:00
2020-07-12 16:32:48 +08:00
li
font-weight 400
2020-07-10 17:49:51 +08:00
2020-07-12 16:32:48 +08:00
ol
margin-left 20px
2020-07-10 17:49:51 +08:00
2020-07-12 16:32:48 +08:00
li
font-weight 300
2020-07-10 17:49:51 +08:00
2020-07-12 16:32:48 +08:00
.tools
margin-top 80px
margin-bottom 10px
text-align center
user-select none
.reward
margin 15px 0
border 1px solid #888
padding 5px 10px
display inline-block
color #888
font-weight 300
cursor pointer
margin auto
2020-07-10 17:49:51 +08:00
2020-07-12 16:32:48 +08:00
.vditor--fullscreen
2020-07-19 21:18:44 +08:00
z-index 9999
2020-07-10 17:49:51 +08:00
2020-09-17 21:07:07 +08:00
.modal-setting
z-index 99999
.vue-modal-content
2020-09-19 14:32:07 +08:00
padding 10px 20px 10px 10px
2020-09-17 21:07:07 +08:00
box-sizing border-box
2020-09-19 14:32:07 +08:00
.vue-modal-title
text-align center
margin-top 5px
margin-bottom 10px
font-weight 500
.el-form-item
margin-bottom 10px
2020-09-17 21:07:07 +08:00
.vue-modal-buttons
2020-08-21 21:12:37 +08:00
display flex
flex 0 1 auto
width 100%
border-top 1px solid #eee
box-sizing border-box
text-align center
2020-09-17 21:07:07 +08:00
bottom 0
position absolute
2020-08-21 21:12:37 +08:00
2020-09-17 21:07:07 +08:00
.vue-modal-button
2020-08-21 21:12:37 +08:00
font-size 12px !important
background transparent
padding 0
margin 0
border 0
cursor pointer
box-sizing border-box
line-height 40px
height 40px
color inherit
font inherit
outline none
text-align center
width 100%
2020-09-17 21:07:07 +08:00
bottom 0
2020-08-21 21:12:37 +08:00
@media (max-width 768px)
.postPage
.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
2019-02-07 16:26:17 +08:00
</style>