fix(eslint): reduce warnings in GitHub Actions deployment
- Disable formatting rules (handled by Prettier) - Relaxed strict Vue/JS rules for demo code compatibility - Fix syntax errors in ApiPlayground and VoiceCloningDemo - Fix duplicate else-if condition in ApiPlayground - Fix Promise executor async pattern in AutoregressiveAudioDemo - Add TypeScript file support to ESLint config Warnings reduced from 295 to 251 problems. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
+49
-20
@@ -5,19 +5,23 @@
|
||||
<template>
|
||||
<div class="caching-demo">
|
||||
<div class="header">
|
||||
<div class="title">缓存策略:速度与更新的平衡</div>
|
||||
<div class="subtitle">对比不同缓存策略的效果</div>
|
||||
<div class="title">
|
||||
缓存策略:速度与更新的平衡
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
对比不同缓存策略的效果
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="strategy-selector">
|
||||
<button
|
||||
v-for="strategy in strategies"
|
||||
:key="strategy.name"
|
||||
@click="selectStrategy(strategy)"
|
||||
:class="[
|
||||
'strategy-btn',
|
||||
{ active: selectedStrategy.name === strategy.name }
|
||||
]"
|
||||
@click="selectStrategy(strategy)"
|
||||
>
|
||||
<span class="strategy-icon">{{ strategy.icon }}</span>
|
||||
<span class="strategy-name">{{ strategy.name }}</span>
|
||||
@@ -28,32 +32,46 @@
|
||||
<div class="browser-window">
|
||||
<div class="browser-header">
|
||||
<div class="browser-controls">
|
||||
<span class="dot red"></span>
|
||||
<span class="dot yellow"></span>
|
||||
<span class="dot green"></span>
|
||||
<span class="dot red" />
|
||||
<span class="dot yellow" />
|
||||
<span class="dot green" />
|
||||
</div>
|
||||
<div class="browser-url">
|
||||
{{ selectedStrategy.url }}
|
||||
</div>
|
||||
<div class="browser-url">{{ selectedStrategy.url }}</div>
|
||||
</div>
|
||||
|
||||
<div class="browser-content">
|
||||
<div class="loading-overlay" v-if="isLoading">
|
||||
<div class="spinner"></div>
|
||||
<div class="loading-text">加载中... ({{ loadingProgress }}%)</div>
|
||||
<div
|
||||
v-if="isLoading"
|
||||
class="loading-overlay"
|
||||
>
|
||||
<div class="spinner" />
|
||||
<div class="loading-text">
|
||||
加载中... ({{ loadingProgress }}%)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-content" v-else>
|
||||
<div
|
||||
v-else
|
||||
class="page-content"
|
||||
>
|
||||
<div class="page-hero">
|
||||
<h2>{{ selectedStrategy.pageTitle }}</h2>
|
||||
</div>
|
||||
<div class="page-body">
|
||||
<div
|
||||
class="resource-item"
|
||||
v-for="(resource, index) in selectedStrategy.resources"
|
||||
:key="index"
|
||||
class="resource-item"
|
||||
>
|
||||
<div class="resource-icon">{{ resource.icon }}</div>
|
||||
<div class="resource-icon">
|
||||
{{ resource.icon }}
|
||||
</div>
|
||||
<div class="resource-info">
|
||||
<div class="resource-name">{{ resource.name }}</div>
|
||||
<div class="resource-name">
|
||||
{{ resource.name }}
|
||||
</div>
|
||||
<div
|
||||
class="resource-status"
|
||||
:class="resource.cached ? 'cached' : 'network'"
|
||||
@@ -61,8 +79,12 @@
|
||||
{{ resource.cached ? '✓ 来自缓存' : '↓ 从服务器下载' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-size">{{ resource.size }}</div>
|
||||
<div class="resource-time">{{ resource.time }}</div>
|
||||
<div class="resource-size">
|
||||
{{ resource.size }}
|
||||
</div>
|
||||
<div class="resource-time">
|
||||
{{ resource.time }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -75,7 +97,10 @@
|
||||
<span class="metric-icon">⚡</span>
|
||||
<span class="metric-title">加载时间</span>
|
||||
</div>
|
||||
<div class="metric-value" :class="selectedStrategy.performanceClass">
|
||||
<div
|
||||
class="metric-value"
|
||||
:class="selectedStrategy.performanceClass"
|
||||
>
|
||||
{{ selectedStrategy.loadTime }}
|
||||
</div>
|
||||
<div
|
||||
@@ -91,12 +116,14 @@
|
||||
<span class="metric-icon">💾</span>
|
||||
<span class="metric-title">缓存命中</span>
|
||||
</div>
|
||||
<div class="metric-value">{{ selectedStrategy.cacheHit }}%</div>
|
||||
<div class="metric-value">
|
||||
{{ selectedStrategy.cacheHit }}%
|
||||
</div>
|
||||
<div class="metric-bar">
|
||||
<div
|
||||
class="metric-fill"
|
||||
:style="{ width: selectedStrategy.cacheHit + '%' }"
|
||||
></div>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -119,7 +146,9 @@
|
||||
<h3>{{ selectedStrategy.name }} 说明</h3>
|
||||
<p>{{ selectedStrategy.description }}</p>
|
||||
<div class="code-example">
|
||||
<div class="code-header">配置示例</div>
|
||||
<div class="code-header">
|
||||
配置示例
|
||||
</div>
|
||||
<pre><code>{{ selectedStrategy.code }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+148
-47
@@ -5,7 +5,9 @@
|
||||
<template>
|
||||
<div class="crp-demo">
|
||||
<div class="header">
|
||||
<div class="title">关键渲染路径 (Critical Rendering Path)</div>
|
||||
<div class="title">
|
||||
关键渲染路径 (Critical Rendering Path)
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
浏览器如何将 HTML、CSS 和 JavaScript 转换为像素
|
||||
</div>
|
||||
@@ -32,87 +34,158 @@
|
||||
</div>
|
||||
|
||||
<div class="arrow-section">
|
||||
<div class="arrow">→</div>
|
||||
<div class="arrow">
|
||||
→
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="process-section">
|
||||
<div class="step" :class="{ active: currentStep === 'dom' }">
|
||||
<div
|
||||
class="step"
|
||||
:class="{ active: currentStep === 'dom' }"
|
||||
>
|
||||
<div class="step-header">
|
||||
<div class="step-icon">🌲</div>
|
||||
<div class="step-title">DOM 树</div>
|
||||
<div class="step-icon">
|
||||
🌲
|
||||
</div>
|
||||
<div class="step-title">
|
||||
DOM 树
|
||||
</div>
|
||||
</div>
|
||||
<div class="tree-visualization">
|
||||
<div class="tree-node root">html</div>
|
||||
<div class="tree-node root">
|
||||
html
|
||||
</div>
|
||||
<div class="tree-children">
|
||||
<div class="tree-node">head</div>
|
||||
<div class="tree-node">body</div>
|
||||
<div class="tree-node">
|
||||
head
|
||||
</div>
|
||||
<div class="tree-node">
|
||||
body
|
||||
</div>
|
||||
<div class="tree-children">
|
||||
<div class="tree-node">div.container</div>
|
||||
<div class="tree-node">
|
||||
div.container
|
||||
</div>
|
||||
<div class="tree-children">
|
||||
<div class="tree-node">h1</div>
|
||||
<div class="tree-node">p</div>
|
||||
<div class="tree-node">
|
||||
h1
|
||||
</div>
|
||||
<div class="tree-node">
|
||||
p
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step" :class="{ active: currentStep === 'cssom' }">
|
||||
<div
|
||||
class="step"
|
||||
:class="{ active: currentStep === 'cssom' }"
|
||||
>
|
||||
<div class="step-header">
|
||||
<div class="step-icon">🎨</div>
|
||||
<div class="step-title">CSSOM 树</div>
|
||||
<div class="step-icon">
|
||||
🎨
|
||||
</div>
|
||||
<div class="step-title">
|
||||
CSSOM 树
|
||||
</div>
|
||||
</div>
|
||||
<div class="tree-visualization">
|
||||
<div class="tree-node root">body</div>
|
||||
<div class="tree-node root">
|
||||
body
|
||||
</div>
|
||||
<div class="tree-children">
|
||||
<div class="tree-node">.container</div>
|
||||
<div class="tree-node">
|
||||
.container
|
||||
</div>
|
||||
<div class="tree-children">
|
||||
<div class="tree-node">h1</div>
|
||||
<div class="tree-node">p</div>
|
||||
<div class="tree-node">
|
||||
h1
|
||||
</div>
|
||||
<div class="tree-node">
|
||||
p
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step" :class="{ active: currentStep === 'render' }">
|
||||
<div
|
||||
class="step"
|
||||
:class="{ active: currentStep === 'render' }"
|
||||
>
|
||||
<div class="step-header">
|
||||
<div class="step-icon">🖼️</div>
|
||||
<div class="step-title">渲染树</div>
|
||||
<div class="step-icon">
|
||||
🖼️
|
||||
</div>
|
||||
<div class="step-title">
|
||||
渲染树
|
||||
</div>
|
||||
</div>
|
||||
<div class="tree-visualization">
|
||||
<div class="tree-node root">body</div>
|
||||
<div class="tree-node root">
|
||||
body
|
||||
</div>
|
||||
<div class="tree-children">
|
||||
<div class="tree-node">div.container</div>
|
||||
<div class="tree-node">
|
||||
div.container
|
||||
</div>
|
||||
<div class="tree-children">
|
||||
<div class="tree-node">h1</div>
|
||||
<div class="tree-node">p</div>
|
||||
<div class="tree-node">
|
||||
h1
|
||||
</div>
|
||||
<div class="tree-node">
|
||||
p
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step" :class="{ active: currentStep === 'layout' }">
|
||||
<div
|
||||
class="step"
|
||||
:class="{ active: currentStep === 'layout' }"
|
||||
>
|
||||
<div class="step-header">
|
||||
<div class="step-icon">📐</div>
|
||||
<div class="step-title">布局 (Layout)</div>
|
||||
<div class="step-icon">
|
||||
📐
|
||||
</div>
|
||||
<div class="step-title">
|
||||
布局 (Layout)
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-demo">
|
||||
<div class="layout-box container">
|
||||
<div class="layout-label">container</div>
|
||||
<div class="layout-label">
|
||||
container
|
||||
</div>
|
||||
<div class="layout-box h1">
|
||||
<div class="layout-label">h1</div>
|
||||
<div class="layout-label">
|
||||
h1
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-box p">
|
||||
<div class="layout-label">p</div>
|
||||
<div class="layout-label">
|
||||
p
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step" :class="{ active: currentStep === 'paint' }">
|
||||
<div
|
||||
class="step"
|
||||
:class="{ active: currentStep === 'paint' }"
|
||||
>
|
||||
<div class="step-header">
|
||||
<div class="step-icon">🖌️</div>
|
||||
<div class="step-title">绘制 (Paint)</div>
|
||||
<div class="step-icon">
|
||||
🖌️
|
||||
</div>
|
||||
<div class="step-title">
|
||||
绘制 (Paint)
|
||||
</div>
|
||||
</div>
|
||||
<div class="paint-demo">
|
||||
<div class="paint-box container">
|
||||
@@ -124,23 +197,40 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step" :class="{ active: currentStep === 'composite' }">
|
||||
<div
|
||||
class="step"
|
||||
:class="{ active: currentStep === 'composite' }"
|
||||
>
|
||||
<div class="step-header">
|
||||
<div class="step-icon">✨</div>
|
||||
<div class="step-title">合成 (Composite)</div>
|
||||
<div class="step-icon">
|
||||
✨
|
||||
</div>
|
||||
<div class="step-title">
|
||||
合成 (Composite)
|
||||
</div>
|
||||
</div>
|
||||
<div class="composite-demo">
|
||||
<div class="composite-layer">图层 1: 背景</div>
|
||||
<div class="composite-layer">图层 2: 内容</div>
|
||||
<div class="composite-layer">图层 3: 装饰</div>
|
||||
<div class="composite-result">= 最终页面</div>
|
||||
<div class="composite-layer">
|
||||
图层 1: 背景
|
||||
</div>
|
||||
<div class="composite-layer">
|
||||
图层 2: 内容
|
||||
</div>
|
||||
<div class="composite-layer">
|
||||
图层 3: 装饰
|
||||
</div>
|
||||
<div class="composite-result">
|
||||
= 最终页面
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline">
|
||||
<div class="timeline-header">渲染时间线</div>
|
||||
<div class="timeline-header">
|
||||
渲染时间线
|
||||
</div>
|
||||
<div class="timeline-bar">
|
||||
<div
|
||||
v-for="(step, index) in timelineSteps"
|
||||
@@ -154,7 +244,10 @@
|
||||
}"
|
||||
@click="setStep(step.name)"
|
||||
>
|
||||
<div class="segment-label" :style="{ color: step.color }">
|
||||
<div
|
||||
class="segment-label"
|
||||
:style="{ color: step.color }"
|
||||
>
|
||||
{{ step.label }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -167,7 +260,9 @@
|
||||
|
||||
<div class="optimization-tips">
|
||||
<div class="tip-card">
|
||||
<div class="tip-icon">⚡</div>
|
||||
<div class="tip-icon">
|
||||
⚡
|
||||
</div>
|
||||
<div class="tip-content">
|
||||
<h4>优化 DOM 构建</h4>
|
||||
<p>减少 HTML 嵌套层级,避免不必要的标签。使用语义化 HTML。</p>
|
||||
@@ -175,7 +270,9 @@
|
||||
</div>
|
||||
|
||||
<div class="tip-card">
|
||||
<div class="tip-icon">🎨</div>
|
||||
<div class="tip-icon">
|
||||
🎨
|
||||
</div>
|
||||
<div class="tip-content">
|
||||
<h4>优化 CSS</h4>
|
||||
<p>CSS 是渲染阻塞资源。将关键 CSS 内联,异步加载非关键 CSS。</p>
|
||||
@@ -183,7 +280,9 @@
|
||||
</div>
|
||||
|
||||
<div class="tip-card">
|
||||
<div class="tip-icon">⚙️</div>
|
||||
<div class="tip-icon">
|
||||
⚙️
|
||||
</div>
|
||||
<div class="tip-content">
|
||||
<h4>优化 JavaScript</h4>
|
||||
<p>
|
||||
@@ -194,7 +293,9 @@
|
||||
</div>
|
||||
|
||||
<div class="tip-card">
|
||||
<div class="tip-icon">📐</div>
|
||||
<div class="tip-icon">
|
||||
📐
|
||||
</div>
|
||||
<div class="tip-content">
|
||||
<h4>减少重排</h4>
|
||||
<p>
|
||||
|
||||
+40
-13
@@ -5,8 +5,12 @@
|
||||
<template>
|
||||
<div class="image-optimization-demo">
|
||||
<div class="header">
|
||||
<div class="title">图片格式对比:大小与质量的权衡</div>
|
||||
<div class="subtitle">对比不同图片格式的大小和质量</div>
|
||||
<div class="title">
|
||||
图片格式对比:大小与质量的权衡
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
对比不同图片格式的大小和质量
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="format-grid">
|
||||
@@ -18,16 +22,28 @@
|
||||
@click="selectFormat(format.name)"
|
||||
>
|
||||
<div class="format-header">
|
||||
<div class="format-name">{{ format.name }}</div>
|
||||
<div class="format-badge" :class="format.badgeClass">
|
||||
<div class="format-name">
|
||||
{{ format.name }}
|
||||
</div>
|
||||
<div
|
||||
class="format-badge"
|
||||
:class="format.badgeClass"
|
||||
>
|
||||
{{ format.badge }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="format-preview" :style="{ background: format.gradient }">
|
||||
<div
|
||||
class="format-preview"
|
||||
:style="{ background: format.gradient }"
|
||||
>
|
||||
<div class="preview-content">
|
||||
<div class="preview-image">🖼️</div>
|
||||
<div class="preview-size">{{ format.size }}</div>
|
||||
<div class="preview-image">
|
||||
🖼️
|
||||
</div>
|
||||
<div class="preview-size">
|
||||
{{ format.size }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -46,7 +62,7 @@
|
||||
<div
|
||||
class="quality-fill"
|
||||
:style="{ width: format.quality + '%' }"
|
||||
></div>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
@@ -56,8 +72,12 @@
|
||||
</div>
|
||||
|
||||
<div class="format-use-case">
|
||||
<div class="use-case-label">适用场景</div>
|
||||
<div class="use-case-value">{{ format.useCase }}</div>
|
||||
<div class="use-case-label">
|
||||
适用场景
|
||||
</div>
|
||||
<div class="use-case-value">
|
||||
{{ format.useCase }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -76,7 +96,10 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="format in formats" :key="format.name">
|
||||
<tr
|
||||
v-for="format in formats"
|
||||
:key="format.name"
|
||||
>
|
||||
<td>
|
||||
<strong>{{ format.name }}</strong>
|
||||
</td>
|
||||
@@ -99,7 +122,9 @@
|
||||
|
||||
<div class="tips">
|
||||
<div class="tip-card">
|
||||
<div class="tip-icon">💡</div>
|
||||
<div class="tip-icon">
|
||||
💡
|
||||
</div>
|
||||
<div class="tip-content">
|
||||
<h4>优化建议</h4>
|
||||
<ul>
|
||||
@@ -115,7 +140,9 @@
|
||||
</div>
|
||||
|
||||
<div class="tip-card">
|
||||
<div class="tip-icon">🔧</div>
|
||||
<div class="tip-icon">
|
||||
🔧
|
||||
</div>
|
||||
<div class="tip-content">
|
||||
<h4>工具推荐</h4>
|
||||
<ul>
|
||||
|
||||
+40
-16
@@ -5,21 +5,25 @@
|
||||
<template>
|
||||
<div class="lazy-loading-demo">
|
||||
<div class="header">
|
||||
<div class="title">图片懒加载:节省带宽,提升性能</div>
|
||||
<div class="subtitle">对比懒加载和立即加载的区别</div>
|
||||
<div class="title">
|
||||
图片懒加载:节省带宽,提升性能
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
对比懒加载和立即加载的区别
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-container">
|
||||
<div class="mode-selector">
|
||||
<button
|
||||
@click="mode = 'eager'"
|
||||
:class="['mode-btn', { active: mode === 'eager' }]"
|
||||
@click="mode = 'eager'"
|
||||
>
|
||||
📦 立即加载
|
||||
</button>
|
||||
<button
|
||||
@click="mode = 'lazy'"
|
||||
:class="['mode-btn', { active: mode === 'lazy' }]"
|
||||
@click="mode = 'lazy'"
|
||||
>
|
||||
⏳ 懒加载
|
||||
</button>
|
||||
@@ -32,7 +36,10 @@
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-label">节省流量</span>
|
||||
<span class="stat-value" :class="{ positive: savedBandwidth > 0 }">
|
||||
<span
|
||||
class="stat-value"
|
||||
:class="{ positive: savedBandwidth > 0 }"
|
||||
>
|
||||
{{ savedBandwidth > 0 ? '-' : '' }}{{ savedBandwidth }} KB
|
||||
</span>
|
||||
</div>
|
||||
@@ -43,18 +50,20 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="scroll-container"
|
||||
ref="scrollContainer"
|
||||
class="scroll-container"
|
||||
@scroll="handleScroll"
|
||||
>
|
||||
<div class="content-area">
|
||||
<div class="placeholder">向下滚动查看更多内容</div>
|
||||
<div class="placeholder">
|
||||
向下滚动查看更多内容
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="(image, index) in images"
|
||||
:key="index"
|
||||
class="image-item"
|
||||
:ref="(el) => setImageRef(el, index)"
|
||||
class="image-item"
|
||||
>
|
||||
<div
|
||||
class="image-wrapper"
|
||||
@@ -64,21 +73,36 @@
|
||||
v-if="!image.loaded && mode === 'lazy'"
|
||||
class="placeholder-box"
|
||||
>
|
||||
<div class="spinner"></div>
|
||||
<div class="placeholder-text">加载中...</div>
|
||||
<div class="spinner" />
|
||||
<div class="placeholder-text">
|
||||
加载中...
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="image.loaded" class="image-box">
|
||||
<div class="image-icon">🖼️</div>
|
||||
<div
|
||||
v-else-if="image.loaded"
|
||||
class="image-box"
|
||||
>
|
||||
<div class="image-icon">
|
||||
🖼️
|
||||
</div>
|
||||
<div class="image-info">
|
||||
<div class="image-size">{{ image.size }}</div>
|
||||
<div class="image-dim">{{ image.dimensions }}</div>
|
||||
<div class="image-size">
|
||||
{{ image.size }}
|
||||
</div>
|
||||
<div class="image-dim">
|
||||
{{ image.dimensions }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="image-caption">图片 {{ index + 1 }}</div>
|
||||
<div class="image-caption">
|
||||
图片 {{ index + 1 }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="placeholder">已经到底了</div>
|
||||
<div class="placeholder">
|
||||
已经到底了
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
+96
-32
@@ -20,66 +20,130 @@
|
||||
min="0.5"
|
||||
max="5"
|
||||
step="0.1"
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="metrics-grid">
|
||||
<div class="metric-card" :class="fcpStatus.class">
|
||||
<div
|
||||
class="metric-card"
|
||||
:class="fcpStatus.class"
|
||||
>
|
||||
<div class="metric-header">
|
||||
<div class="metric-name">FCP</div>
|
||||
<div class="metric-full">First Contentful Paint</div>
|
||||
<div class="metric-name">
|
||||
FCP
|
||||
</div>
|
||||
<div class="metric-full">
|
||||
First Contentful Paint
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric-value">{{ fcp }} s</div>
|
||||
<div class="metric-desc">首次内容绘制</div>
|
||||
<div class="metric-status">{{ fcpStatus.text }}</div>
|
||||
<div class="indicator" :class="fcpStatus.class"></div>
|
||||
<div class="metric-value">
|
||||
{{ fcp }} s
|
||||
</div>
|
||||
<div class="metric-desc">
|
||||
首次内容绘制
|
||||
</div>
|
||||
<div class="metric-status">
|
||||
{{ fcpStatus.text }}
|
||||
</div>
|
||||
<div
|
||||
class="indicator"
|
||||
:class="fcpStatus.class"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="metric-card" :class="lcpStatus.class">
|
||||
<div
|
||||
class="metric-card"
|
||||
:class="lcpStatus.class"
|
||||
>
|
||||
<div class="metric-header">
|
||||
<div class="metric-name">LCP</div>
|
||||
<div class="metric-full">Largest Contentful Paint</div>
|
||||
<div class="metric-name">
|
||||
LCP
|
||||
</div>
|
||||
<div class="metric-full">
|
||||
Largest Contentful Paint
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric-value">{{ lcp }} s</div>
|
||||
<div class="metric-desc">最大内容绘制</div>
|
||||
<div class="metric-status">{{ lcpStatus.text }}</div>
|
||||
<div class="indicator" :class="lcpStatus.class"></div>
|
||||
<div class="metric-value">
|
||||
{{ lcp }} s
|
||||
</div>
|
||||
<div class="metric-desc">
|
||||
最大内容绘制
|
||||
</div>
|
||||
<div class="metric-status">
|
||||
{{ lcpStatus.text }}
|
||||
</div>
|
||||
<div
|
||||
class="indicator"
|
||||
:class="lcpStatus.class"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="metric-card" :class="fidStatus.class">
|
||||
<div
|
||||
class="metric-card"
|
||||
:class="fidStatus.class"
|
||||
>
|
||||
<div class="metric-header">
|
||||
<div class="metric-name">FID</div>
|
||||
<div class="metric-full">First Input Delay</div>
|
||||
<div class="metric-name">
|
||||
FID
|
||||
</div>
|
||||
<div class="metric-full">
|
||||
First Input Delay
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric-value">{{ fid }} ms</div>
|
||||
<div class="metric-desc">首次输入延迟</div>
|
||||
<div class="metric-status">{{ fidStatus.text }}</div>
|
||||
<div class="indicator" :class="fidStatus.class"></div>
|
||||
<div class="metric-value">
|
||||
{{ fid }} ms
|
||||
</div>
|
||||
<div class="metric-desc">
|
||||
首次输入延迟
|
||||
</div>
|
||||
<div class="metric-status">
|
||||
{{ fidStatus.text }}
|
||||
</div>
|
||||
<div
|
||||
class="indicator"
|
||||
:class="fidStatus.class"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="metric-card" :class="clsStatus.class">
|
||||
<div
|
||||
class="metric-card"
|
||||
:class="clsStatus.class"
|
||||
>
|
||||
<div class="metric-header">
|
||||
<div class="metric-name">CLS</div>
|
||||
<div class="metric-full">Cumulative Layout Shift</div>
|
||||
<div class="metric-name">
|
||||
CLS
|
||||
</div>
|
||||
<div class="metric-full">
|
||||
Cumulative Layout Shift
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric-value">{{ cls }}</div>
|
||||
<div class="metric-desc">累积布局偏移</div>
|
||||
<div class="metric-status">{{ clsStatus.text }}</div>
|
||||
<div class="indicator" :class="clsStatus.class"></div>
|
||||
<div class="metric-value">
|
||||
{{ cls }}
|
||||
</div>
|
||||
<div class="metric-desc">
|
||||
累积布局偏移
|
||||
</div>
|
||||
<div class="metric-status">
|
||||
{{ clsStatus.text }}
|
||||
</div>
|
||||
<div
|
||||
class="indicator"
|
||||
:class="clsStatus.class"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="standards">
|
||||
<div class="standard-item">
|
||||
<span class="color-box good"></span>
|
||||
<span class="color-box good" />
|
||||
<span>良好</span>
|
||||
</div>
|
||||
<div class="standard-item">
|
||||
<span class="color-box needs-improvement"></span>
|
||||
<span class="color-box needs-improvement" />
|
||||
<span>需改进</span>
|
||||
</div>
|
||||
<div class="standard-item">
|
||||
<span class="color-box poor"></span>
|
||||
<span class="color-box poor" />
|
||||
<span>差</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+39
-12
@@ -9,8 +9,12 @@
|
||||
<template>
|
||||
<div class="performance-overview">
|
||||
<div class="header">
|
||||
<div class="title">前端性能优化全景图</div>
|
||||
<div class="subtitle">点击下方维度,探索性能瓶颈与优化方案的对应关系</div>
|
||||
<div class="title">
|
||||
前端性能优化全景图
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
点击下方维度,探索性能瓶颈与优化方案的对应关系
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 维度切换 -->
|
||||
@@ -28,23 +32,35 @@
|
||||
</div>
|
||||
|
||||
<!-- 内容展示区 -->
|
||||
<div class="content-area" :class="currentDim.id">
|
||||
<div
|
||||
class="content-area"
|
||||
:class="currentDim.id"
|
||||
>
|
||||
<div class="panel bottlenecks">
|
||||
<h3>
|
||||
<span class="icon">⚠️</span>
|
||||
常见瓶颈 (Bottlenecks)
|
||||
</h3>
|
||||
<ul class="list">
|
||||
<li v-for="(item, index) in currentDim.bottlenecks" :key="index">
|
||||
<div class="item-title">{{ item.title }}</div>
|
||||
<div class="item-desc">{{ item.desc }}</div>
|
||||
<li
|
||||
v-for="(item, index) in currentDim.bottlenecks"
|
||||
:key="index"
|
||||
>
|
||||
<div class="item-title">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
<div class="item-desc">
|
||||
{{ item.desc }}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="arrow">
|
||||
<div class="arrow-line"></div>
|
||||
<div class="arrow-text">如何解决?</div>
|
||||
<div class="arrow-line" />
|
||||
<div class="arrow-text">
|
||||
如何解决?
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel solutions">
|
||||
@@ -53,11 +69,22 @@
|
||||
优化方案 (Solutions)
|
||||
</h3>
|
||||
<ul class="list">
|
||||
<li v-for="(item, index) in currentDim.solutions" :key="index">
|
||||
<div class="item-title">{{ item.title }}</div>
|
||||
<div class="item-desc">{{ item.desc }}</div>
|
||||
<li
|
||||
v-for="(item, index) in currentDim.solutions"
|
||||
:key="index"
|
||||
>
|
||||
<div class="item-title">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
<div class="item-desc">
|
||||
{{ item.desc }}
|
||||
</div>
|
||||
<div class="tags">
|
||||
<span v-for="tag in item.tags" :key="tag" class="tag">{{ tag }}</span>
|
||||
<span
|
||||
v-for="tag in item.tags"
|
||||
:key="tag"
|
||||
class="tag"
|
||||
>{{ tag }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
+94
-23
@@ -37,54 +37,113 @@
|
||||
</div>
|
||||
|
||||
<div class="performance-meter">
|
||||
<div class="meter-label">性能影响</div>
|
||||
<div class="meter-label">
|
||||
性能影响
|
||||
</div>
|
||||
<div class="meter-bar">
|
||||
<div
|
||||
class="meter-fill"
|
||||
:class="performanceLevel.class"
|
||||
:style="{ width: performanceImpact + '%' }"
|
||||
></div>
|
||||
/>
|
||||
</div>
|
||||
<div class="meter-value" :class="performanceLevel.class">
|
||||
<div
|
||||
class="meter-value"
|
||||
:class="performanceLevel.class"
|
||||
>
|
||||
{{ performanceLevel.text }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats">
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">操作类型</div>
|
||||
<div class="stat-value">{{ currentOperation }}</div>
|
||||
<div class="stat-label">
|
||||
操作类型
|
||||
</div>
|
||||
<div class="stat-value">
|
||||
{{ currentOperation }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">影响范围</div>
|
||||
<div class="stat-value">{{ affectedElements }} 个元素</div>
|
||||
<div class="stat-label">
|
||||
影响范围
|
||||
</div>
|
||||
<div class="stat-value">
|
||||
{{ affectedElements }} 个元素
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<div v-if="activeTab === 'reflow'" class="control-group">
|
||||
<button @click="changeWidth" class="btn high-impact">改变宽度</button>
|
||||
<button @click="changePosition" class="btn high-impact">改变位置</button>
|
||||
<button @click="addBox" class="btn high-impact">添加元素</button>
|
||||
<div
|
||||
v-if="activeTab === 'reflow'"
|
||||
class="control-group"
|
||||
>
|
||||
<button
|
||||
class="btn high-impact"
|
||||
@click="changeWidth"
|
||||
>
|
||||
改变宽度
|
||||
</button>
|
||||
<button
|
||||
class="btn high-impact"
|
||||
@click="changePosition"
|
||||
>
|
||||
改变位置
|
||||
</button>
|
||||
<button
|
||||
class="btn high-impact"
|
||||
@click="addBox"
|
||||
>
|
||||
添加元素
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="activeTab === 'repaint'" class="control-group">
|
||||
<button @click="changeColor" class="btn medium-impact">改变颜色</button>
|
||||
<button @click="changeBackground" class="btn medium-impact">
|
||||
<div
|
||||
v-if="activeTab === 'repaint'"
|
||||
class="control-group"
|
||||
>
|
||||
<button
|
||||
class="btn medium-impact"
|
||||
@click="changeColor"
|
||||
>
|
||||
改变颜色
|
||||
</button>
|
||||
<button
|
||||
class="btn medium-impact"
|
||||
@click="changeBackground"
|
||||
>
|
||||
改变背景
|
||||
</button>
|
||||
<button @click="toggleBorder" class="btn medium-impact">切换边框</button>
|
||||
<button
|
||||
class="btn medium-impact"
|
||||
@click="toggleBorder"
|
||||
>
|
||||
切换边框
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="activeTab === 'composite'" class="control-group">
|
||||
<button @click="transformTranslate" class="btn low-impact">
|
||||
<div
|
||||
v-if="activeTab === 'composite'"
|
||||
class="control-group"
|
||||
>
|
||||
<button
|
||||
class="btn low-impact"
|
||||
@click="transformTranslate"
|
||||
>
|
||||
Transform 位移
|
||||
</button>
|
||||
<button @click="transformRotate" class="btn low-impact">
|
||||
<button
|
||||
class="btn low-impact"
|
||||
@click="transformRotate"
|
||||
>
|
||||
Transform 旋转
|
||||
</button>
|
||||
<button @click="changeOpacity" class="btn low-impact">
|
||||
<button
|
||||
class="btn low-impact"
|
||||
@click="changeOpacity"
|
||||
>
|
||||
改变透明度
|
||||
</button>
|
||||
</div>
|
||||
@@ -92,18 +151,30 @@
|
||||
</div>
|
||||
|
||||
<Transition name="fade">
|
||||
<div v-if="activeTab" class="tab-info">
|
||||
<div v-if="activeTab === 'reflow'" class="info-content">
|
||||
<div
|
||||
v-if="activeTab"
|
||||
class="tab-info"
|
||||
>
|
||||
<div
|
||||
v-if="activeTab === 'reflow'"
|
||||
class="info-content"
|
||||
>
|
||||
<p>
|
||||
<strong>重排 (Reflow)</strong>:当元素的位置、尺寸发生变化时,浏览器需要重新计算布局。重排开销最大,因为要重新计算所有受影响元素的位置。
|
||||
</p>
|
||||
</div>
|
||||
<div v-if="activeTab === 'repaint'" class="info-content">
|
||||
<div
|
||||
v-if="activeTab === 'repaint'"
|
||||
class="info-content"
|
||||
>
|
||||
<p>
|
||||
<strong>重绘 (Repaint)</strong>:当元素的外观(颜色、背景)发生变化,但位置不变时,浏览器只需要重新绘制像素。比重排快,但仍有开销。
|
||||
</p>
|
||||
</div>
|
||||
<div v-if="activeTab === 'composite'" class="info-content">
|
||||
<div
|
||||
v-if="activeTab === 'composite'"
|
||||
class="info-content"
|
||||
>
|
||||
<p>
|
||||
<strong>合成 (Composite)</strong>:使用 transform 和 opacity 等属性,浏览器可以在合成层上完成变化,完全不触发布局和绘制。性能最佳,推荐优先使用。
|
||||
</p>
|
||||
|
||||
+21
-8
@@ -53,15 +53,25 @@ const renderedCount = computed(() => visibleItems.value.length)
|
||||
|
||||
<div class="controls">
|
||||
<div class="stat-box">
|
||||
<div class="stat-label">总数据量</div>
|
||||
<div class="stat-value">{{ TOTAL_ITEMS.toLocaleString() }}</div>
|
||||
<div class="stat-label">
|
||||
总数据量
|
||||
</div>
|
||||
<div class="stat-value">
|
||||
{{ TOTAL_ITEMS.toLocaleString() }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-box highlight">
|
||||
<div class="stat-label">实际渲染</div>
|
||||
<div class="stat-value">{{ renderedCount }}</div>
|
||||
<div class="stat-label">
|
||||
实际渲染
|
||||
</div>
|
||||
<div class="stat-value">
|
||||
{{ renderedCount }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-box">
|
||||
<div class="stat-label">节省内存</div>
|
||||
<div class="stat-label">
|
||||
节省内存
|
||||
</div>
|
||||
<div class="stat-value">
|
||||
~{{ ((1 - renderedCount / TOTAL_ITEMS) * 100).toFixed(1) }}%
|
||||
</div>
|
||||
@@ -69,12 +79,15 @@ const renderedCount = computed(() => visibleItems.value.length)
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="scroll-container"
|
||||
ref="containerRef"
|
||||
@scroll="onScroll"
|
||||
class="scroll-container"
|
||||
:style="{ height: CONTAINER_HEIGHT + 'px' }"
|
||||
@scroll="onScroll"
|
||||
>
|
||||
<div class="scroll-phantom" :style="{ height: totalHeight + 'px' }"></div>
|
||||
<div
|
||||
class="scroll-phantom"
|
||||
:style="{ height: totalHeight + 'px' }"
|
||||
/>
|
||||
<div class="visible-list">
|
||||
<div
|
||||
v-for="item in visibleItems"
|
||||
|
||||
Reference in New Issue
Block a user