mjz update

This commit is contained in:
mjz
2023-05-28 18:15:33 +08:00
parent 9b75e60571
commit ed6e2d81fb
243 changed files with 11730 additions and 6 deletions

382
vdoing/layouts/Layout.vue Normal file
View File

@@ -0,0 +1,382 @@
<template>
<div
class="theme-container"
:class="pageClasses"
@touchstart="onTouchStart"
@touchend="onTouchEnd"
>
<Navbar v-if="shouldShowNavbar" @toggle-sidebar="toggleSidebar" />
<div class="sidebar-mask" @click="toggleSidebar(false)"></div>
<div
v-if="$themeConfig.sidebarHoverTriggerOpen !== false"
class="sidebar-hover-trigger"
></div>
<Sidebar
:items="sidebarItems"
@toggle-sidebar="toggleSidebar"
v-show="showSidebar"
>
<template #top v-if="sidebarSlotTop">
<div
class="sidebar-slot sidebar-slot-top"
v-html="sidebarSlotTop"
></div>
</template>
<template #bottom v-if="sidebarSlotBottom">
<div
class="sidebar-slot sidebar-slot-bottom"
v-html="sidebarSlotBottom"
></div>
</template>
<!-- <slot name="sidebar-top" #top />
<slot name="sidebar-bottom" #bottom /> -->
</Sidebar>
<!-- 首页 -->
<Home v-if="$page.frontmatter.home" />
<!-- 分类页 -->
<CategoriesPage v-else-if="$page.frontmatter.categoriesPage" />
<!-- 标签页 -->
<TagsPage v-else-if="$page.frontmatter.tagsPage" />
<!-- 归档页 -->
<ArchivesPage v-else-if="$page.frontmatter.archivesPage" />
<!-- 文章页或其他页 -->
<Page v-else :sidebar-items="sidebarItems">
<template #top v-if="pageSlotTop">
<div class="page-slot page-slot-top" v-html="pageSlotTop"></div>
</template>
<template #bottom v-if="pageSlotBottom">
<div class="page-slot page-slot-bottom" v-html="pageSlotBottom"></div>
</template>
<!-- <slot
name="page-top"
#top
/>
<slot
name="page-bottom"
#bottom
/> -->
</Page>
<Footer />
<Buttons ref="buttons" @toggle-theme-mode="toggleThemeMode" />
<BodyBgImg v-if="$themeConfig.bodyBgImg" />
<!-- 自定义html插入左右下角的小窗口 -->
<div
class="custom-html-window custom-html-window-lb"
v-if="windowLB"
v-show="showWindowLB"
>
<div class="custom-wrapper">
<span class="close-but" @click="showWindowLB = false">×</span>
<div v-html="windowLB" />
</div>
</div>
<div
class="custom-html-window custom-html-window-rb"
v-if="windowRB"
v-show="showWindowRB"
>
<div class="custom-wrapper">
<span class="close-but" @click="showWindowRB = false">×</span>
<div v-html="windowRB" />
</div>
</div>
</div>
</template>
<script>
import Home from '@theme/components/Home.vue'
import Navbar from '@theme/components/Navbar.vue'
import Page from '@theme/components/Page.vue'
import CategoriesPage from '@theme/components/CategoriesPage.vue'
import TagsPage from '@theme/components/TagsPage.vue'
import ArchivesPage from '@theme/components/ArchivesPage.vue'
import Sidebar from '@theme/components/Sidebar.vue'
import Buttons from '@theme/components/Buttons.vue'
import Footer from '@theme/components/Footer'
import BodyBgImg from '@theme/components/BodyBgImg'
import { resolveSidebarItems } from '../util'
import storage from 'good-storage' // 本地存储
import _ from 'lodash'
const MOBILE_DESKTOP_BREAKPOINT = 719 // refer to config.styl
const NAVBAR_HEIGHT = 58 // 导航栏高度
export default {
components: { Home, Navbar, Page, CategoriesPage, TagsPage, ArchivesPage, Sidebar, Footer, Buttons, BodyBgImg },
data() {
return {
hideNavbar: false,
isSidebarOpen: true,
showSidebar: false,
themeMode: 'auto',
showWindowLB: true,
showWindowRB: true
}
},
computed: {
sidebarSlotTop() {
return this.getHtmlStr('sidebarT')
},
sidebarSlotBottom() {
return this.getHtmlStr('sidebarB')
},
pageSlotTop() {
return this.getHtmlStr('pageT')
},
pageSlotBottom() {
return this.getHtmlStr('pageB')
},
windowLB() {
return this.getHtmlStr('windowLB')
},
windowRB() {
return this.getHtmlStr('windowRB')
},
showRightMenu() {
const { headers } = this.$page
return (
!this.$frontmatter.home
&& this.$themeConfig.rightMenuBar !== false
&& headers
&& headers.length
&& this.$frontmatter.sidebar !== false
)
},
shouldShowNavbar() {
const { themeConfig } = this.$site
const { frontmatter } = this.$page
if (
frontmatter.navbar === false
|| themeConfig.navbar === false) {
return false
}
return (
this.$title
|| themeConfig.logo
|| themeConfig.repo
|| themeConfig.nav
|| this.$themeLocaleConfig.nav
)
},
shouldShowSidebar() {
const { frontmatter } = this.$page
return (
!frontmatter.home
&& frontmatter.sidebar !== false
&& this.sidebarItems.length
&& frontmatter.showSidebar !== false
)
},
sidebarItems() {
return resolveSidebarItems(
this.$page,
this.$page.regularPath,
this.$site,
this.$localePath
)
},
pageClasses() {
const userPageClass = this.$page.frontmatter.pageClass
return [
{
'no-navbar': !this.shouldShowNavbar,
'hide-navbar': this.hideNavbar, // 向下滚动隐藏导航栏
'sidebar-open': this.isSidebarOpen,
'no-sidebar': !this.shouldShowSidebar,
'have-rightmenu': this.showRightMenu,
'have-body-img': this.$themeConfig.bodyBgImg,
'only-sidebarItem': this.sidebarItems.length === 1 && this.sidebarItems[0].type === 'page', // 左侧边栏只有一项时
},
userPageClass
]
}
},
created() {
const sidebarOpen = this.$themeConfig.sidebarOpen
if (sidebarOpen === false) {
this.isSidebarOpen = sidebarOpen
}
},
beforeMount() {
this.isSidebarOpenOfclientWidth()
const mode = storage.get('mode') // 不放在created是因为vuepress不能在created访问浏览器api如window
const { defaultMode } = this.$themeConfig
if (defaultMode && defaultMode !== 'auto' && !mode ) {
this.themeMode = defaultMode
} else if(!mode || mode === 'auto' || defaultMode === 'auto') { // 当未切换过模式,或模式处于'跟随系统'时
this._autoMode()
} else {
this.themeMode = mode
}
this.setBodyClass()
// 引入图标库
const social = this.$themeConfig.social
if (social && social.iconfontCssFile) {
let linkElm = document.createElement("link")
linkElm.setAttribute('rel', 'stylesheet');
linkElm.setAttribute("type", "text/css")
linkElm.setAttribute("href", social.iconfontCssFile)
document.head.appendChild(linkElm)
}
},
mounted() {
// 初始化页面时链接锚点无法跳转到指定id的解决方案
const hash = document.location.hash;
if (hash.length > 1) {
const id = decodeURIComponent(hash.substring(1))
const element = document.getElementById(id)
if (element) element.scrollIntoView()
}
// 解决移动端初始化页面时侧边栏闪现的问题
this.showSidebar = true
this.$router.afterEach(() => {
this.isSidebarOpenOfclientWidth()
})
// 向下滚动收起导航栏
let p = 0, t = 0;
window.addEventListener('scroll', _.throttle(() => {
if (!this.isSidebarOpen) { // 侧边栏关闭时
p = this.getScrollTop()
if (t < p && p > NAVBAR_HEIGHT) { // 向下滚动
this.hideNavbar = true
} else { // 向上
this.hideNavbar = false
}
setTimeout(() => { t = p }, 0)
}
}, 300))
},
watch: {
isSidebarOpen() {
if (this.isSidebarOpen) { // 侧边栏打开时,恢复导航栏显示
this.hideNavbar = false
}
},
themeMode() {
this.setBodyClass()
}
},
methods: {
getHtmlStr(module) {
const { htmlModules } = this.$themeConfig
return htmlModules ? htmlModules[module] : ''
},
setBodyClass() {
let { pageStyle = 'card', bodyBgImg } = this.$themeConfig
if (pageStyle !== 'card' && pageStyle !== 'line' || bodyBgImg) { pageStyle = 'card' }
document.body.className = `theme-mode-${this.themeMode} theme-style-${pageStyle}`
},
getScrollTop() {
return window.pageYOffset
|| document.documentElement.scrollTop
|| document.body.scrollTop || 0
},
isSidebarOpenOfclientWidth() {
if (document.documentElement.clientWidth < MOBILE_DESKTOP_BREAKPOINT) {
this.isSidebarOpen = false
}
},
toggleSidebar(to) {
this.isSidebarOpen = typeof to === 'boolean' ? to : !this.isSidebarOpen
this.$emit('toggle-sidebar', this.isSidebarOpen)
},
_autoMode() {
if (window.matchMedia('(prefers-color-scheme: dark)').matches) { // 系统处于深色模式
this.themeMode = 'dark'
} else {
this.themeMode = 'light'
}
},
toggleThemeMode(key) {
if (key === 'auto') {
this._autoMode()
} else {
this.themeMode = key
}
storage.set('mode', key)
},
// side swipe
onTouchStart(e) {
this.touchStart = {
x: e.changedTouches[0].clientX,
y: e.changedTouches[0].clientY
}
},
onTouchEnd(e) {
const dx = e.changedTouches[0].clientX - this.touchStart.x
const dy = e.changedTouches[0].clientY - this.touchStart.y
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) {
if (dx > 0 && this.touchStart.x <= 80) {
this.toggleSidebar(true)
} else {
this.toggleSidebar(false)
}
}
}
}
}
</script>
<style lang="stylus">
.custom-html-window
position fixed
bottom 0
display flex
overflow hidden
font-weight 350
@media (max-width 960px)
display none
.custom-wrapper
position relative
max-width 200px
max-height 400px
.close-but
cursor pointer
position absolute
right 0
top 0
font-size 1.5rem
line-height 1.5rem
width 1.5rem
height 1.5rem
opacity 0
transition all 0.2s
&:hover
opacity 0.9
&:hover
.close-but
opacity 0.7
&.custom-html-window-lb
left 0
z-index 99
&>*
align-self flex-end
&.custom-html-window-rb
right 80px
z-index 10
justify-content flex-end
&>*
align-self flex-end
</style>