<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>辗转相除法 - 完整教学</title>
<link rel="stylesheet" href="https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/assets/katex/katex.min.css">
<script defer src="https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/assets/katex/katex.min.js"></script>
<script defer src="https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/assets/katex/auto-render.min.js"></script>
<script src="https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/assets/js/vue.global.prod.js"></script>
<script src="https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/assets/js/gsap.min.js"></script>
<style>
* {
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
html, body {
margin: 0;
padding: 0;
background: #F0F4F8;
overflow: hidden;
height: 100vh;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
-webkit-text-size-adjust: 100%;
}
#app {
height: 100vh;
width: 100%;
max-width: 480px;
margin: 0 auto;
background: #fff;
display: flex;
flex-direction: column;
box-shadow: 0 0 20px rgba(0,0,0,0.05);
}
.content-area {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding-bottom: 80px;
-webkit-overflow-scrolling: touch;
}
/* 顶部标签栏 */
.top-tabs {
display: flex;
background: linear-gradient(135deg, #10B981 0%, #059669 100%);
padding: 10px 10px 0 10px;
gap: 5px;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.top-tab {
flex-shrink: 0;
padding: 10px 12px;
border-radius: 12px 12px 0 0;
font-size: 12px;
font-weight: bold;
color: rgba(255,255,255,0.7);
cursor: pointer;
transition: all 0.3s;
background: rgba(255,255,255,0.1);
min-width: 80px;
text-align: center;
}
.top-tab.active {
background: white;
color: #059669;
transform: translateY(-2px);
box-shadow: 0 -2px 10px rgba(0,0,0,0.1);
}
/* 底部导航 */
.bottom-nav {
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 100%;
max-width: 480px;
height: 70px;
background: white;
border-top: 1px solid #e0e0e0;
display: flex;
justify-content: space-around;
align-items: center;
z-index: 1000;
box-shadow: 0 -2px 10px rgba(0,0,0,0.05);
}
.nav-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
padding: 8px;
transition: all 0.3s;
color: #64748B;
}
.nav-item.active { color: #10B981; }
.nav-icon { font-size: 24px; margin-bottom: 4px; }
.nav-label { font-size: 12px; font-weight: 500; }
/* 通用样式 */
.page-container { padding: 20px; }
.section-title {
font-size: 20px;
font-weight: 800;
color: #1E293B;
margin: 20px 0 15px 0;
display: flex;
align-items: center;
gap: 8px;
}
.card {
background: white;
border-radius: 12px;
padding: 20px;
margin-bottom: 15px;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
border: 1px solid #E2E8F0;
}
.tag {
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
margin-bottom: 8px;
}
.tag-blue { background: #E0F2FE; color: #0284C7; }
.tag-green { background: #D1FAE5; color: #065F46; }
.tag-orange { background: #FFEDD5; color: #C2410C; }
.tag-purple { background: #F3E8FF; color: #7C3AED; }
.formula-box {
background: #F0FDF4;
padding: 15px;
border-radius: 8px;
border-left: 4px solid #10B981;
margin: 15px 0;
font-size: 16px;
text-align: center;
}
.speak-btn {
background: linear-gradient(135deg, #10B981 0%, #059669 100%);
color: white;
border: none;
padding: 12px 20px;
border-radius: 20px;
font-size: 14px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
box-shadow: 0 4px 10px rgba(16, 185, 129, 0.3);
width: 100%;
}
/* 动画舞台 */
.anim-stage {
background: #1E293B;
border-radius: 16px;
padding: 25px 15px;
min-height: 400px;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
border: 2px solid #334155;
margin: 15px 0;
}
.anim-text {
color: white;
margin-top: auto;
font-size: 14px;
font-weight: bold;
text-align: center;
min-height: 60px;
background: rgba(0,0,0,0.4);
padding: 12px 15px;
border-radius: 20px;
backdrop-filter: blur(4px);
width: 100%;
display: flex;
align-items: center;
justify-content: center;
line-height: 1.5;
}
.step-controls {
display: flex;
gap: 10px;
margin-bottom: 15px;
justify-content: center;
flex-wrap: wrap;
}
.step-btn {
background: #10B981;
color: white;
border: none;
padding: 8px 20px;
border-radius: 20px;
font-weight: bold;
font-size: 13px;
cursor: pointer;
transition: all 0.2s;
}
.step-btn:disabled { background: #CBD5E1; cursor: not-allowed; }
.step-btn:active:not(:disabled) { transform: scale(0.95); }
/* 除法演示 */
.division-demo {
color: white;
width: 100%;
margin-top: 30px;
}
.division-row {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
font-size: 18px;
font-weight: bold;
opacity: 0;
}
.division-equation {
background: rgba(255,255,255,0.1);
padding: 12px 20px;
border-radius: 10px;
border: 2px solid #10B981;
}
.division-highlight {
color: #FCD34D;
font-size: 22px;
}
.division-arrow {
font-size: 30px;
color: #10B981;
margin: 10px 0;
opacity: 0;
}
/* 铺地砖动画 */
.tile-demo {
width: 100%;
margin-top: 20px;
position: relative;
}
.rectangle {
border: 3px solid #10B981;
position: relative;
margin: 0 auto;
background: rgba(16, 185, 129, 0.05);
}
.rectangle-label {
position: absolute;
top: -25px;
left: 50%;
transform: translateX(-50%);
color: white;
font-size: 13px;
font-weight: bold;
white-space: nowrap;
}
.tile {
position: absolute;
border: 2px solid #FCD34D;
background: repeating-linear-gradient(
45deg,
rgba(252, 211, 77, 0.2),
rgba(252, 211, 77, 0.2) 5px,
rgba(252, 211, 77, 0.3) 5px,
rgba(252, 211, 77, 0.3) 10px
);
opacity: 0;
}
.tile-label {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-weight: bold;
font-size: 12px;
}
/* 例题样式 */
.example-item {
border: 2px solid #E2E8F0;
border-radius: 10px;
margin-bottom: 12px;
overflow: hidden;
}
.example-header {
padding: 15px;
background: #F8FAFC;
font-weight: bold;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
font-size: 14px;
}
.example-content {
padding: 15px;
border-top: 1px solid #E2E8F0;
background: white;
line-height: 1.8;
font-size: 13px;
color: #334155;
display: none;
}
.example-item.active .example-content { display: block; }
.example-solution {
background: #F0FDF4;
padding: 12px;
border-radius: 8px;
margin-top: 10px;
border-left: 3px solid #10B981;
}
/* 练习题样式 */
.question-card {
background: white;
border-radius: 16px;
padding: 20px;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
margin-bottom: 15px;
}
.question-text {
font-size: 16px;
font-weight: bold;
margin-bottom: 15px;
line-height: 1.6;
color: #1E293B;
}
.answer-input {
width: 100%;
padding: 12px;
border: 2px solid #E2E8F0;
border-radius: 8px;
font-size: 16px;
margin-bottom: 10px;
}
.submit-btn {
background: #10B981;
color: white;
border: none;
padding: 12px;
border-radius: 8px;
width: 100%;
font-weight: bold;
font-size: 16px;
cursor: pointer;
}
.feedback-box {
margin-top: 10px;
padding: 12px;
border-radius: 8px;
font-size: 13px;
line-height: 1.6;
}
.feedback-correct {
background: #ECFDF5;
color: #047857;
border: 2px solid #10B981;
}
.feedback-wrong {
background: #FEF2F2;
color: #B91C1C;
border: 2px solid #EF4444;
}
.comparison-table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
margin: 15px 0;
}
.comparison-table th {
background: #10B981;
color: white;
padding: 10px;
font-weight: bold;
}
.comparison-table td {
padding: 10px;
border: 1px solid #E2E8F0;
background: white;
}
.highlight-box {
background: #FEF3C7;
padding: 15px;
border-radius: 8px;
border-left: 4px solid #F59E0B;
margin: 15px 0;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes slideDown {
from { opacity: 0; transform: translateY(-20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
</style><script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.body, {
delimiters: [
{left: "$$", right: "$$", display: true},
{left: "\\[", right: "\\]", display: true},
{left: "$", right: "$", display: false},
{left: "\\(", right: "\\)", display: false}
],
throwOnError: false
});
});
</script>
</head>
<body>
<div id="app">
<div class="content-area">
<!-- Page 1: 原理讲解 -->
<div v-show="currentPage === 1">
<div class="top-tabs">
<div class="top-tab" :class="{active: theoryTab === 'why'}" @click="theoryTab = 'why'">
为什么学
</div>
<div class="top-tab" :class="{active: theoryTab === 'principle'}" @click="theoryTab = 'principle'">
核心原理
</div>
<div class="top-tab" :class="{active: theoryTab === 'steps'}" @click="theoryTab = 'steps'">
计算流程
</div>
</div>
<div class="page-container">
<!-- 为什么学 -->
<div v-show="theoryTab === 'why'" class="tab-content">
<div class="section-title">🤔 为什么要学辗转相除法?</div>
<div class="card">
<div class="tag tag-orange">问题场景</div>
<p style="font-size: 14px; color: #334155; line-height: 1.8; margin-top: 10px;">
求 $12$ 和 $18$ 的最大公约数,我们可以用短除法一眼看出来。<br><br>
但如果让你求 <strong style="color: #DC2626;">$2021$ 和 $1517$</strong> 的最大公约数呢?
</p>
<div style="background: #FEF2F2; padding: 15px; border-radius: 8px; margin: 15px 0;">
<div style="font-size: 13px; color: #B91C1C; line-height: 1.8;">
❌ <strong>分解质因数?</strong> 太慢了,2021和1517都很难分解<br>
❌ <strong>短除法?</strong> 肉眼看不出有什么公因子<br>
❌ <strong>试除法?</strong> 要试2, 3, 5, 7, 11, 13... 太累了
</div>
</div>
<div style="background: #ECFDF5; padding: 15px; border-radius: 8px; border: 2px solid #10B981;">
<div style="font-size: 14px; color: #047857; font-weight: bold; margin-bottom: 8px;">
✅ 辗转相除法的核心优势
</div>
<div style="font-size: 13px; color: #065F46; line-height: 2;">
• <strong>不需要判断质数</strong><br>
• <strong>不需要分解因数</strong><br>
• <strong>只需要会做除法</strong><br>
• <strong>几步就能得出答案</strong>
</div>
</div>
</div>
<div class="card">
<div class="tag tag-green">实际演示</div>
<p style="font-size: 14px; color: #334155; margin: 10px 0;">
看看用辗转相除法求 $2021$ 和 $1517$ 有多快:
</p>
<div style="background: #F1F5F9; padding: 15px; border-radius: 8px; font-family: monospace; font-size: 13px;">
$2021 \div 1517 = 1$ 余 $504$<br>
$1517 \div 504 = 3$ 余 $5$<br>
$504 \div 5 = 100$ 余 $4$<br>
$5 \div 4 = 1$ 余 $1$<br>
$4 \div 1 = 4$ 余 $0$ ✓<br><br>
<strong style="color: #10B981;">答案:GCD = 1(互质)</strong>
</div>
</div>
<button class="speak-btn" @click="speakWhy">
🔊 听讲解
</button>
</div>
<!-- 核心原理 -->
<div v-show="theoryTab === 'principle'" class="tab-content">
<div class="section-title">🎯 核心原理</div>
<div class="card">
<div class="tag tag-blue">数学定义</div>
<p style="font-size: 14px; color: #334155; line-height: 1.8; margin-top: 10px;">
对于任意两个正整数 $a$ 和 $b$(假设 $a > b$):
</p>
<div class="formula-box">
$$\text{GCD}(a, b) = \text{GCD}(b, a \bmod b)$$
</div>
<p style="font-size: 13px; color: #64748B; text-align: center;">
两数的最大公约数 = 较小数与余数的最大公约数
</p>
</div>
<div class="card">
<div class="tag tag-green">为什么这样做是对的?</div>
<div style="font-size: 14px; color: #334155; line-height: 1.8; margin-top: 10px;">
<p><strong>假设:</strong>我们要求 $a$ 和 $b$ 的最大公约数,设为 $d$。</p>
<p style="margin-top: 10px;"><strong>第一步:</strong>既然 $d$ 能整除 $a$ 和 $b$,那么:</p>
<div style="background: #F0F9FF; padding: 12px; border-radius: 6px; margin: 10px 0;">
$a = d \times m$ (某个整数 $m$)<br>
$b = d \times n$ (某个整数 $n$)
</div>
<p><strong>第二步:</strong>做除法 $a \div b$,得到商 $q$ 和余数 $r$:</p>
<div style="background: #F0F9FF; padding: 12px; border-radius: 6px; margin: 10px 0;">
$a = b \times q + r$
</div>
<p><strong>第三步:</strong>把 $a$ 和 $b$ 代入:</p>
<div style="background: #F0F9FF; padding: 12px; border-radius: 6px; margin: 10px 0;">
$d \times m = (d \times n) \times q + r$<br>
$r = d \times m - d \times n \times q$<br>
$r = d \times (m - n \times q)$
</div>
<p><strong>结论:</strong>余数 $r$ 也能被 $d$ 整除!所以 $d$ 也是 $b$ 和 $r$ 的公约数。</p>
<div class="highlight-box">
<strong>💡 关键洞察:</strong><br>
$a$ 和 $b$ 的公约数 = $b$ 和 $r$ 的公约数<br>
所以问题规模变小了!
</div>
</div>
</div>
<button class="speak-btn" @click="speakPrinciple">
🔊 听原理讲解
</button>
</div>
<!-- 计算流程 -->
<div v-show="theoryTab === 'steps'" class="tab-content">
<div class="section-title">📝 计算流程(标准步骤)</div>
<div class="card">
<div class="tag tag-green">例题:求 GCD(104, 40)</div>
<div class="step-controls">
<button class="step-btn" @click="prevCalcStep" :disabled="calcStep === 0">◀ 上一步</button>
<button class="step-btn" @click="nextCalcStep" :disabled="calcStep >= 4">下一步 ▶</button>
<button class="step-btn" @click="resetCalcDemo" style="background: #64748B;">🔄 重置</button>
</div>
<div class="anim-stage">
<div class="division-demo">
<div class="division-row" id="calc-step1">
<div class="division-equation">
$104 \div 40 = 2$ 余 <span class="division-highlight">24</span>
</div>
</div>
<div class="division-arrow" id="calc-arrow1">↓</div>
<div class="division-row" id="calc-step2">
<div class="division-equation">
$40 \div 24 = 1$ 余 <span class="division-highlight">16</span>
</div>
</div>
<div class="division-arrow" id="calc-arrow2">↓</div>
<div class="division-row" id="calc-step3">
<div class="division-equation">
$24 \div 16 = 1$ 余 <span class="division-highlight">8</span>
</div>
</div>
<div class="division-arrow" id="calc-arrow3">↓</div>
<div class="division-row" id="calc-step4">
<div class="division-equation" style="border-color: #FCD34D;">
$16 \div 8 = 2$ 余 <span class="division-highlight">0</span> ✓
</div>
</div>
</div>
<div class="anim-text" id="calc-text">点击"下一步"开始演示</div>
</div>
</div>
<div class="card">
<div class="tag tag-blue">关键理解</div>
<div style="font-size: 13px; color: #334155; line-height: 1.8; margin-top: 10px;">
<p><strong>🔄 每一轮都在做什么?</strong></p>
<div style="background: #F8FAFC; padding: 12px; border-radius: 6px; margin: 10px 0;">
• <strong>除数</strong> 变成 <strong>新的被除数</strong><br>
• <strong>余数</strong> 变成 <strong>新的除数</strong><br>
• 数字越来越小,直到余数为0
</div>
<p style="margin-top: 15px;"><strong>🎯 什么时候停止?</strong></p>
<div style="background: #ECFDF5; padding: 12px; border-radius: 6px; margin: 10px 0; border: 2px solid #10B981;">
当余数为 <strong>0</strong> 时,这一轮的<strong>除数</strong>(也就是上一轮的余数)就是最大公约数!
</div>
</div>
</div>
<button class="speak-btn" @click="speakSteps">
🔊 听步骤讲解
</button>
</div>
</div>
</div>
<!-- Page 2: 几何理解 -->
<div v-show="currentPage === 2" class="page-container">
<div class="section-title">🏗️ 几何直观理解:铺地砖模型</div>
<div class="card">
<div class="tag tag-orange">任务</div>
<p style="font-size: 14px; color: #334155; line-height: 1.8; margin-top: 10px;">
有一个 <strong>$104 \times 40$</strong> 的长方形房间,要用<strong>同样大小的正方形</strong>地砖铺满。<br>
地砖边长最大是多少?
</p>
</div>
<div class="card">
<div class="tag tag-green">动画演示</div>
<div class="step-controls">
<button class="step-btn" @click="prevTileStep" :disabled="tileStep === 0">◀ 上一步</button>
<button class="step-btn" @click="nextTileStep" :disabled="tileStep >= 4">下一步 ▶</button>
<button class="step-btn" @click="resetTileDemo" style="background: #64748B;">🔄 重置</button>
</div>
<div class="anim-stage">
<div class="tile-demo" id="tile-container">
<!-- 动画将在这里生成 -->
</div>
<div class="anim-text" id="tile-text">点击"下一步"开始铺砖</div>
</div>
</div>
<div class="card">
<div class="tag tag-blue">理解要点</div>
<div style="font-size: 13px; color: #334155; line-height: 1.8; margin-top: 10px;">
<p><strong>🧩 核心逻辑:</strong></p>
<div style="background: #FEF3C7; padding: 12px; border-radius: 6px; margin: 10px 0;">
每次切完后,剩下的小长方形也必须能被同样的地砖铺满!<br>
所以我们要一直切到<strong>恰好铺满</strong>为止。
</div>
<p style="margin-top: 15px;"><strong>✨ 最后能铺满的正方形边长,就是最大公约数!</strong></p>
</div>
</div>
<button class="speak-btn" @click="speakTile">
🔊 听几何理解
</button>
</div>
<!-- Page 3: 对比减法 -->
<div v-show="currentPage === 3" class="page-container">
<div class="section-title">⚖️ 辗转相除 vs 更相减损</div>
<div class="card">
<div class="tag tag-purple">更相减损术</div>
<p style="font-size: 14px; color: #334155; line-height: 1.8; margin-top: 10px;">
中国古代数学名著《九章算术》中的方法,<strong>用减法代替除法</strong>。
</p>
<div class="formula-box" style="background: #F3E8FF; border-color: #7C3AED;">
$$\text{GCD}(a, b) = \text{GCD}(b, a - b)$$
</div>
</div>
<div class="card">
<div class="tag tag-green">对比演示:求 GCD(104, 40)</div>
<table class="comparison-table">
<tr>
<th style="width: 50%;">辗转相除法(除法)</th>
<th style="width: 50%;">更相减损术(减法)</th>
</tr>
<tr>
<td>
$104 \div 40 = 2$ 余 $24$<br>
$40 \div 24 = 1$ 余 $16$<br>
$24 \div 16 = 1$ 余 $8$<br>
$16 \div 8 = 2$ 余 $0$<br>
<strong style="color: #10B981;">共4步</strong>
</td>
<td>
$104 - 40 = 64$<br>
$64 - 40 = 24$<br>
$40 - 24 = 16$<br>
$24 - 16 = 8$<br>
$16 - 8 = 8$<br>
$8 = 8$ 停止<br>
<strong style="color: #F59E0B;">共5步</strong>
</td>
</tr>
</table>
</div>
<div class="card">
<div class="tag tag-orange">优缺点对比</div>
<div style="font-size: 13px; color: #334155; line-height: 1.8; margin-top: 10px;">
<p><strong>✅ 辗转相除法(除法):</strong></p>
<div style="background: #ECFDF5; padding: 12px; border-radius: 6px; margin: 10px 0;">
• <strong>收敛极快</strong>,适合大数<br>
• 例如 GCD(10000, 1):除法1步,减法要减10000次<br>
• <strong>现代数学的标准算法</strong>
</div>
<p style="margin-top: 15px;"><strong>✅ 更相减损术(减法):</strong></p>
<div style="background: #FEF3C7; padding: 12px; border-radius: 6px; margin: 10px 0;">
• 适合<strong>计算机二进制运算</strong>(移位+减法比除法快)<br>
• 适合<strong>小学生</strong>还没熟练掌握两位数除法时使用<br>
• 中国古代数学智慧
</div>
</div>
</div>
<div class="card" style="background: linear-gradient(135deg, #FEF3C7 0%, #FDE68A 100%);">
<div style="font-size: 14px; font-weight: bold; color: #92400E; margin-bottom: 10px;">💡 记忆口诀</div>
<p style="font-size: 13px; color: #78350F; line-height: 1.6; margin: 0;">
<strong>除法快,减法稳</strong><br>
除法三步走,减法慢慢来<br>
大数用除法,小数随便选
</p>
</div>
<button class="speak-btn" @click="speakComparison">
🔊 听对比讲解
</button>
</div>
<!-- Page 4: 经典例题 -->
<div v-show="currentPage === 4" class="page-container">
<div class="section-title">📚 5道经典例题</div>
<div class="example-item" :class="{active: activeExample === index}" v-for="(ex, index) in classicExamples" :key="index">
<div class="example-header" @click="toggleExample(index)">
<span>{{ ex.title }}</span>
<span>{{ activeExample === index ? '▲' : '▼' }}</span>
</div>
<div class="example-content">
<div style="font-weight: bold; margin-bottom: 10px;">{{ ex.question }}</div>
<div class="example-solution" v-html="ex.solution"></div>
</div>
</div>
</div>
<!-- Page 5: 练习题 -->
<div v-show="currentPage === 5" class="page-container">
<div class="section-title">✏️ 10道练习题</div>
<div v-if="!practiceDone">
<div class="question-card">
<div class="tag tag-blue">练习 {{ currentPracticeIndex + 1 }}/10</div>
<div class="question-text" v-html="practiceQuestions[currentPracticeIndex].question"></div>
<input
type="number"
class="answer-input"
v-model="userAnswer"
placeholder="输入答案"
@keyup.enter="checkPracticeAnswer"
:disabled="practiceAnswered">
<button class="submit-btn" @click="checkPracticeAnswer" v-if="!practiceAnswered">
提交答案
</button>
<div v-if="practiceAnswered" class="feedback-box" :class="isPracticeCorrect ? 'feedback-correct' : 'feedback-wrong'">
<div v-if="isPracticeCorrect" style="font-weight: bold; margin-bottom: 5px;">🎉 正确!</div>
<div v-else style="font-weight: bold; margin-bottom: 5px;">💡 答案:{{ practiceQuestions[currentPracticeIndex].answer }}</div>
<div v-html="practiceQuestions[currentPracticeIndex].explanation"></div>
</div>
<button v-if="practiceAnswered" class="submit-btn" @click="nextPractice" style="margin-top: 10px;">
{{ currentPracticeIndex < 9 ? '下一题 →' : '完成练习 🎯' }}
</button>
</div>
</div>
<div v-else class="card" style="text-align: center; padding: 40px 20px;">
<div style="font-size: 60px; margin-bottom: 20px;">🏆</div>
<h2 style="color: #1E293B; margin-bottom: 10px;">练习完成!</h2>
<p style="font-size: 18px; color: #64748B; margin-bottom: 30px;">得分:{{ practiceScore }}/100</p>
<button class="submit-btn" @click="switchPage(6)">挑战奥数题 →</button>
</div>
</div>
<!-- Page 6: 奥数真题 -->
<div v-show="currentPage === 6" class="page-container">
<div class="section-title">🏆 10道杯赛真题</div>
<div class="card" style="background: linear-gradient(135deg, #FEF3C7 0%, #FDE68A 100%);">
<div style="font-size: 14px; color: #92400E; line-height: 1.6;">
<strong>💡 提示:</strong>这些题目来自华杯赛、希望杯、迎春杯等真题。<br>
难度较大,建议先掌握基础练习后再挑战!
</div>
</div>
<div class="example-item" :class="{active: activeOlympiad === index}" v-for="(q, index) in olympiadQuestions" :key="'olympiad-' + index">
<div class="example-header" @click="toggleOlympiad(index)">
<span>{{ q.title }}</span>
<span>{{ activeOlympiad === index ? '▲' : '▼' }}</span>
</div>
<div class="example-content">
<div style="font-weight: bold; margin-bottom: 10px;" v-html="q.question"></div>
<div v-if="q.hint" style="background: #FEF3C7; padding: 10px; border-radius: 6px; margin: 10px 0; font-size: 12px;">
<strong>💡 提示:</strong>{{ q.hint }}
</div>
<div class="example-solution" v-html="q.solution"></div>
</div>
</div>
</div>
</div>
<!-- 底部导航 -->
<div class="bottom-nav">
<div class="nav-item" :class="{active: currentPage === 1}" @click="switchPage(1)">
<div class="nav-icon">📖</div>
<div class="nav-label">原理</div>
</div>
<div class="nav-item" :class="{active: currentPage === 2}" @click="switchPage(2)">
<div class="nav-icon">🏗️</div>
<div class="nav-label">几何</div>
</div>
<div class="nav-item" :class="{active: currentPage === 3}" @click="switchPage(3)">
<div class="nav-icon">⚖️</div>
<div class="nav-label">对比</div>
</div>
<div class="nav-item" :class="{active: currentPage === 4}" @click="switchPage(4)">
<div class="nav-icon">📚</div>
<div class="nav-label">例题</div>
</div>
<div class="nav-item" :class="{active: currentPage === 5}" @click="switchPage(5)">
<div class="nav-icon">✏️</div>
<div class="nav-label">练习</div>
</div>
<div class="nav-item" :class="{active: currentPage === 6}" @click="switchPage(6)">
<div class="nav-icon">🏆</div>
<div class="nav-label">奥数</div>
</div>
</div>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
currentPage: 1,
theoryTab: 'why',
// 计算流程动画
calcStep: 0,
// 铺地砖动画
tileStep: 0,
// 例题展开
activeExample: null,
activeOlympiad: null,
// 经典例题
classicExamples: [
{
title: '例题1:标准入门型',
question: '求 51 和 136 的最大公约数',
solution: '<strong>解析:</strong>肉眼很难看出51的因数,直接启动算法。<br><br>' +
'$136 \\div 51 = 2$ 余 $34$<br>' +
'$51 \\div 34 = 1$ 余 $17$<br>' +
'$34 \\div 17 = 2$ 余 $0$ ✓<br><br>' +
'<strong style="color: #10B981;">答案:GCD(51, 136) = 17</strong>'
},
{
title: '例题2:层层剥笋型',
question: '求 482 和 268 的最大公约数',
solution: '<strong>解析:</strong><br>' +
'$482 \\div 268 = 1$ 余 $214$<br>' +
'$268 \\div 214 = 1$ 余 $54$<br>' +
'$214 \\div 54 = 3$ 余 $52$ (注意余数依然很大)<br>' +
'$54 \\div 52 = 1$ 余 $2$<br>' +
'$52 \\div 2 = 26$ 余 $0$ ✓<br><br>' +
'<strong style="color: #10B981;">答案:GCD(482, 268) = 2</strong>'
},
{
title: '例题3:伪质数陷阱(必考)',
question: '求 221 和 323 的最大公约数',
solution: '<strong>解析:</strong>这两个数看起来像质数,试除法很累,用辗转相除法秒解。<br><br>' +
'$323 \\div 221 = 1$ 余 $102$<br>' +
'$221 \\div 102 = 2$ 余 $17$<br>' +
'$102 \\div 17 = 6$ 余 $0$ ✓<br><br>' +
'<strong style="color: #10B981;">答案:17</strong><br>' +
'(注:原来 $221 = 13 \\times 17$,$323 = 19 \\times 17$)'
},
{
title: '例题4:分数化简应用',
question: '将分数 $\\frac{2057}{3179}$ 化简为最简分数',
solution: '<strong>解析:</strong>求分子分母的最大公约数。<br><br>' +
'$3179 \\div 2057 = 1$ 余 $1122$<br>' +
'$2057 \\div 1122 = 1$ 余 $935$<br>' +
'$1122 \\div 935 = 1$ 余 $187$<br>' +
'$935 \\div 187 = 5$ 余 $0$ ✓<br><br>' +
'最大公约数是 $187$<br>' +
'分子:$2057 \\div 187 = 11$<br>' +
'分母:$3179 \\div 187 = 17$<br><br>' +
'<strong style="color: #10B981;">答案:$\\frac{11}{17}$</strong>'
},
{
title: '例题5:几何铺砖问题',
question: '长方形纸长216厘米、宽96厘米。裁成若干个同样大小的正方形且无剩余,边长最大是多少?',
solution: '<strong>解析:</strong>求 $\\text{GCD}(216, 96)$。<br><br>' +
'$216 \\div 96 = 2$ 余 $24$<br>' +
'$96 \\div 24 = 4$ 余 $0$ ✓<br><br>' +
'<strong style="color: #10B981;">答案:24厘米</strong>'
}
],
// 练习题
currentPracticeIndex: 0,
practiceScore: 0,
practiceAnswered: false,
isPracticeCorrect: false,
userAnswer: '',
practiceDone: false,
practiceQuestions: [
{question: '求 $91$ 和 $49$ 的最大公约数', answer: 7, explanation: '$91 = 7 \\times 13$,$49 = 7 \\times 7$'},
{question: '求 $143$ 和 $78$ 的最大公约数', answer: 13, explanation: '$143 \\div 78 = 1$ 余 $65$ → $78 \\div 65 = 1$ 余 $13$ → $65 \\div 13 = 5$ 余 $0$'},
{question: '求 $247$ 和 $299$ 的最大公约数', answer: 13, explanation: '$299 - 247 = 52$ → $247 \\div 52 = 4$ 余 $39$ → $52 \\div 39 = 1$ 余 $13$'},
{question: '求 $850$ 和 $325$ 的最大公约数', answer: 25, explanation: '$850 \\div 325 = 2$ 余 $200$ → $325 \\div 200 = 1$ 余 $125$ → $200 \\div 125 = 1$ 余 $75$ → $125 \\div 75 = 1$ 余 $50$ → $75 \\div 50 = 1$ 余 $25$ → $50 \\div 25 = 2$ 余 $0$'},
{question: '求 $111$ 和 $37$ 的最大公约数', answer: 37, explanation: '$111$ 是 $37$ 的 $3$ 倍,倍数关系,直接选小的'},
{question: '求 $1001$ 和 $357$ 的最大公约数', answer: 7, explanation: '$1001 = 7 \\times 11 \\times 13$,$357 = 3 \\times 7 \\times 17$'},
{question: '求 $2023$ 和 $2024$ 的最大公约数', answer: 1, explanation: '相邻的两个自然数互质,GCD必为1'},
{question: '求 $345$ 和 $150$ 的最大公约数', answer: 15, explanation: '$345 \\div 150 = 2$ 余 $45$ → $150 \\div 45 = 3$ 余 $15$ → $45 \\div 15 = 3$ 余 $0$'},
{question: '求 $12345$ 和 $12340$ 的最大公约数', answer: 5, explanation: '两数之差为 $5$,公约数一定是差的因数,最大只能是 $5$'},
{question: '分数 $\\frac{161}{253}$ 约分后是什么?(输入分子)', answer: 7, explanation: 'GCD(161, 253) = 23,约分后为 $\\frac{7}{11}$'}
],
// 奥数真题
olympiadQuestions: [
{
title: '1. 华杯赛真题',
question: '求 $2413$ 和 $2419$ 的最大公约数',
hint: '思考更相减损术的原理,GCD(a, b) = GCD(b, a-b)',
solution: '<strong>解析:</strong>两数之差为 $6$。<br>' +
'公约数只能是 $1, 2, 3, 6$。<br>' +
'因为两数都是奇数,排除 $2, 6$。<br>' +
'$2413$ 数字和为 $10$,不是 $3$ 的倍数,排除 $3$。<br><br>' +
'<strong style="color: #10B981;">答案:1</strong>'
},
{
title: '2. 希望杯真题',
question: '分数 $\\frac{1309}{2431}$ 约分后的结果是多少?',
hint: '典型的"大数约分",直接辗转相除',
solution: '<strong>解析:</strong>$\\text{GCD}(1309, 2431) = 187$<br><br>' +
'<strong style="color: #10B981;">答案:$\\frac{7}{13}$</strong>'
},
{
title: '3. 迎春杯改编',
question: '两个自然数的和是 $50$,它们的最大公约数是 $5$。这两个数可能是多少?',
hint: '设这两个数为 5a 和 5b',
solution: '<strong>解析:</strong>设两数为 $5a$ 和 $5b$,且 $a, b$ 互质。<br>' +
'$5a + 5b = 50$ → $a + b = 10$<br>' +
'互质数对:$(1,9), (3,7)$<br>' +
'对应数对:$(5,45), (15,35)$<br><br>' +
'<strong style="color: #10B981;">答案:(5,45), (15,35) 均可</strong><br>' +
'注意:$(25,25)$ 不行,因为 GCD(25,25)=25 ≠ 5'
},
{
title: '4. 走美杯真题',
question: '求 $111111$ 和 $1111$ 的最大公约数',
hint: '数字重复类问题。111111 = 111100 + 11',
solution: '<strong>解析:</strong><br>' +
'$111111 \\div 1111 = 100$ 余 $11$<br>' +
'转为求 $\\text{GCD}(1111, 11)$<br>' +
'$1111 \\div 11 = 101$ 余 $0$<br><br>' +
'<strong style="color: #10B981;">答案:11</strong>'
},
{
title: '5. 中环杯真题',
question: '长方形纸长2021毫米、宽1517毫米。剪成若干个同样大小的正方形而没有剩余,正方形边长最大是多少?',
hint: '求 GCD(2021, 1517)',
solution: '<strong>解析:</strong><br>' +
'$2021 \\div 1517 = 1$ 余 $504$<br>' +
'$1517 \\div 504 = 3$ 余 $5$<br>' +
'$504 \\div 5 = 100$ 余 $4$<br>' +
'$5 \\div 4 = 1$ 余 $1$<br>' +
'$4 \\div 1 = 4$ 余 $0$<br><br>' +
'<strong style="color: #10B981;">答案:1毫米</strong><br>' +
'(2021和1517是互质的"半质数")'
},
{
title: '6. 奥数经典',
question: '求 $391$ 和 $323$ 的最大公约数',
hint: '使用辗转相除法',
solution: '<strong>解析:</strong><br>' +
'$391 \\div 323 = 1$ 余 $68$<br>' +
'$323 \\div 68 = 4$ 余 $51$<br>' +
'$68 \\div 51 = 1$ 余 $17$<br>' +
'$51 \\div 17 = 3$ 余 $0$<br><br>' +
'<strong style="color: #10B981;">答案:17</strong>'
},
{
title: '7. 华杯赛决赛高难度',
question: '求算式 $(2^{100} - 1)$ 和 $(2^{120} - 1)$ 的最大公约数',
hint: '高级定理:GCD(a^m - 1, a^n - 1) = a^GCD(m,n) - 1',
solution: '<strong>解析:</strong>使用公式:<br>' +
'$\\text{GCD}(a^m - 1, a^n - 1) = a^{\\text{GCD}(m, n)} - 1$<br>' +
'$\\text{GCD}(100, 120) = 20$<br><br>' +
'<strong style="color: #10B981;">答案:$2^{20} - 1$ (即 1048575)</strong>'
},
{
title: '8. 逻辑思维',
question: '已知 $A \\div B = 3$ 余 $10$。如果 $A$ 和 $B$ 的最大公约数是 $5$,求 $B$ 最小是多少?',
hint: '根据原理,GCD(A, B) = GCD(B, 10) = 5',
solution: '<strong>解析:</strong><br>' +
'$\\text{GCD}(B, 10) = 5$<br>' +
'说明 $B$ 是 $5$ 的倍数,但不能整除 $10$(即不含因子 $2$)<br>' +
'且除法要有余数 $10$,说明 $B > 10$<br>' +
'最小满足条件的数是 $15$<br><br>' +
'<strong style="color: #10B981;">答案:15</strong>'
},
{
title: '9. 拓展题:三数求公约',
question: '求三个数 $24, 32, 56$ 的最大公约数',
hint: '先算两个,得出的结果再和第三个算',
solution: '<strong>解析:</strong><br>' +
'$\\text{GCD}(24, 32) = 8$<br>' +
'$\\text{GCD}(8, 56) = 8$<br><br>' +
'<strong style="color: #10B981;">答案:8</strong>'
},
{
title: '10. 挑战题:斐波那契数列',
question: '斐波那契数列:$1, 1, 2, 3, 5, 8, 13, 21, 34...$(每一项等于前两项之和)<br>求第2023项和第2024项的最大公约数',
hint: '想想 2和3,或者 5和8,或者 13和21 的公约数是多少?',
solution: '<strong>解析:</strong><br>' +
'斐波那契数列性质:<strong>相邻两项互质</strong><br>' +
'$\\text{GCD}(F_n, F_{n+1}) = 1$<br>' +
'这也是辗转相除法运算步数最多的情况<br><br>' +
'<strong style="color: #10B981;">答案:1</strong>'
}
]
}
},
methods: {
// 语音播报
speak(text) {
if (window.speechSynthesis) window.speechSynthesis.cancel();
const isWeChat = /MicroMessenger/i.test(navigator.userAgent);
if (isWeChat) {
let audio = document.getElementById('tts-audio');
if (!audio) {
audio = document.createElement('audio'); audio.id = 'tts-audio'; audio.style.display = 'none';
document.body.appendChild(audio);
}
const url = `https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/tts.php?text=${encodeURIComponent(text)}&t=${Date.now()}`;
audio.src = url;
audio.play().catch(e => { if(window.WeixinJSBridge) window.WeixinJSBridge.invoke('getNetworkType',{},()=>audio.play()); });
} else {
if (window.speechSynthesis) {
const u = new SpeechSynthesisUtterance(text); u.lang = 'zh-CN'; u.rate = 0.9;
window.speechSynthesis.speak(u);
}
}
},
speakWhy() {
this.speak('辗转相除法的核心优势是,不需要判断质数,不需要分解因数,只需要会做除法,就能求出最大公约数。比如求2021和1517的最大公约数,用辗转相除法只需要5步就能算出来。');
},
speakPrinciple() {
this.speak('辗转相除法的核心原理是,两个数的最大公约数等于较小数与余数的最大公约数。为什么呢?因为如果一个数能整除大数和小数,那它一定也能整除余数。所以问题规模不断变小,直到余数为0。');
},
speakSteps() {
this.speak('计算流程很简单。第一步,大数除以小数,得到余数。第二步,除数变成新的被除数,余数变成新的除数。第三步,重复这个过程。第四步,当余数为0时,这一轮的除数就是最大公约数。');
},
speakTile() {
this.speak('铺地砖模型帮助我们理解算法。有一个104乘40的长方形房间,要用正方形地砖铺满。每次我们用短边作为正方形边长去切,切完后剩下一个更小的长方形。不断切下去,直到恰好铺满。最后能铺满的正方形边长,就是最大公约数。');
},
speakComparison() {
this.speak('辗转相除法和更相减损术的区别是,一个用除法,一个用减法。除法收敛快,适合大数。减法适合计算机运算和小学生使用。两种方法原理相同,只是实现方式不同。');
},
// 页面切换
switchPage(page) {
if (window.speechSynthesis) window.speechSynthesis.cancel();
this.currentPage = page;
window.scrollTo(0, 0);
if (page === 1) {
this.$nextTick(() => {
this.renderMath();
});
}
},
// 渲染数学公式
renderMath() {
if (typeof renderMathInElement !== 'undefined') {
setTimeout(() => {
renderMathInElement(document.body, {
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false}
],
throwOnError: false
});
}, 100);
}
},
// 计算流程动画
resetCalcDemo() {
this.calcStep = 0;
if (typeof gsap !== 'undefined') {
gsap.set('#calc-step1, #calc-step2, #calc-step3, #calc-step4', {opacity: 0});
gsap.set('#calc-arrow1, #calc-arrow2, #calc-arrow3', {opacity: 0});
}
document.getElementById('calc-text').textContent = '点击"下一步"开始演示';
},
nextCalcStep() {
if (this.calcStep < 4) {
this.calcStep++;
this.renderCalcStep();
}
},
prevCalcStep() {
if (this.calcStep > 0) {
this.calcStep--;
this.renderCalcStep();
}
},
renderCalcStep() {
if (typeof gsap === 'undefined') return;
const texts = [
'点击"下一步"开始演示',
'第1轮:104除以40,余数是24。问题变成求GCD(40, 24)',
'第2轮:40除以24,余数是16。问题变成求GCD(24, 16)',
'第3轮:24除以16,余数是8。问题变成求GCD(16, 8)',
'第4轮:16除以8,余数是0!整除了,答案就是8!'
];
document.getElementById('calc-text').textContent = texts[this.calcStep];
// 重置
gsap.set('#calc-step1, #calc-step2, #calc-step3, #calc-step4', {opacity: 0});
gsap.set('#calc-arrow1, #calc-arrow2, #calc-arrow3', {opacity: 0});
// 显示对应步骤
if (this.calcStep >= 1) {
gsap.to('#calc-step1', {opacity: 1, duration: 0.5});
if (this.calcStep >= 2) {
gsap.to('#calc-arrow1', {opacity: 1, duration: 0.3, delay: 0.5});
gsap.to('#calc-step2', {opacity: 1, duration: 0.5, delay: 0.8});
}
if (this.calcStep >= 3) {
gsap.to('#calc-arrow2', {opacity: 1, duration: 0.3, delay: 1.3});
gsap.to('#calc-step3', {opacity: 1, duration: 0.5, delay: 1.6});
}
if (this.calcStep >= 4) {
gsap.to('#calc-arrow3', {opacity: 1, duration: 0.3, delay: 2.1});
gsap.to('#calc-step4', {opacity: 1, duration: 0.5, delay: 2.4});
gsap.to('#calc-step4 .division-equation', {
scale: [1, 1.1, 1],
duration: 0.5,
delay: 2.9
});
}
}
this.$nextTick(() => this.renderMath());
},
// 铺地砖动画
resetTileDemo() {
this.tileStep = 0;
document.getElementById('tile-container').innerHTML = '';
document.getElementById('tile-text').textContent = '点击"下一步"开始铺砖';
},
nextTileStep() {
if (this.tileStep < 4) {
this.tileStep++;
this.renderTileStep();
}
},
prevTileStep() {
if (this.tileStep > 0) {
this.tileStep--;
this.renderTileStep();
}
},
renderTileStep() {
if (typeof gsap === 'undefined') return;
const container = document.getElementById('tile-container');
container.innerHTML = '';
const texts = [
'点击"下一步"开始铺砖',
'第1刀:以短边40为边长切正方形。切出2个40×40的大正方形,剩下24×40的小长方形',
'第2刀:处理剩下的24×40区域。切出1个24×24的正方形,剩下16×24',
'第3刀:处理16×24。切出1个16×16的正方形,剩下8×16',
'第4刀:处理8×16。刚好切出2个8×8的正方形,没有剩余!所以答案是8'
];
document.getElementById('tile-text').textContent = texts[this.tileStep];
// 根据步骤渲染不同的图形
if (this.tileStep === 1) {
// 104x40的矩形,切出2个40x40
const rect = document.createElement('div');
rect.className = 'rectangle';
rect.style.width = '260px';
rect.style.height = '100px';
container.appendChild(rect);
const label = document.createElement('div');
label.className = 'rectangle-label';
label.textContent = '104 × 40';
rect.appendChild(label);
// 添加两个40x40的砖
for (let i = 0; i < 2; i++) {
const tile = document.createElement('div');
tile.className = 'tile';
tile.style.width = '100px';
tile.style.height = '100px';
tile.style.left = (i * 100) + 'px';
tile.style.top = '0px';
rect.appendChild(tile);
const tileLabel = document.createElement('div');
tileLabel.className = 'tile-label';
tileLabel.textContent = '40×40';
tile.appendChild(tileLabel);
gsap.to(tile, {opacity: 1, duration: 0.5, delay: i * 0.3});
}
// 剩余24x40区域高亮
const remaining = document.createElement('div');
remaining.style.cssText = 'position: absolute; right: 0; top: 0; width: 60px; height: 100px; border: 3px dashed #EF4444; border-left: none; opacity: 0;';
rect.appendChild(remaining);
gsap.to(remaining, {opacity: 1, duration: 0.5, delay: 0.8});
} else if (this.tileStep === 2) {
// 24x40的矩形
const rect = document.createElement('div');
rect.className = 'rectangle';
rect.style.width = '150px';
rect.style.height = '100px';
container.appendChild(rect);
const label = document.createElement('div');
label.className = 'rectangle-label';
label.textContent = '24 × 40 (剩余部分)';
rect.appendChild(label);
// 添加1个24x24的砖
const tile = document.createElement('div');
tile.className = 'tile';
tile.style.width = '60px';
tile.style.height = '60px';
tile.style.left = '0px';
tile.style.top = '0px';
rect.appendChild(tile);
const tileLabel = document.createElement('div');
tileLabel.className = 'tile-label';
tileLabel.textContent = '24×24';
tile.appendChild(tileLabel);
gsap.to(tile, {opacity: 1, duration: 0.5});
// 剩余16x24
const remaining = document.createElement('div');
remaining.style.cssText = 'position: absolute; right: 0; top: 0; width: 90px; height: 60px; border: 3px dashed #EF4444; border-left: none; border-bottom: none; opacity: 0;';
rect.appendChild(remaining);
gsap.to(remaining, {opacity: 1, duration: 0.5, delay: 0.6});
} else if (this.tileStep === 3) {
// 16x24的矩形
const rect = document.createElement('div');
rect.className = 'rectangle';
rect.style.width = '120px';
rect.style.height = '80px';
container.appendChild(rect);
const label = document.createElement('div');
label.className = 'rectangle-label';
label.textContent = '16 × 24 (剩余部分)';
rect.appendChild(label);
// 添加1个16x16的砖
const tile = document.createElement('div');
tile.className = 'tile';
tile.style.width = '50px';
tile.style.height = '50px';
tile.style.left = '0px';
tile.style.top = '0px';
rect.appendChild(tile);
const tileLabel = document.createElement('div');
tileLabel.className = 'tile-label';
tileLabel.textContent = '16×16';
tile.appendChild(tileLabel);
gsap.to(tile, {opacity: 1, duration: 0.5});
// 剩余8x16
const remaining = document.createElement('div');
remaining.style.cssText = 'position: absolute; right: 0; top: 0; width: 70px; height: 50px; border: 3px dashed #EF4444; border-left: none; border-bottom: none; opacity: 0;';
rect.appendChild(remaining);
gsap.to(remaining, {opacity: 1, duration: 0.5, delay: 0.6});
} else if (this.tileStep === 4) {
// 8x16的矩形,刚好2个8x8
const rect = document.createElement('div');
rect.className = 'rectangle';
rect.style.width = '80px';
rect.style.height = '50px';
rect.style.border = '3px solid #FCD34D';
container.appendChild(rect);
const label = document.createElement('div');
label.className = 'rectangle-label';
label.textContent = '8 × 16 (最后剩余)';
label.style.color = '#FCD34D';
rect.appendChild(label);
// 添加2个8x8的砖
for (let i = 0; i < 2; i++) {
const tile = document.createElement('div');
tile.className = 'tile';
tile.style.width = '40px';
tile.style.height = '40px';
tile.style.left = (i * 40) + 'px';
tile.style.top = '5px';
tile.style.border = '3px solid #FCD34D';
rect.appendChild(tile);
const tileLabel = document.createElement('div');
tileLabel.className = 'tile-label';
tileLabel.textContent = '8×8';
tile.appendChild(tileLabel);
gsap.to(tile, {opacity: 1, duration: 0.5, delay: i * 0.3});
}
gsap.to(rect, {
scale: [1, 1.1, 1],
duration: 0.6,
delay: 0.8
});
}
},
// 例题展开
toggleExample(index) {
this.activeExample = this.activeExample === index ? null : index;
this.$nextTick(() => this.renderMath());
},
toggleOlympiad(index) {
this.activeOlympiad = this.activeOlympiad === index ? null : index;
this.$nextTick(() => this.renderMath());
},
// 练习题
checkPracticeAnswer() {
if (this.practiceAnswered) return;
const correct = parseInt(this.userAnswer) === this.practiceQuestions[this.currentPracticeIndex].answer;
this.practiceAnswered = true;
this.isPracticeCorrect = correct;
if (correct) {
this.practiceScore += 10;
}
this.$nextTick(() => this.renderMath());
},
nextPractice() {
if (this.currentPracticeIndex < 9) {
this.currentPracticeIndex++;
this.practiceAnswered = false;
this.userAnswer = '';
this.$nextTick(() => this.renderMath());
} else {
this.practiceDone = true;
}
}
},
mounted() {
this.renderMath();
}
}).mount('#app');
</script>
</body>
</html>
💡 这段代码完全由 gemini 生成。
登录后可复制完整代码