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:
sanbuphy
2026-02-18 17:38:10 +08:00
parent 8b01686e68
commit 0eba9e87e9
456 changed files with 28450 additions and 9677 deletions
@@ -21,8 +21,13 @@
@click="activeEra = activeEra === era.id ? null : era.id"
>
<div class="era-marker">
<div class="era-dot">{{ era.emoji }}</div>
<div v-if="index < eras.length - 1" class="era-line"></div>
<div class="era-dot">
{{ era.emoji }}
</div>
<div
v-if="index < eras.length - 1"
class="era-line"
/>
</div>
<div class="era-content">
@@ -31,12 +36,19 @@
<span class="era-name">{{ era.name }}</span>
</div>
<div class="era-brief">{{ era.brief }}</div>
<div class="era-brief">
{{ era.brief }}
</div>
<Transition name="expand">
<div v-if="activeEra === era.id" class="era-detail">
<div
v-if="activeEra === era.id"
class="era-detail"
>
<div class="detail-section">
<div class="section-title">🔑 关键技术</div>
<div class="section-title">
🔑 关键技术
</div>
<div class="tech-tags">
<span
v-for="tech in era.technologies.slice(0, 5)"
@@ -46,9 +58,16 @@
</div>
</div>
<div class="detail-section" v-if="era.metaphor">
<div class="section-title">💡 生活比喻</div>
<div class="metaphor-box">{{ era.metaphor }}</div>
<div
v-if="era.metaphor"
class="detail-section"
>
<div class="section-title">
💡 生活比喻
</div>
<div class="metaphor-box">
{{ era.metaphor }}
</div>
</div>
</div>
</Transition>
@@ -25,41 +25,64 @@
</button>
</div>
<div class="comparison-container">
<!-- Imperative Side (jQuery) -->
<div class="side imperative-side">
<div class="side-header">
<span class="badge imperative">jQuery / 命令式</span>
<span class="sub-label">通俗说法: 告诉怎么做</span>
</div>
<div class="demo-area">
<!-- The UI -->
<div class="counter-ui">
<div class="display-value" id="jq-display">{{ jqCount }}</div>
<div class="meters">
<div class="meter-label">Progress:</div>
<div class="meter-bar">
<div
class="meter-fill"
id="jq-meter"
:style="{ width: jqProgress + '%' }"
></div>
</div>
<div class="status-text" id="jq-status">
{{ jqStatus }}
</div>
</div>
<div class="controls">
<button class="btn-decrement" @click="updateJq(-1)">-</button>
<button class="btn-increment" @click="updateJq(1)">+</button>
</div>
<div class="comparison-container">
<!-- Imperative Side (jQuery) -->
<div class="side imperative-side">
<div class="side-header">
<span class="badge imperative">jQuery / 命令式</span>
<span class="sub-label">通俗说法: 告诉怎么做</span>
</div>
<!-- The Code -->
<div v-show="currentView === 'code'" class="code-panel">
<div class="code-block imperative-code">
<pre><code>function updateCounter(change) {
<div class="demo-area">
<!-- The UI -->
<div class="counter-ui">
<div
id="jq-display"
class="display-value"
>
{{ jqCount }}
</div>
<div class="meters">
<div class="meter-label">
Progress:
</div>
<div class="meter-bar">
<div
id="jq-meter"
class="meter-fill"
:style="{ width: jqProgress + '%' }"
/>
</div>
<div
id="jq-status"
class="status-text"
>
{{ jqStatus }}
</div>
</div>
<div class="controls">
<button
class="btn-decrement"
@click="updateJq(-1)"
>
-
</button>
<button
class="btn-increment"
@click="updateJq(1)"
>
+
</button>
</div>
</div>
<!-- The Code -->
<div
v-show="currentView === 'code'"
class="code-panel"
>
<div class="code-block imperative-code">
<pre><code>function updateCounter(change) {
// 1. Get current value
var count = parseInt($('#counter').text());
@@ -83,64 +106,89 @@
// 6. Update DOM element 4...
// Oops! Forgot to update the color indicator!
}</code></pre>
</div>
</div>
</div>
<div
v-if="showAnalysis"
class="pain-points"
>
<div class="pain-point">
<span class="icon"></span>
<span>需要手动操作多个 DOM 元素</span>
</div>
<div class="pain-point">
<span class="icon">🐛</span>
<span>容易遗漏更新导致界面不一致</span>
</div>
<div class="pain-point">
<span class="icon">🍝</span>
<span>逻辑分散代码难以维护</span>
</div>
</div>
</div>
<div class="pain-points" v-if="showAnalysis">
<div class="pain-point">
<span class="icon"></span>
<span>需要手动操作多个 DOM 元素</span>
</div>
<div class="pain-point">
<span class="icon">🐛</span>
<span>容易遗漏更新导致界面不一致</span>
</div>
<div class="pain-point">
<span class="icon">🍝</span>
<span>逻辑分散代码难以维护</span>
<!-- VS Divider -->
<div class="vs-divider">
<div class="vs-badge">
VS
</div>
</div>
</div>
<!-- VS Divider -->
<div class="vs-divider">
<div class="vs-badge">VS</div>
</div>
<!-- Declarative Side (Vue) -->
<div class="side declarative-side">
<div class="side-header">
<span class="badge declarative">Vue / 声明式</span>
<span class="sub-label">通俗说法: 告诉要什么</span>
</div>
<!-- Declarative Side (Vue) -->
<div class="side declarative-side">
<div class="side-header">
<span class="badge declarative">Vue / 声明式</span>
<span class="sub-label">通俗说法: 告诉要什么</span>
</div>
<div class="demo-area">
<!-- The UI -->
<div class="counter-ui">
<div class="display-value">{{ vueCount }}</div>
<div class="meters">
<div class="meter-label">Progress:</div>
<div class="meter-bar">
<div class="demo-area">
<!-- The UI -->
<div class="counter-ui">
<div class="display-value">
{{ vueCount }}
</div>
<div class="meters">
<div class="meter-label">
Progress:
</div>
<div class="meter-bar">
<div
class="meter-fill"
:style="{ width: vueProgress + '%' }"
/>
</div>
<div
class="meter-fill"
:style="{ width: vueProgress + '%' }"
></div>
class="status-text"
:class="{ warning: vueCount > 5 }"
>
{{ vueStatus }}
</div>
</div>
<div class="status-text" :class="{ warning: vueCount > 5 }">
{{ vueStatus }}
<div class="controls">
<button
class="btn-decrement"
@click="vueCount--"
>
-
</button>
<button
class="btn-increment"
@click="vueCount++"
>
+
</button>
</div>
</div>
<div class="controls">
<button class="btn-decrement" @click="vueCount--">-</button>
<button class="btn-increment" @click="vueCount++">+</button>
</div>
</div>
<!-- The Code -->
<div v-show="currentView === 'code'" class="code-panel">
<div class="code-block declarative-code">
<pre><code>export default {
<!-- The Code -->
<div
v-show="currentView === 'code'"
class="code-panel"
>
<div class="code-block declarative-code">
<pre><code>export default {
data() {
return {
count: 0
@@ -166,33 +214,39 @@
{{ status }}
&lt;/div&gt;
&lt;/template&gt;</code></pre>
</div>
</div>
</div>
<div
v-if="showAnalysis"
class="benefits"
>
<div class="benefit">
<span class="icon"></span>
<span>只关注数据不用手动操作 DOM</span>
</div>
<div class="benefit">
<span class="icon">🔄</span>
<span>数据变化自动同步到所有相关视图</span>
</div>
<div class="benefit">
<span class="icon">🧩</span>
<span>代码结构清晰易于维护</span>
</div>
</div>
</div>
<div class="benefits" v-if="showAnalysis">
<div class="benefit">
<span class="icon"></span>
<span>只关注数据不用手动操作 DOM</span>
</div>
<div class="benefit">
<span class="icon">🔄</span>
<span>数据变化自动同步到所有相关视图</span>
</div>
<div class="benefit">
<span class="icon">🧩</span>
<span>代码结构清晰易于维护</span>
</div>
</div>
</div>
</div>
<!-- 底部控制 -->
<div class="demo-controls">
<button class="toggle-btn" @click="showAnalysis = !showAnalysis">
{{ showAnalysis ? '隐藏' : '显示' }}对比分析
</button>
</div>
<!-- 底部控制 -->
<div class="demo-controls">
<button
class="toggle-btn"
@click="showAnalysis = !showAnalysis"
>
{{ showAnalysis ? '隐藏' : '显示' }}对比分析
</button>
</div>
</div>
<!-- 信息框 -->
@@ -52,8 +52,12 @@
class="step-item"
:class="{ active: index === currentStep }"
>
<div class="step-number">{{ index + 1 }}</div>
<div class="step-text">{{ step }}</div>
<div class="step-number">
{{ index + 1 }}
</div>
<div class="step-text">
{{ step }}
</div>
</div>
</div>
</div>
@@ -64,7 +68,10 @@
<div class="ledger-header">
<span class="ledger-icon">📒</span>
<span class="ledger-title">今日账本</span>
<span class="ledger-status" :class="mode">{{ ledgerStatus }}</span>
<span
class="ledger-status"
:class="mode"
>{{ ledgerStatus }}</span>
</div>
<div class="ledger-content">
@@ -105,8 +112,8 @@
<div class="action-buttons">
<button
class="btn btn-primary"
@click="processOrder"
:disabled="isProcessing || allCompleted"
@click="processOrder"
>
{{ isProcessing ? '处理中...' : allCompleted ? '今日完成!' : '下一道菜' }}
</button>
@@ -6,8 +6,12 @@
<div class="rendering-demo">
<!-- 故事引入 -->
<div class="story-box">
<div class="story-emoji">🍽👨🍳</div>
<h4 class="story-title">小美的餐厅</h4>
<div class="story-emoji">
🍽👨🍳
</div>
<h4 class="story-title">
小美的餐厅
</h4>
<p class="story-text">
小美开了家餐厅有三种上菜方式<br>
<strong>CSR客户端渲染</strong>给你半成品食材包你自己做 <br>
@@ -35,56 +39,124 @@
<div class="demo-container">
<!-- 客户区 -->
<div class="customer-area">
<div class="customer-icon">🧑🦰</div>
<div class="customer-label">用户浏览器</div>
<div class="customer-icon">
🧑🦰
</div>
<div class="customer-label">
用户浏览器
</div>
<div class="table">
<div v-if="activeStrategy === 'csr'" class="table-content">
<div
v-if="activeStrategy === 'csr'"
class="table-content"
>
<div class="ingredients-pack">
<div class="pack-label">📦 食材包</div>
<div class="pack-content">
<div class="ingredient">🥬 菜叶</div>
<div class="ingredient">🥩 肉片</div>
<div class="ingredient">🧂 调料</div>
<div class="pack-label">
📦 食材包
</div>
<div class="pack-content">
<div class="ingredient">
🥬 菜叶
</div>
<div class="ingredient">
🥩 肉片
</div>
<div class="ingredient">
🧂 调料
</div>
</div>
<div class="instruction">
请自己烹饪
</div>
<div class="instruction"> 请自己烹饪</div>
</div>
</div>
<div v-else class="table-content ready">
<div class="dish">{{ currentStrategy.dish }}</div>
<div class="dish-status">{{ currentStrategy.readyStatus }}</div>
<div
v-else
class="table-content ready"
>
<div class="dish">
{{ currentStrategy.dish }}
</div>
<div class="dish-status">
{{ currentStrategy.readyStatus }}
</div>
</div>
</div>
</div>
<!-- 传输区 -->
<div class="transfer-area">
<div v-if="isAnimating" class="transfer-animation">
<div class="transfer-content">{{ currentStrategy.transferItem }}</div>
<div class="transfer-arrow"></div>
<div
v-if="isAnimating"
class="transfer-animation"
>
<div class="transfer-content">
{{ currentStrategy.transferItem }}
</div>
<div class="transfer-arrow">
</div>
</div>
<div v-else class="transfer-info">
<div class="info-label">{{ currentStrategy.transferLabel }}</div>
<div
v-else
class="transfer-info"
>
<div class="info-label">
{{ currentStrategy.transferLabel }}
</div>
</div>
</div>
<!-- 厨房/服务器 -->
<div class="kitchen-area">
<div class="kitchen-icon">👨🍳</div>
<div class="kitchen-label">{{ currentStrategy.serverLabel }}</div>
<div class="kitchen-icon">
👨🍳
</div>
<div class="kitchen-label">
{{ currentStrategy.serverLabel }}
</div>
<div class="kitchen-content">
<div v-if="activeStrategy === 'csr'" class="server-station">
<div class="station-icon">📡</div>
<div class="station-label">配送站</div>
<div class="station-desc">只管配送不做菜</div>
<div
v-if="activeStrategy === 'csr'"
class="server-station"
>
<div class="station-icon">
📡
</div>
<div class="station-label">
配送站
</div>
<div class="station-desc">
只管配送不做菜
</div>
</div>
<div v-else-if="activeStrategy === 'ssr'" class="server-kitchen">
<div class="chef-action">{{ chefAction }}</div>
<div class="cooking-pot" v-if="isCooking">🍳</div>
<div
v-else-if="activeStrategy === 'ssr'"
class="server-kitchen"
>
<div class="chef-action">
{{ chefAction }}
</div>
<div
v-if="isCooking"
class="cooking-pot"
>
🍳
</div>
</div>
<div v-else class="server-cabinet">
<div class="cabinet-icon">🗄</div>
<div class="cabinet-label">保温柜</div>
<div class="cabinet-desc">{{ currentStrategy.cabinetDesc }}</div>
<div
v-else
class="server-cabinet"
>
<div class="cabinet-icon">
🗄
</div>
<div class="cabinet-label">
保温柜
</div>
<div class="cabinet-desc">
{{ currentStrategy.cabinetDesc }}
</div>
</div>
</div>
</div>
@@ -93,96 +165,201 @@
<!-- 性能指标 -->
<div class="metrics-panel">
<div class="metric-item">
<div class="metric-label">首屏速度</div>
<div class="metric-bar">
<div class="metric-fill" :style="{ width: currentStrategy.firstScreenScore + '%', background: currentStrategy.color }"></div>
<div class="metric-label">
首屏速度
</div>
<div class="metric-bar">
<div
class="metric-fill"
:style="{ width: currentStrategy.firstScreenScore + '%', background: currentStrategy.color }"
/>
</div>
<div
class="metric-value"
:style="{ color: currentStrategy.color }"
>
{{ currentStrategy.firstScreenText }}
</div>
<div class="metric-value" :style="{ color: currentStrategy.color }">{{ currentStrategy.firstScreenText }}</div>
</div>
<div class="metric-item">
<div class="metric-label">交互体验</div>
<div class="metric-bar">
<div class="metric-fill" :style="{ width: currentStrategy.interactionScore + '%', background: currentStrategy.color }"></div>
<div class="metric-label">
交互体验
</div>
<div class="metric-bar">
<div
class="metric-fill"
:style="{ width: currentStrategy.interactionScore + '%', background: currentStrategy.color }"
/>
</div>
<div
class="metric-value"
:style="{ color: currentStrategy.color }"
>
{{ currentStrategy.interactionText }}
</div>
<div class="metric-value" :style="{ color: currentStrategy.color }">{{ currentStrategy.interactionText }}</div>
</div>
<div class="metric-item">
<div class="metric-label">SEO 友好度</div>
<div class="metric-bar">
<div class="metric-fill" :style="{ width: currentStrategy.seoScore + '%', background: currentStrategy.color }"></div>
<div class="metric-label">
SEO 友好度
</div>
<div class="metric-bar">
<div
class="metric-fill"
:style="{ width: currentStrategy.seoScore + '%', background: currentStrategy.color }"
/>
</div>
<div
class="metric-value"
:style="{ color: currentStrategy.color }"
>
{{ currentStrategy.seoText }}
</div>
<div class="metric-value" :style="{ color: currentStrategy.color }">{{ currentStrategy.seoText }}</div>
</div>
</div>
<!-- 操作按钮 -->
<div class="controls">
<button class="btn btn-primary" @click="startDemo" :disabled="isAnimating">
<button
class="btn btn-primary"
:disabled="isAnimating"
@click="startDemo"
>
{{ isAnimating ? '演示中...' : '开始演示' }}
</button>
<button class="btn btn-secondary" @click="resetDemo">
<button
class="btn btn-secondary"
@click="resetDemo"
>
重置
</button>
</div>
<!-- 详细对比表 -->
<div class="comparison-table">
<div class="table-title">📊 三种渲染方式详细对比</div>
<div class="table-title">
📊 三种渲染方式详细对比
</div>
<div class="table-content">
<div class="comparison-row header">
<div class="col-feature">特点</div>
<div class="col-csr">CSR</div>
<div class="col-ssr">SSR</div>
<div class="col-ssg">SSG</div>
<div class="col-feature">
特点
</div>
<div class="col-csr">
CSR
</div>
<div class="col-ssr">
SSR
</div>
<div class="col-ssg">
SSG
</div>
</div>
<div class="comparison-row">
<div class="col-feature">比喻</div>
<div class="col-csr">给半成品食材包自己做</div>
<div class="col-ssr">厨房做好菜端给你</div>
<div class="col-ssg">提前做好放保温柜</div>
<div class="col-feature">
比喻
</div>
<div class="col-csr">
给半成品食材包自己做
</div>
<div class="col-ssr">
厨房做好菜端给你
</div>
<div class="col-ssg">
提前做好放保温柜
</div>
</div>
<div class="comparison-row">
<div class="col-feature">首屏速度</div>
<div class="col-csr">要等 JS</div>
<div class="col-ssr">直接给 HTML</div>
<div class="col-ssg">最快直接给 HTML</div>
<div class="col-feature">
首屏速度
</div>
<div class="col-csr">
要等 JS
</div>
<div class="col-ssr">
直接给 HTML
</div>
<div class="col-ssg">
最快直接给 HTML
</div>
</div>
<div class="comparison-row">
<div class="col-feature">交互体验</div>
<div class="col-csr">流畅已在浏览器</div>
<div class="col-ssr">较流畅交互仍需 JS</div>
<div class="col-ssg">较流畅交互仍需 JS</div>
<div class="col-feature">
交互体验
</div>
<div class="col-csr">
流畅已在浏览器
</div>
<div class="col-ssr">
较流畅交互仍需 JS
</div>
<div class="col-ssg">
较流畅交互仍需 JS
</div>
</div>
<div class="comparison-row">
<div class="col-feature">SEO 友好度</div>
<div class="col-csr">搜不到内容</div>
<div class="col-ssr">完整 HTML</div>
<div class="col-ssg">完整 HTML</div>
<div class="col-feature">
SEO 友好度
</div>
<div class="col-csr">
搜不到内容
</div>
<div class="col-ssr">
完整 HTML
</div>
<div class="col-ssg">
完整 HTML
</div>
</div>
<div class="comparison-row">
<div class="col-feature">服务器压力</div>
<div class="col-csr">只传 JS</div>
<div class="col-ssr">每次都渲染</div>
<div class="col-ssg">最小预渲染好</div>
<div class="col-feature">
服务器压力
</div>
<div class="col-csr">
只传 JS
</div>
<div class="col-ssr">
每次都渲染
</div>
<div class="col-ssg">
最小预渲染好
</div>
</div>
<div class="comparison-row">
<div class="col-feature">适合场景</div>
<div class="col-csr">后台系统工具应用</div>
<div class="col-ssr">新闻网站电商首页</div>
<div class="col-ssg">博客文档站</div>
<div class="col-feature">
适合场景
</div>
<div class="col-csr">
后台系统工具应用
</div>
<div class="col-ssr">
新闻网站电商首页
</div>
<div class="col-ssg">
博客文档站
</div>
</div>
<div class="comparison-row">
<div class="col-feature">代表框架</div>
<div class="col-csr">React SPAVue SPA</div>
<div class="col-ssr">Next.js SSRNuxt SSR</div>
<div class="col-ssg">Next.js SSGNuxt SSG</div>
<div class="col-feature">
代表框架
</div>
<div class="col-csr">
React SPAVue SPA
</div>
<div class="col-ssr">
Next.js SSRNuxt SSR
</div>
<div class="col-ssg">
Next.js SSGNuxt SSG
</div>
</div>
</div>
</div>
<!-- 核心要点 -->
<div class="key-takeaway">
<div class="takeaway-icon">🎯</div>
<div class="takeaway-icon">
🎯
</div>
<div class="takeaway-content">
<strong>如何选择</strong><br>
<strong>CSR</strong>适合需要复杂交互不关心 SEO 的应用如后台管理系统<br>
@@ -6,8 +6,12 @@
<div class="magic-closet">
<!-- 故事开头 -->
<div class="story-box">
<div class="story-emoji">👗🚪</div>
<h4 class="story-title">小美的魔法衣柜</h4>
<div class="story-emoji">
👗🚪
</div>
<h4 class="story-title">
小美的魔法衣柜
</h4>
<p class="story-text">
小美有一件神奇的魔法衣柜不管你把它放在大房间还是小房间<br>
<strong>里面的衣服都会自动叠好排好完美适应空间大小</strong>
@@ -24,13 +28,13 @@
<div class="slider-box">
<span class="slider-emoji">🏠</span>
<input
type="range"
v-model="closetWidth"
type="range"
:min="280"
:max="900"
step="10"
class="magic-slider"
/>
>
<span class="slider-emoji">🏰</span>
</div>
@@ -40,7 +44,10 @@
</div>
<!-- 魔法衣柜展示 -->
<div class="closet-display" :style="{ width: closetWidth + 'px' }">
<div
class="closet-display"
:style="{ width: closetWidth + 'px' }"
>
<div class="closet-header">
<span class="closet-icon">🚪</span>
<span class="closet-title">小美的魔法衣柜</span>
@@ -48,7 +55,10 @@
</div>
<div class="closet-interior">
<div class="clothes-rack" :style="rackStyle">
<div
class="clothes-rack"
:style="rackStyle"
>
<div
v-for="(item, index) in clothes"
:key="index"
@@ -56,10 +66,21 @@
:class="{ 'folded': isSmallSpace }"
:style="{ animationDelay: (index * 0.1) + 's' }"
>
<div class="item-hanger">🪝</div>
<div class="item-emoji">{{ item.emoji }}</div>
<div class="item-name">{{ item.name }}</div>
<div class="fold-hint" v-if="isSmallSpace">叠好了!</div>
<div class="item-hanger">
🪝
</div>
<div class="item-emoji">
{{ item.emoji }}
</div>
<div class="item-name">
{{ item.name }}
</div>
<div
v-if="isSmallSpace"
class="fold-hint"
>
叠好了!
</div>
</div>
</div>
</div>
@@ -72,24 +93,48 @@
<!-- 魔法原理说明 -->
<div class="magic-explain">
<div class="explain-title">🔮 魔法原理揭秘</div>
<div class="explain-title">
🔮 魔法原理揭秘
</div>
<div class="explain-cards">
<div class="explain-card">
<div class="card-icon">📱</div>
<div class="card-title">小房间手机</div>
<div class="card-desc">衣柜只有 320px 衣服会自动叠起来<strong>1</strong>排开</div>
<div class="card-icon">
📱
</div>
<div class="card-title">
小房间手机
</div>
<div class="card-desc">
衣柜只有 320px 衣服会自动叠起来<strong>1</strong>排开
</div>
</div>
<div class="explain-arrow"></div>
<div class="explain-card">
<div class="card-icon">📲</div>
<div class="card-title">中房间平板</div>
<div class="card-desc">衣柜有 768px 衣服舒展开<strong>2</strong>排开</div>
<div class="explain-arrow">
</div>
<div class="explain-arrow"></div>
<div class="explain-card">
<div class="card-icon">💻</div>
<div class="card-title">大房间电脑</div>
<div class="card-desc">衣柜有 1200px 衣服完全展开<strong>3</strong>排开</div>
<div class="card-icon">
📲
</div>
<div class="card-title">
中房间平板
</div>
<div class="card-desc">
衣柜有 768px 衣服舒展开<strong>2</strong>排开
</div>
</div>
<div class="explain-arrow">
</div>
<div class="explain-card">
<div class="card-icon">
💻
</div>
<div class="card-title">
大房间电脑
</div>
<div class="card-desc">
衣柜有 1200px 衣服完全展开<strong>3</strong>排开
</div>
</div>
</div>
</div>
@@ -124,7 +169,9 @@
<!-- 总结 -->
<div class="summary-box">
<div class="summary-icon">🎯</div>
<div class="summary-icon">
🎯
</div>
<div class="summary-content">
<strong>关键 takeaway</strong>
响应式布局就像小美的魔法衣柜<strong>同一套衣服内容</strong>
@@ -22,185 +22,296 @@
</p>
</div>
<!-- 模式选择 -->
<div class="mode-selector">
<div
class="mode-card"
:class="{ active: mode === 'mpa' }"
@click="switchMode('mpa')"
>
<div class="mode-icon">📚</div>
<div class="mode-name">MPA 多页应用</div>
<div class="mode-sub">通俗说法: 像翻书</div>
<div class="mode-desc">每点一次链接浏览器向服务器要新页面</div>
<!-- 模式选择 -->
<div class="mode-selector">
<div
class="mode-card"
:class="{ active: mode === 'mpa' }"
@click="switchMode('mpa')"
>
<div class="mode-icon">
📚
</div>
<div class="mode-name">
MPA 多页应用
</div>
<div class="mode-sub">
通俗说法: 像翻书
</div>
<div class="mode-desc">
每点一次链接浏览器向服务器要新页面
</div>
</div>
<div class="vs-divider">
VS
</div>
<div
class="mode-card"
:class="{ active: mode === 'spa' }"
@click="switchMode('spa')"
>
<div class="mode-icon">
📄
</div>
<div class="mode-name">
SPA 单页应用
</div>
<div class="mode-sub">
通俗说法: 像换纸
</div>
<div class="mode-desc">
只加载一次后续只切换内容
</div>
</div>
</div>
<div class="vs-divider">VS</div>
<!-- 动画演示 -->
<div class="demo-area">
<div class="demo-header">
<span>当前模式</span>
<span
class="mode-badge"
:class="mode"
>{{ mode === 'mpa' ? 'MPA 多页应用' : 'SPA 单页应用' }}</span>
</div>
<div
class="mode-card"
:class="{ active: mode === 'spa' }"
@click="switchMode('spa')"
>
<div class="mode-icon">📄</div>
<div class="mode-name">SPA 单页应用</div>
<div class="mode-sub">通俗说法: 像换纸</div>
<div class="mode-desc">只加载一次后续只切换内容</div>
</div>
</div>
<!-- 场景模拟 -->
<div class="scene-container">
<!-- 书架服务器 -->
<div class="server-side">
<div class="server-icon">
📚
</div>
<div class="server-label">
书架服务器
</div>
<div class="books-shelf">
<div
v-for="page in pages"
:key="page.id"
class="book-item"
:class="{
active: currentPage === page.id,
loading: mode === 'mpa' && isLoading && page.id === targetPage
}"
>
{{ page.emoji }}
</div>
</div>
</div>
<!-- 动画演示 -->
<div class="demo-area">
<div class="demo-header">
<span>当前模式</span>
<span class="mode-badge" :class="mode">{{ mode === 'mpa' ? 'MPA 多页应用' : 'SPA 单页应用' }}</span>
</div>
<!-- 场景模拟 -->
<div class="scene-container">
<!-- 书架服务器 -->
<div class="server-side">
<div class="server-icon">📚</div>
<div class="server-label">书架服务器</div>
<div class="books-shelf">
<!-- 传输过程 -->
<div class="transfer-area">
<div
v-if="mode === 'mpa' && isLoading"
class="transfer-animation"
>
<div class="transfer-icon">
{{ pages.find(p => p.id === targetPage)?.emoji }}
</div>
<div class="transfer-arrow">
</div>
</div>
<div
v-else
class="transfer-placeholder"
>
<span>{{ mode === 'mpa' ? '点击页面传输' : '无需传输' }}</span>
</div>
</div>
<!-- 阅读区浏览器 -->
<div class="browser-side">
<div class="browser-icon">
📖
</div>
<div class="browser-label">
阅读区浏览器
</div>
<div class="reading-paper">
<Transition
:name="mode === 'mpa' ? 'page-flip' : 'content-fade'"
mode="out-in"
>
<div
:key="currentPage"
class="page-content"
>
<div class="page-emoji">
{{ getCurrentPage.emoji }}
</div>
<div class="page-title">
{{ getCurrentPage.title }}
</div>
<div class="page-text">
{{ getCurrentPage.content }}
</div>
</div>
</Transition>
<!-- 状态保留测试 -->
<div class="state-test">
<div class="test-label">
状态保留测试
</div>
<input
v-model="userInput"
type="text"
placeholder="在这里输入文字,然后切换页面..."
class="test-input"
>
</div>
</div>
</div>
</div>
<!-- 导航控制 -->
<div class="navigation-controls">
<div class="nav-label">
切换页面
</div>
<div class="nav-buttons">
<button
v-for="page in pages"
:key="page.id"
class="book-item"
:class="{
active: currentPage === page.id,
loading: mode === 'mpa' && isLoading && page.id === targetPage
}"
class="nav-btn"
:class="{ active: currentPage === page.id }"
:disabled="isLoading"
@click="navigateTo(page.id)"
>
{{ page.emoji }}
</div>
{{ page.emoji }} {{ page.title }}
</button>
</div>
</div>
<!-- 传输过程 -->
<div class="transfer-area">
<div v-if="mode === 'mpa' && isLoading" class="transfer-animation">
<div class="transfer-icon">{{ pages.find(p => p.id === targetPage)?.emoji }}</div>
<div class="transfer-arrow"></div>
</div>
<div v-else class="transfer-placeholder">
<span>{{ mode === 'mpa' ? '点击页面传输' : '无需传输' }}</span>
</div>
</div>
<!-- 阅读区浏览器 -->
<div class="browser-side">
<div class="browser-icon">📖</div>
<div class="browser-label">阅读区浏览器</div>
<div class="reading-paper">
<Transition :name="mode === 'mpa' ? 'page-flip' : 'content-fade'" mode="out-in">
<div :key="currentPage" class="page-content">
<div class="page-emoji">{{ getCurrentPage.emoji }}</div>
<div class="page-title">{{ getCurrentPage.title }}</div>
<div class="page-text">{{ getCurrentPage.content }}</div>
</div>
</Transition>
<!-- 状态保留测试 -->
<div class="state-test">
<div class="test-label"> 状态保留测试</div>
<input
v-model="userInput"
type="text"
placeholder="在这里输入文字,然后切换页面..."
class="test-input"
/>
</div>
</div>
</div>
</div>
<!-- 导航控制 -->
<div class="navigation-controls">
<div class="nav-label">切换页面</div>
<div class="nav-buttons">
<button
v-for="page in pages"
:key="page.id"
class="nav-btn"
:class="{ active: currentPage === page.id }"
@click="navigateTo(page.id)"
:disabled="isLoading"
<!-- 状态指示 -->
<div class="status-indicator">
<div
v-if="mode === 'mpa'"
class="status-text mpa"
>
{{ page.emoji }} {{ page.title }}
</button>
<span class="status-icon">📚</span>
<span>每次切换都要从书架拿新书服务器请求</span>
</div>
<div
v-else
class="status-text spa"
>
<span class="status-icon"></span>
<span>内容已经下载好了切换不需要再拿前端路由</span>
</div>
</div>
</div>
<!-- 状态指示 -->
<div class="status-indicator">
<div v-if="mode === 'mpa'" class="status-text mpa">
<span class="status-icon">📚</span>
<span>每次切换都要从书架拿新书服务器请求</span>
<!-- 对比表格 -->
<div class="comparison-table">
<div class="table-title">
📊 MPA vs SPA 对比
</div>
<div v-else class="status-text spa">
<span class="status-icon"></span>
<span>内容已经下载好了切换不需要再拿前端路由</span>
<div class="table-content">
<div class="comparison-row header">
<div class="col-feature">
特点
</div>
<div class="col-mpa">
MPA 多页应用
</div>
<div class="col-spa">
SPA 单页应用
</div>
</div>
<div class="comparison-row">
<div class="col-feature">
比喻
</div>
<div class="col-mpa">
翻书每翻一页换一本书
</div>
<div class="col-spa">
换纸同一本书里换内容
</div>
</div>
<div class="comparison-row">
<div class="col-feature">
页面切换
</div>
<div class="col-mpa">
每次都重新加载整个页面
</div>
<div class="col-spa">
只加载一次后续只切换内容
</div>
</div>
<div class="comparison-row">
<div class="col-feature">
速度体验
</div>
<div class="col-mpa">
每次都有"白屏-加载"的过程
</div>
<div class="col-spa">
页面切换流畅无白屏
</div>
</div>
<div class="comparison-row">
<div class="col-feature">
状态保留
</div>
<div class="col-mpa">
切换页面后输入的内容会丢失
</div>
<div class="col-spa">
切换页面后输入的内容还在
</div>
</div>
<div class="comparison-row">
<div class="col-feature">
搜索引擎
</div>
<div class="col-mpa">
容易被搜索到SEO 友好
</div>
<div class="col-spa">
需要额外处理才能被搜索到
</div>
</div>
<div class="comparison-row">
<div class="col-feature">
首屏加载
</div>
<div class="col-mpa">
服务器直接给 HTML首屏快
</div>
<div class="col-spa">
需要先下载 JS首屏可能慢
</div>
</div>
<div class="comparison-row">
<div class="col-feature">
适合场景
</div>
<div class="col-mpa">
博客新闻企业官网
</div>
<div class="col-spa">
淘宝网易云音乐后台系统
</div>
</div>
</div>
</div>
</div>
<!-- 对比表格 -->
<div class="comparison-table">
<div class="table-title">📊 MPA vs SPA 对比</div>
<div class="table-content">
<div class="comparison-row header">
<div class="col-feature">特点</div>
<div class="col-mpa">MPA 多页应用</div>
<div class="col-spa">SPA 单页应用</div>
</div>
<div class="comparison-row">
<div class="col-feature">比喻</div>
<div class="col-mpa">翻书每翻一页换一本书</div>
<div class="col-spa">换纸同一本书里换内容</div>
</div>
<div class="comparison-row">
<div class="col-feature">页面切换</div>
<div class="col-mpa">每次都重新加载整个页面</div>
<div class="col-spa">只加载一次后续只切换内容</div>
</div>
<div class="comparison-row">
<div class="col-feature">速度体验</div>
<div class="col-mpa">每次都有"白屏-加载"的过程</div>
<div class="col-spa">页面切换流畅无白屏</div>
</div>
<div class="comparison-row">
<div class="col-feature">状态保留</div>
<div class="col-mpa">切换页面后输入的内容会丢失</div>
<div class="col-spa">切换页面后输入的内容还在</div>
</div>
<div class="comparison-row">
<div class="col-feature">搜索引擎</div>
<div class="col-mpa">容易被搜索到SEO 友好</div>
<div class="col-spa">需要额外处理才能被搜索到</div>
</div>
<div class="comparison-row">
<div class="col-feature">首屏加载</div>
<div class="col-mpa">服务器直接给 HTML首屏快</div>
<div class="col-spa">需要先下载 JS首屏可能慢</div>
</div>
<div class="comparison-row">
<div class="col-feature">适合场景</div>
<div class="col-mpa">博客新闻企业官网</div>
<div class="col-spa">淘宝网易云音乐后台系统</div>
</div>
<!-- 核心要点 -->
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>
<strong>MPA</strong> 每次切换都要"整页刷新"像翻书适合内容为主的网站
<strong>SPA</strong> 只加载一次后续"局部更新"像换纸适合交互复杂的应用
关键是<strong>状态会不会丢</strong>
</div>
</div>
<!-- 核心要点 -->
<div class="info-box">
<span class="icon">💡</span>
<strong>核心思想</strong>
<strong>MPA</strong> 每次切换都要"整页刷新"像翻书适合内容为主的网站
<strong>SPA</strong> 只加载一次后续"局部更新"像换纸适合交互复杂的应用
关键是<strong>状态会不会丢</strong>
</div>
</div>
</div>
</template>
@@ -29,23 +29,41 @@
:class="{ active: mode === 'separate' }"
@click="mode = 'separate'"
>
<div class="mode-icon">🛵</div>
<div class="mode-name">切图模式</div>
<div class="mode-desc">通俗说法: 一箱一趟</div>
<div class="mode-detail">需要 6 趟运输</div>
<div class="mode-icon">
🛵
</div>
<div class="mode-name">
切图模式
</div>
<div class="mode-desc">
通俗说法: 一箱一趟
</div>
<div class="mode-detail">
需要 6 趟运输
</div>
</div>
<div class="vs-divider">VS</div>
<div class="vs-divider">
VS
</div>
<div
class="mode-card"
:class="{ active: mode === 'packed' }"
@click="mode = 'packed'"
>
<div class="mode-icon">🚚</div>
<div class="mode-name">雪碧图模式</div>
<div class="mode-desc">通俗说法: 打包一车拉</div>
<div class="mode-detail">只需 1 趟运输</div>
<div class="mode-icon">
🚚
</div>
<div class="mode-name">
雪碧图模式
</div>
<div class="mode-desc">
通俗说法: 打包一车拉
</div>
<div class="mode-detail">
只需 1 趟运输
</div>
</div>
</div>
@@ -53,8 +71,12 @@
<div class="animation-area">
<!-- 起点 -->
<div class="location start">
<div class="location-icon">🏠</div>
<div class="location-label">旧家</div>
<div class="location-icon">
🏠
</div>
<div class="location-label">
旧家
</div>
<div class="boxes-remaining">
剩余箱子: <span class="count">{{ remainingBoxes }}</span>
</div>
@@ -62,7 +84,7 @@
<!-- 道路 -->
<div class="road">
<div class="road-line"></div>
<div class="road-line" />
<!-- 运输车辆 -->
<div
@@ -75,7 +97,10 @@
<div class="vehicle-body">
{{ mode === 'separate' ? '🛵' : '🚚' }}
</div>
<div class="vehicle-cargo" v-if="vehicle.cargo > 0">
<div
v-if="vehicle.cargo > 0"
class="vehicle-cargo"
>
{{ mode === 'separate' ? '📦' : '📦×' + vehicle.cargo }}
</div>
</div>
@@ -83,8 +108,12 @@
<!-- 终点 -->
<div class="location end">
<div class="location-icon">🏡</div>
<div class="location-label">新家</div>
<div class="location-icon">
🏡
</div>
<div class="location-label">
新家
</div>
<div class="boxes-delivered">
已送达: <span class="count">{{ deliveredBoxes }}</span>/6
</div>
@@ -94,18 +123,32 @@
<!-- 统计面板 -->
<div class="stats-panel">
<div class="stat-item">
<div class="stat-label">运输趟数</div>
<div class="stat-value" :class="{ 'good': trips <= 2, 'bad': trips > 2 }">
<div class="stat-label">
运输趟数
</div>
<div
class="stat-value"
:class="{ 'good': trips <= 2, 'bad': trips > 2 }"
>
{{ trips }}
</div>
</div>
<div class="stat-item">
<div class="stat-label">总耗时</div>
<div class="stat-value">{{ totalTime.toFixed(1) }} </div>
<div class="stat-label">
总耗时
</div>
<div class="stat-value">
{{ totalTime.toFixed(1) }}
</div>
</div>
<div class="stat-item">
<div class="stat-label">效率评分</div>
<div class="stat-value" :class="efficiencyClass">
<div class="stat-label">
效率评分
</div>
<div
class="stat-value"
:class="efficiencyClass"
>
{{ efficiency }}
</div>
</div>
@@ -115,8 +158,8 @@
<div class="controls">
<button
class="btn btn-primary"
@click="startSimulation"
:disabled="isRunning"
@click="startSimulation"
>
{{ isRunning ? '运输中...' : '开始搬家' }}
</button>