Skip to content

Commit 0dbdde9

Browse files
docs: ✏️ 优化演示 Demo 在小屏幕上的显示效果 (#1296)
* docs: ✏️ 优化演示 Demo 在小屏幕上的显示效果 * docs: ✏️ postMessage 的 targetOrigin 应为精确的 Origin(协议+域名+端口)
1 parent 1a9f626 commit 0dbdde9

5 files changed

Lines changed: 499 additions & 215 deletions

File tree

docs/.vitepress/theme/components/VPDoc.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ const expanded = ref(true)
195195
.content {
196196
order: 1;
197197
margin: 0;
198-
min-width: 640px;
198+
min-width: 600px;
199199
}
200200
}
201201

docs/.vitepress/theme/components/VPIframe.vue

Lines changed: 192 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
2-
<!-- 主容器:根据展开状态和过渡状态添加对应类名 -->
3-
<div v-if="href" class="demo-model" :class="{
2+
<!-- 大屏幕:原有的固定容器 -->
3+
<div v-if="href && !isSmallScreen" class="demo-model" :class="{
44
'collapsed': !expanded,
55
'transition-end': transitionEnd
66
}" @transitionend="onTransitionEnd">
@@ -18,12 +18,42 @@
1818
<iframe v-if="expanded&&transitionEnd" ref="iframe" id="demo" class="iframe" scrolling="auto" frameborder="0" :src="href" />
1919
</div>
2020
</div>
21+
22+
<!-- 小屏幕:触发按钮 -->
23+
<div v-if="href && isSmallScreen && !isTinyScreen" class="demo-trigger" @click="openDrawer">
24+
<el-icon class="trigger-icon">
25+
<component :is="Expand" />
26+
</el-icon>
27+
</div>
28+
29+
<!-- 小屏幕:Drawer抽屉 -->
30+
<view v-if="isSmallScreen && !isTinyScreen" class="drawer-container">
31+
<el-drawer
32+
33+
v-model="drawerVisible"
34+
direction="rtl"
35+
size="380px"
36+
:modal="false"
37+
:lock-scroll="false"
38+
:before-close="closeDrawer"
39+
>
40+
<div class="demo-header">
41+
<ExternalLink :href="href" class="demo-link">
42+
</ExternalLink>
43+
<QrCode class="demo-qrcode" :src="qrcode" v-if="qrcode"></QrCode>
44+
</div>
45+
<div class="drawer-content">
46+
<iframe v-if="drawerVisible" ref="drawerIframe" class="drawer-iframe" scrolling="auto" frameborder="0" :src="href" />
47+
</div>
48+
</el-drawer>
49+
</view>
2150
</template>
2251

2352
<script setup lang="ts">
2453
import { Expand, Fold } from '@element-plus/icons-vue'
54+
import { ElDrawer, ElIcon } from 'element-plus'
2555
import { useRoute, useData } from 'vitepress'
26-
import { computed, onMounted, ref, watch } from 'vue'
56+
import { computed, onMounted, ref, watch, onUnmounted } from 'vue'
2757
import QrCode from './QrCode.vue'
2858
2959
interface Props {
@@ -38,7 +68,11 @@ const props = withDefaults(defineProps<Props>(), {
3868
// 状态管理
3969
const baseUrl = ref('')
4070
const iframe = ref<HTMLIFrameElement | null>(null)
71+
const drawerIframe = ref<HTMLIFrameElement | null>(null)
4172
const transitionEnd = ref(true)
73+
const drawerVisible = ref(false)
74+
const isSmallScreen = ref(false)
75+
const isTinyScreen = ref(false)
4276
4377
const emit = defineEmits<{
4478
'update:expanded': [boolean] // 更新展开状态
@@ -64,6 +98,19 @@ const qrcode = computed(() => {
6498
return `/wxqrcode/${paths[paths.length - 1]}.png`
6599
})
66100
101+
// 获取页面标题
102+
const pageTitle = computed(() => {
103+
const path = route.path
104+
const paths = path ? path.split('.')[0].split('/') : []
105+
if (!paths.length) return '预览Demo'
106+
107+
// 将kebab-case转换为更友好的标题格式
108+
const pageName = paths[paths.length - 1]
109+
return pageName.split('-').map(word =>
110+
word.charAt(0).toUpperCase() + word.slice(1)
111+
).join(' ')
112+
})
113+
67114
// 工具函数:转换 kebab-case 为 camelCase
68115
function kebabToCamel(input: string): string {
69116
return input.replace(/-([a-z])/g, (match, group) => group.toUpperCase())
@@ -87,6 +134,26 @@ function toggleExpand() {
87134
transitionEnd.value = false
88135
}
89136
137+
// 小屏幕抽屉控制
138+
function openDrawer() {
139+
drawerVisible.value = true
140+
}
141+
142+
function closeDrawer() {
143+
drawerVisible.value = false
144+
}
145+
146+
// 检查屏幕尺寸
147+
function checkScreenSize() {
148+
isSmallScreen.value = window.innerWidth <= 1439
149+
isTinyScreen.value = window.innerWidth < 1280
150+
}
151+
152+
// 监听窗口大小变化
153+
function handleResize() {
154+
checkScreenSize()
155+
}
156+
90157
// 过渡结束处理
91158
function onTransitionEnd() {
92159
transitionEnd.value = true
@@ -95,15 +162,19 @@ function onTransitionEnd() {
95162
96163
// iframe 消息通信
97164
function sendMessage() {
98-
if (iframe.value?.contentWindow) {
99-
iframe.value.contentWindow.postMessage(vitepressData.isDark.value, href.value)
165+
const targetIframe = isSmallScreen.value ? drawerIframe.value : iframe.value
166+
if (targetIframe?.contentWindow) {
167+
const targetOrigin = new URL(href.value, location.origin).origin
168+
targetIframe.contentWindow.postMessage(vitepressData.isDark.value, targetOrigin)
100169
}
101170
}
102171
103172
// 发送语言信息给iframe
104173
function sendLanguageMessage() {
105-
if (iframe.value?.contentWindow) {
106-
iframe.value.contentWindow.postMessage(vitepressData.lang.value, href.value)
174+
const targetIframe = isSmallScreen.value ? drawerIframe.value : iframe.value
175+
if (targetIframe?.contentWindow) {
176+
const targetOrigin = new URL(href.value, location.origin).origin
177+
targetIframe.contentWindow.postMessage(vitepressData.lang.value, targetOrigin)
107178
}
108179
}
109180
@@ -112,13 +183,31 @@ onMounted(() => {
112183
? `${location.origin}/demo/?timestamp=${new Date().getTime()}#/`
113184
: 'http://localhost:5173/demo/#/'
114185
186+
// 初始化屏幕尺寸检查
187+
checkScreenSize()
188+
window.addEventListener('resize', handleResize)
189+
115190
// 监听 iframe 加载完成事件
116191
iframe.value?.addEventListener('load', () => {
117192
sendMessage()
118193
sendLanguageMessage()
119194
})
120195
})
121196
197+
onUnmounted(() => {
198+
window.removeEventListener('resize', handleResize)
199+
})
200+
201+
// 监听抽屉iframe加载完成
202+
watch(drawerIframe, (newVal) => {
203+
if (newVal) {
204+
newVal.addEventListener('load', () => {
205+
sendMessage()
206+
sendLanguageMessage()
207+
})
208+
}
209+
})
210+
122211
watch(
123212
() => vitepressData.isDark.value,
124213
sendMessage
@@ -266,8 +355,102 @@ watch(
266355
}
267356
}
268357
269-
@media (max-width: 1439px) {
270-
.demo-model {
358+
/* 小屏幕触发按钮样式 */
359+
.demo-trigger {
360+
position: fixed;
361+
z-index: 10;
362+
right: 16px;
363+
top: calc(var(--vp-nav-height) + 32px);
364+
width: 48px;
365+
height: 48px;
366+
background: var(--vp-c-bg-alt);
367+
border-radius: 12px;
368+
box-shadow: var(--vp-shadow-4);
369+
display: flex;
370+
align-items: center;
371+
justify-content: center;
372+
cursor: pointer;
373+
transition: all 0.3s ease-in-out;
374+
}
375+
376+
.demo-trigger:hover {
377+
transform: scale(1.05);
378+
}
379+
380+
.trigger-icon {
381+
font-size: 24px;
382+
color: var(--vp-c-text-1);
383+
}
384+
385+
/* 抽屉内容样式 */
386+
.drawer-header {
387+
display: flex;
388+
align-items: center;
389+
justify-content: space-between;
390+
padding: 16px 0;
391+
border-bottom: 1px solid var(--vp-c-divider);
392+
margin-bottom: 16px;
393+
}
394+
395+
.drawer-title {
396+
font-size: 18px;
397+
font-weight: 600;
398+
color: var(--vp-c-text-1);
399+
flex: 1;
400+
}
401+
402+
.drawer-actions {
403+
display: flex;
404+
align-items: center;
405+
gap: 12px;
406+
}
407+
408+
.drawer-actions .demo-link {
409+
font-size: 20px !important;
410+
color: var(--vp-c-text-2);
411+
transition: color 0.3s ease;
412+
}
413+
414+
.drawer-actions .demo-link:hover {
415+
color: var(--vp-c-brand-1);
416+
}
417+
418+
.drawer-actions .demo-qrcode {
419+
font-size: 20px !important;
420+
color: var(--vp-c-text-2);
421+
}
422+
423+
.drawer-content {
424+
display: flex;
425+
flex-direction: column;
426+
align-items: center;
427+
width: 340px;
428+
height: calc(340px * 143.6 / 70.9);
429+
}
430+
431+
.drawer-iframe {
432+
width: 340px;
433+
height: calc(340px * 143.6 / 70.9);
434+
border: none;
435+
border-radius: 20px;
436+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
437+
background: var(--vp-c-bg);
438+
overflow: hidden;
439+
}
440+
441+
.drawer-container {
442+
--el-drawer-bg-color: var(--vp-c-bg);
443+
:deep() {
444+
.el-drawer {
445+
background-color: var(--vp-c-bg) !important;
446+
}
447+
}
448+
}
449+
450+
451+
452+
@media (max-width: 768px) {
453+
.demo-trigger {
271454
display: none;
272455
}
273456
}

docs/.vitepress/theme/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
/*
22
* @Author: weisheng
33
* @Date: 2024-10-12 22:09:33
4-
* @LastEditTime: 2025-09-03 16:11:27
4+
* @LastEditTime: 2025-09-10 23:37:53
55
* @LastEditors: weisheng
66
* @Description:
77
* @FilePath: /wot-design-uni/docs/.vitepress/theme/index.ts
88
* 记得注释
99
*/
1010
import { h } from 'vue'
1111
import Theme from 'vitepress/theme'
12-
import { useRouter } from 'vitepress'
1312
import './styles/vars.css'
1413
import './styles/custom.css'
1514
import './styles/scrollbar.scss'
@@ -23,6 +22,7 @@ import ExternalLink from './components/ExternalLink.vue'
2322
import WwAds from './components/WwAds.vue'
2423
import ElementPlus, { ElMessageBox } from 'element-plus'
2524
import 'element-plus/dist/index.css'
25+
import 'element-plus/theme-chalk/dark/css-vars.css'
2626

2727
// 声明百度统计全局变量
2828
declare global {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
"@dcloudio/uni-mp-weixin": "3.0.0-4050720250324001",
8585
"@dcloudio/uni-mp-xhs": "3.0.0-4050720250324001",
8686
"@dcloudio/uni-quickapp-webview": "3.0.0-4050720250324001",
87-
"element-plus": "^2.3.9",
87+
"element-plus": "^2.11.2",
8888
"vite-plugin-compression": "^0.5.1",
8989
"vitepress": "^1.6.3",
9090
"vue": "^3.4.38",

0 commit comments

Comments
 (0)