vuepress-theme-vdoing/vdoing/theme-vdoing/layouts/Layout.vue

206 lines
4.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>
<Sidebar
:items="sidebarItems"
@toggle-sidebar="toggleSidebar"
v-show="showSidebar"
>
<slot
name="sidebar-top"
#top
/>
<slot
name="sidebar-bottom"
#bottom
/>
</Sidebar>
<Home v-if="$page.frontmatter.home"/>
<Page
v-else
:sidebar-items="sidebarItems"
>
<slot
name="page-top"
#top
/>
<slot
name="page-bottom"
#bottom
/>
</Page>
<Buttons
ref="buttons"
@toggle-theme-mode="toggleThemeMode"
/>
</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 Sidebar from '@theme/components/Sidebar.vue'
import Buttons from '@theme/components/Buttons.vue'
import { resolveSidebarItems } from '../util'
import storage from 'good-storage' // 本地存储
const MOBILE_DESKTOP_BREAKPOINT = 719 // refer to config.styl
export default {
components: { Home, Page, Sidebar, Navbar, Buttons },
data () {
return {
isSidebarOpen: true,
showSidebar: false,
themeMode: 'light'
}
},
computed: {
showRightMenu() {
const { headers } = this.$page
return (
!this.$frontmatter.home
&& 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
)
},
sidebarItems () {
return resolveSidebarItems(
this.$page,
this.$page.regularPath,
this.$site,
this.$localePath
)
},
pageClasses () {
const userPageClass = this.$page.frontmatter.pageClass
return [
{
'no-navbar': !this.shouldShowNavbar,
'sidebar-open': this.isSidebarOpen,
'no-sidebar': !this.shouldShowSidebar,
'have-rightmenu': this.showRightMenu,
},
'theme-mode-' + this.themeMode,
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
if(!mode || mode === 'auto') { // 当未切换过模式,或模式处于'跟随系统'时
this._autoMode()
} else {
this.themeMode = mode
}
},
mounted () {
this.showSidebar = true // 解决移动端初始化页面时侧边栏闪现的问题
this.$router.afterEach(() => {
this.isSidebarOpenOfclientWidth()
})
},
methods: {
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>