120 lines
3.4 KiB
JavaScript
120 lines
3.4 KiB
JavaScript
|
|
import DefaultTheme from 'vitepress/theme'
|
|||
|
|
import Viewer from 'viewerjs'
|
|||
|
|
import 'viewerjs/dist/viewer.css'
|
|||
|
|
import TypeIt from 'typeit'
|
|||
|
|
import { onMounted, watch, nextTick } from 'vue'
|
|||
|
|
import { useRoute, useData } from 'vitepress'
|
|||
|
|
import './style.css'
|
|||
|
|
|
|||
|
|
export default {
|
|||
|
|
extends: DefaultTheme,
|
|||
|
|
setup() {
|
|||
|
|
const route = useRoute()
|
|||
|
|
const { frontmatter } = useData()
|
|||
|
|
let viewer = null
|
|||
|
|
|
|||
|
|
const initViewer = () => {
|
|||
|
|
// 销毁旧实例
|
|||
|
|
if (viewer) {
|
|||
|
|
viewer.destroy()
|
|||
|
|
viewer = null
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 找到文章内容容器
|
|||
|
|
const doc = document.querySelector('.vp-doc')
|
|||
|
|
if (doc) {
|
|||
|
|
// 初始化 Viewer,配置一些常用选项
|
|||
|
|
viewer = new Viewer(doc, {
|
|||
|
|
button: true, // 显示右上角关闭按钮
|
|||
|
|
navbar: true, // 显示底部缩略图导航
|
|||
|
|
title: true, // 显示图片标题(alt 属性)
|
|||
|
|
toolbar: true, // 显示工具栏(缩放、旋转等)
|
|||
|
|
tooltip: true, // 显示缩放百分比
|
|||
|
|
movable: true, // 允许拖拽
|
|||
|
|
zoomable: true, // 允许缩放
|
|||
|
|
rotatable: true, // 允许旋转
|
|||
|
|
scalable: true, // 允许翻转
|
|||
|
|
transition: false, // 禁用自带动画,确保打开瞬间无飞入
|
|||
|
|
fullscreen: true, // 允许全屏播放
|
|||
|
|
shown() {
|
|||
|
|
// 打开完成后,标记为 ready,CSS 此时才会介入 transition
|
|||
|
|
document.body.classList.add('viewer-ready')
|
|||
|
|
},
|
|||
|
|
hide() {
|
|||
|
|
// 关闭前移除标记,确保关闭瞬间无动画
|
|||
|
|
document.body.classList.remove('viewer-ready')
|
|||
|
|
},
|
|||
|
|
keyboard: true, // 允许键盘控制
|
|||
|
|
url: 'src', // 图片源
|
|||
|
|
// 过滤掉不想查看的图片(比如表情包等小图标,如果需要的话)
|
|||
|
|
filter(image) {
|
|||
|
|
return !image.classList.contains('no-viewer')
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const initTypewriter = () => {
|
|||
|
|
const taglineData = frontmatter.value.hero?.tagline
|
|||
|
|
if (Array.isArray(taglineData) && taglineData.length > 0) {
|
|||
|
|
const taglineEl = document.querySelector('.VPHomeHero .tagline')
|
|||
|
|
if (taglineEl) {
|
|||
|
|
taglineEl.innerHTML = ''
|
|||
|
|
|
|||
|
|
const typeIt = new TypeIt(taglineEl, {
|
|||
|
|
speed: 50,
|
|||
|
|
startDelay: 500,
|
|||
|
|
loop: true
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
taglineData.forEach((text) => {
|
|||
|
|
typeIt.type(text).pause(2000).delete().pause(500)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
typeIt.go()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const optimizeImages = () => {
|
|||
|
|
const images = document.querySelectorAll('.vp-doc img')
|
|||
|
|
images.forEach(img => {
|
|||
|
|
if (img.complete) {
|
|||
|
|
applyImageStyle(img)
|
|||
|
|
} else {
|
|||
|
|
img.onload = () => applyImageStyle(img)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const applyImageStyle = (img) => {
|
|||
|
|
const { naturalWidth, naturalHeight } = img
|
|||
|
|
if (!naturalWidth || !naturalHeight) return
|
|||
|
|
|
|||
|
|
const ratio = naturalHeight / naturalWidth
|
|||
|
|
img.classList.remove('img-tall', 'img-very-tall')
|
|||
|
|
|
|||
|
|
if (ratio > 2) {
|
|||
|
|
img.classList.add('img-very-tall')
|
|||
|
|
} else if (ratio > 1.2) {
|
|||
|
|
img.classList.add('img-tall')
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
onMounted(() => {
|
|||
|
|
initViewer()
|
|||
|
|
initTypewriter()
|
|||
|
|
optimizeImages()
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
watch(
|
|||
|
|
() => route.path,
|
|||
|
|
() => nextTick(() => {
|
|||
|
|
initViewer()
|
|||
|
|
initTypewriter()
|
|||
|
|
optimizeImages()
|
|||
|
|
})
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
}
|