feat(docs): enhance interactive demos and improve documentation
- Add new interactive components for frontend routing, browser rendering pipeline, and database transactions - Improve existing demos with better visuals, explanations, and examples - Update documentation structure and content for better clarity - Add new utility scripts and update package.json with new commands - Fix formatting and alignment in documentation tables
This commit is contained in:
+301
-21
@@ -1,13 +1,57 @@
|
||||
<template>
|
||||
<div class="demo-container">
|
||||
<div class="paint-layer-demo">
|
||||
<div class="demo-header">
|
||||
<h4>{{ title }}</h4>
|
||||
<p class="hint">{{ description }}</p>
|
||||
<span class="icon">🎨</span>
|
||||
<span class="title">绘制层优化</span>
|
||||
<span class="subtitle">浏览器如何通过分层提升性能</span>
|
||||
</div>
|
||||
|
||||
<div class="demo-content">
|
||||
<el-alert type="info" :closable="false">
|
||||
绘制层演示组件占位符 - 待实现具体交互
|
||||
</el-alert>
|
||||
<div class="layer-visualization">
|
||||
<div class="layers-container">
|
||||
<div
|
||||
v-for="(layer, index) in layers"
|
||||
:key="layer.id"
|
||||
class="layer"
|
||||
:class="{ active: layer.isActive, promoted: layer.isPromoted }"
|
||||
:style="{ zIndex: index }"
|
||||
>
|
||||
<div class="layer-header">
|
||||
<span class="layer-icon">{{ layer.icon }}</span>
|
||||
<span class="layer-name">{{ layer.name }}</span>
|
||||
<span v-if="layer.isPromoted" class="promoted-badge">GPU层</span>
|
||||
</div>
|
||||
<div class="layer-content">
|
||||
<div v-if="layer.id === 'background'" class="background-box"></div>
|
||||
<div v-if="layer.id === 'card'" class="card-box">
|
||||
<div class="card-title">卡片</div>
|
||||
</div>
|
||||
<div v-if="layer.id === 'button'" class="button-box">按钮</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="properties-panel">
|
||||
<div class="panel-title">触发新层的 CSS 属性:</div>
|
||||
<div class="property-list">
|
||||
<div
|
||||
v-for="prop in promotedProperties"
|
||||
:key="prop.name"
|
||||
class="property-item"
|
||||
@mouseenter="highlightLayer(prop.layerId)"
|
||||
@mouseleave="clearHighlight"
|
||||
>
|
||||
<code class="property-code">{{ prop.code }}</code>
|
||||
<span class="property-desc">{{ prop.desc }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<span class="icon">💡</span>
|
||||
<strong>核心要点:</strong>浏览器把需要动画的元素提升到独立的 GPU 层,这样动画时只需要调整位置和透明度,不需要重绘。但不要滥用,每个层都会占用 GPU 内存。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -15,36 +59,272 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const title = ref('绘制层演示')
|
||||
const description = ref('展示浏览器渲染过程中的绘制层合成机制')
|
||||
const layers = ref([
|
||||
{
|
||||
id: 'background',
|
||||
name: '背景层',
|
||||
icon: '🖼️',
|
||||
isActive: false,
|
||||
isPromoted: false
|
||||
},
|
||||
{
|
||||
id: 'card',
|
||||
name: '内容层',
|
||||
icon: '📄',
|
||||
isActive: false,
|
||||
isPromoted: false
|
||||
},
|
||||
{
|
||||
id: 'button',
|
||||
name: '动画层',
|
||||
icon: '✨',
|
||||
isActive: false,
|
||||
isPromoted: true
|
||||
}
|
||||
])
|
||||
|
||||
const promotedProperties = [
|
||||
{
|
||||
name: '3D变换',
|
||||
code: 'transform: translate3d(0,0,0)',
|
||||
desc: '任何3D变换都会创建新层',
|
||||
layerId: 'button'
|
||||
},
|
||||
{
|
||||
name: '透明度动画',
|
||||
code: 'opacity',
|
||||
desc: '配合transition使用时',
|
||||
layerId: 'button'
|
||||
},
|
||||
{
|
||||
name: '固定定位',
|
||||
code: 'position: fixed',
|
||||
desc: '固定定位元素需要独立层',
|
||||
layerId: 'button'
|
||||
},
|
||||
{
|
||||
name: 'Will-change',
|
||||
code: 'will-change: transform',
|
||||
desc: '显式提示浏览器创建层',
|
||||
layerId: 'button'
|
||||
}
|
||||
]
|
||||
|
||||
function highlightLayer(layerId) {
|
||||
layers.value.forEach(layer => {
|
||||
layer.isActive = layer.id === layerId
|
||||
})
|
||||
}
|
||||
|
||||
function clearHighlight() {
|
||||
layers.value.forEach(layer => {
|
||||
layer.isActive = false
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.demo-container {
|
||||
.paint-layer-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 8px 0;
|
||||
color: var(--vp-c-text-1);
|
||||
.demo-header .icon { font-size: 1.25rem; }
|
||||
.demo-header .title { font-weight: bold; font-size: 1rem; }
|
||||
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.85rem; margin-left: 0.5rem; }
|
||||
|
||||
.demo-content {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.hint {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
.layer-visualization {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.layers-container {
|
||||
position: relative;
|
||||
height: 200px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 6px;
|
||||
padding: 1rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.layer {
|
||||
position: absolute;
|
||||
width: calc(100% - 2rem);
|
||||
height: calc(100% - 2rem);
|
||||
background: var(--vp-c-bg);
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.layer:nth-child(1) {
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
.layer:nth-child(2) {
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
transform: translate(10px, 10px);
|
||||
}
|
||||
|
||||
.layer:nth-child(3) {
|
||||
top: 30px;
|
||||
left: 30px;
|
||||
transform: translate(20px, 20px);
|
||||
}
|
||||
|
||||
.layer.active {
|
||||
border-color: var(--vp-c-brand);
|
||||
box-shadow: 0 0 0 4px rgba(64, 158, 255, 0.2);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.layer.promoted {
|
||||
border-color: var(--vp-c-success);
|
||||
}
|
||||
|
||||
.layer-header {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
left: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.layer-icon {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.layer-name {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.demo-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
.promoted-badge {
|
||||
font-size: 0.7rem;
|
||||
padding: 0.1rem 0.3rem;
|
||||
background: var(--vp-c-success);
|
||||
color: white;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.layer-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.background-box {
|
||||
width: 80%;
|
||||
height: 60%;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.card-box {
|
||||
width: 120px;
|
||||
height: 80px;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.button-box {
|
||||
padding: 0.5rem 1rem;
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.properties-panel {
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.property-list {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.property-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.5rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.property-item:hover {
|
||||
background: var(--vp-c-bg-alt);
|
||||
}
|
||||
|
||||
.property-code {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 0.8rem;
|
||||
padding: 0.2rem 0.4rem;
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 3px;
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.property-desc {
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 0.75rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.info-box .icon { margin-right: 0.25rem; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user