<!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>第06讲:图形的剪拼与分割</title>
<style>
/* --- 基础重置与优化 --- */
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
::-webkit-scrollbar { display: none; width: 0 !important; height: 0 !important; }
* { -ms-overflow-style: none; scrollbar-width: none; }
html, body { margin: 0; padding: 0; background: #F5F7FA; overflow: hidden; height: 100vh; font-family: "PingFang SC", "Microsoft YaHei", sans-serif; }
/* 添加背景纹理,增加质感 */
body {
background-image: radial-gradient(#e0e7ff 2px, transparent 2px);
background-size: 24px 24px;
}
#app { height: 100vh; max-width: 480px; margin: 0 auto; background: rgba(255, 255, 255, 0.95); display: flex; flex-direction: column; box-shadow: 0 0 20px rgba(0,0,0,0.05); backdrop-filter: blur(10px); }
.content-area { flex: 1; overflow-y: auto; padding-bottom: 90px; scroll-behavior: smooth; }
/* --- 底部导航 --- */
.bottom-nav {
position: fixed; bottom: 0; left: 50%; transform: translateX(-50%);
width: 100%; max-width: 480px; height: 75px;
background: rgba(255, 255, 255, 0.98); border-top: 1px solid #f0f0f0;
display: flex; justify-content: space-around; align-items: center; z-index: 9999;
box-shadow: 0 -4px 20px rgba(0,0,0,0.03);
padding-bottom: 10px; /* 适配全面屏底部 */
}
.nav-item { flex: 1; display: flex; flex-direction: column; align-items: center; cursor: pointer; padding: 8px 0; color: #94a3b8; transition: all 0.3s; }
.nav-item.active { color: #667eea; transform: translateY(-2px); }
.nav-icon { font-size: 22px; margin-bottom: 2px; }
.nav-label { font-size: 11px; font-weight: 500; }
/* --- 顶部 Tab --- */
.tab-nav { display: flex; background: white; padding: 5px; border-radius: 12px; margin: 0 20px 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.03); }
.tab-item {
flex: 1; padding: 10px; text-align: center; cursor: pointer;
border-radius: 8px; transition: all 0.3s; font-weight: 600; font-size: 15px; color: #64748b;
}
.tab-item.active { background: #e0e7ff; color: #4338ca; }
/* --- 页面通用 --- */
.intro-page { padding: 40px 25px; text-align: center; }
.intro-emoji { font-size: 72px; margin-bottom: 20px; animation: float 3s ease-in-out infinite; }
@keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
.intro-title { font-size: 28px; color: #1e293b; margin-bottom: 20px; font-weight: 800; letter-spacing: 1px; }
.intro-text { font-size: 17px; line-height: 1.7; color: #475569; text-align: justify; margin-bottom: 30px; padding: 20px; background: #fff; border-radius: 16px; box-shadow: 0 4px 15px rgba(0,0,0,0.05); border: 1px solid #f1f5f9; }
.listen-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white; border: none; padding: 16px 45px; border-radius: 30px;
font-size: 18px; font-weight: bold; cursor: pointer;
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
transition: transform 0.2s, box-shadow 0.2s;
}
.listen-btn:active { transform: scale(0.96); box-shadow: 0 4px 10px rgba(102, 126, 234, 0.3); }
.demo-page, .explain-page, .practice-page { padding: 20px; }
.demo-section, .explain-section { display: none; }
.demo-section.active, .explain-section.active { display: block; animation: fadeIn 0.4s ease; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
/* --- 动画演示区 --- */
.animation-area {
background: #fff;
border-radius: 20px; padding: 10px; min-height: 320px; max-height: 320px;
position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center;
box-shadow: inset 0 0 20px rgba(0,0,0,0.02); border: 1px solid #e2e8f0;
}
.svg-container { width: 100%; height: 100%; }
/* 滤镜定义:SVG阴影 */
.svg-shadow { filter: drop-shadow(0px 3px 3px rgba(0,0,0,0.15)); }
.math-area {
background: white; border-left: 4px solid #667eea; border-radius: 0 12px 12px 0;
padding: 15px; margin: 20px 0; min-height: 80px;
display: flex; align-items: center; justify-content: center;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
}
.math-formula { font-size: 18px; font-weight: bold; color: #334155; text-align: center; }
.step-explanation { background: #eff6ff; padding: 15px; border-radius: 12px; color: #3b82f6; font-size: 15px; line-height: 1.5; margin-bottom: 20px; text-align: center; font-weight: 500; }
.prev-btn, .next-btn {
position: absolute; top: 50%; transform: translateY(-50%);
background: rgba(255, 255, 255, 0.9); color: #667eea; border: 1px solid #e2e8f0;
width: 44px; height: 44px; border-radius: 50%; font-size: 18px;
cursor: pointer; display: flex; align-items: center; justify-content: center;
z-index: 100; transition: all 0.2s; box-shadow: 0 4px 10px rgba(0,0,0,0.08);
}
.prev-btn:disabled, .next-btn:disabled { background: #f1f5f9; color: #cbd5e1; cursor: not-allowed; box-shadow: none; }
.prev-btn:active:not(:disabled), .next-btn:active:not(:disabled) { transform: translateY(-50%) scale(0.9); }
.prev-btn { left: 10px; }
.next-btn { right: 10px; }
/* --- 讲解卡片 --- */
.example-card { background: white; border-radius: 16px; padding: 20px; margin-bottom: 15px; box-shadow: 0 4px 12px rgba(0,0,0,0.04); transition: transform 0.2s; }
.example-card:active { transform: scale(0.99); }
.example-header { display: flex; justify-content: space-between; align-items: center; cursor: pointer; }
.example-title { font-weight: bold; color: #1e293b; font-size: 16px; }
.example-answer { color: #667eea; font-weight: bold; background: #e0e7ff; padding: 4px 10px; border-radius: 6px; font-size: 13px; }
.example-content { font-size: 15px; line-height: 1.7; color: #64748b; padding-top: 15px; margin-top: 10px; border-top: 1px dashed #e2e8f0; display: none; }
.example-content.show { display: block; animation: slideDown 0.3s ease; }
@keyframes slideDown { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: translateY(0); } }
/* --- 练习与奥数 --- */
.question-card { background: white; border-radius: 20px; padding: 25px 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.06); }
.question-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; padding-bottom: 15px; border-bottom: 2px solid #f8fafc; }
.question-number { font-size: 15px; color: #94a3b8; font-weight: 600; }
.score-display { font-size: 16px; color: #f59e0b; font-weight: 800; background: #fffbeb; padding: 4px 12px; border-radius: 20px; }
.question-text { font-size: 19px; line-height: 1.6; color: #334155; margin-bottom: 25px; font-weight: 600; }
.options-container { display: flex; flex-direction: column; gap: 15px; margin-bottom: 25px; }
.option-btn {
background: #fff; border: 2px solid #e2e8f0; border-radius: 12px; padding: 16px;
font-size: 16px; color: #475569; text-align: left; cursor: pointer;
transition: all 0.2s; position: relative; overflow: hidden;
}
.option-btn:not(:disabled):active { transform: scale(0.98); background: #f8fafc; }
.option-btn.correct { background: #ecfdf5; border-color: #10b981; color: #047857; font-weight: bold; }
.option-btn.wrong { background: #fef2f2; border-color: #ef4444; color: #b91c1c; }
/* 错误抖动动画 */
.shake { animation: shake 0.5s cubic-bezier(.36,.07,.19,.97) both; }
@keyframes shake { 10%, 90% { transform: translate3d(-1px, 0, 0); } 20%, 80% { transform: translate3d(2px, 0, 0); } 30%, 50%, 70% { transform: translate3d(-4px, 0, 0); } 40%, 60% { transform: translate3d(4px, 0, 0); } }
.feedback-area { padding: 18px; border-radius: 12px; margin-bottom: 20px; font-size: 15px; line-height: 1.6; animation: fadeIn 0.3s; }
.feedback-correct { background: #ecfdf5; color: #065f46; border: 1px solid #d1fae5; }
.feedback-wrong { background: #fff1f2; color: #9f1239; border: 1px solid #ffe4e6; }
.next-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none;
width: 100%; padding: 18px; border-radius: 16px; font-size: 18px; font-weight: bold; cursor: pointer;
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.3);
}
.completion-page { text-align: center; padding: 60px 20px; }
.completion-emoji { font-size: 100px; margin-bottom: 20px; filter: drop-shadow(0 10px 10px rgba(0,0,0,0.1)); }
.final-score { font-size: 60px; color: #f59e0b; font-weight: 800; margin-bottom: 30px; text-shadow: 2px 2px 0px #fcd34d; }
.hint-box { background: #fff7ed; border-left: 5px solid #f97316; padding: 15px; border-radius: 8px; margin: 15px 0; font-size: 14px; color: #9a3412; font-weight: 500; }
.difficulty-badge { display: inline-block; margin-left: 8px; padding: 2px 8px; border-radius: 6px; font-size: 12px; font-weight: 800; vertical-align: middle; }
.difficulty-1 { background: #d1fae5; color: #047857; }
.difficulty-2 { background: #fef3c7; color: #b45309; }
.difficulty-3 { background: #fee2e2; color: #b91c1c; }
/* --- 秘籍卡片 --- */
.secrets-container { padding: 25px; overflow-x: auto; white-space: nowrap; padding-bottom: 40px; -webkit-overflow-scrolling: touch; }
.secret-card {
display: inline-block; width: 280px; height: 320px; border-radius: 24px; padding: 30px; margin-right: 20px;
color: white; white-space: normal; vertical-align: top;
box-shadow: 0 15px 35px rgba(0,0,0,0.15); border: 1px solid rgba(255,255,255,0.2);
position: relative; overflow: hidden;
}
.secret-card::after { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient(rgba(255,255,255,0.1), transparent); pointer-events: none; }
.secret-card:nth-child(1) { background: linear-gradient(135deg, #a18cd1 0%, #fbc2eb 100%); }
.secret-card:nth-child(2) { background: linear-gradient(135deg, #84fab0 0%, #8fd3f4 100%); }
.secret-card:nth-child(3) { background: linear-gradient(135deg, #e0c3fc 0%, #8ec5fc 100%); }
.secret-icon { font-size: 60px; margin-bottom: 25px; text-align: center; text-shadow: 0 4px 10px rgba(0,0,0,0.1); }
.secret-title { font-size: 24px; font-weight: 800; margin-bottom: 15px; text-align: center; }
.secret-content { font-size: 16px; line-height: 1.6; text-align: center; opacity: 0.95; }
</style>
</head>
<body>
<div id="app">
<div class="content-area">
<div v-show="currentPage === 1" class="intro-page">
<div class="intro-emoji">🎂</div>
<div class="intro-title">图形的剪拼与分割</div>
<div class="intro-text">
小朋友们,妈妈切西瓜的时候,切成4块还是切成8块,西瓜的大小变了吗?没有!这就是图形的秘密。<br><br>
学习图形的剪拼,就像玩七巧板和折纸,形状可以千变万化,但图形本身的大小(面积)就像魔法一样不会消失!
</div>
<button class="listen-btn" @click="speak('欢迎学习图形的剪拼与分割。想象一下切蛋糕,不管切成几块,合起来还是原来那么大!')">
🔊 听老师讲解
</button>
</div>
<div v-show="currentPage === 2" class="demo-page">
<div class="tab-nav">
<div class="tab-item" :class="{active: demoTab === 'direct'}" @click="switchDemoTab('direct')">✂️ 图形变换</div>
<div class="tab-item" :class="{active: demoTab === 'theory'}" @click="switchDemoTab('theory')">⚖️ 面积守恒</div>
</div>
<div class="demo-section" :class="{active: demoTab === 'direct'}">
<div class="animation-area">
<svg class="svg-container" viewBox="0 0 400 280">
<defs>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="2" dy="2" stdDeviation="2" flood-color="#000" flood-opacity="0.15"/>
</filter>
</defs>
<rect id="square" x="100" y="50" width="150" height="150" fill="#93c5fd" stroke="#3b82f6" stroke-width="2" filter="url(#shadow)"/>
<path id="cut-line" d="M100,50 L250,200" stroke="#ef4444" stroke-width="3" stroke-dasharray="8,5" opacity="0"/>
<g id="scissor" opacity="0" transform="translate(80, 30)">
<path d="M10,0 L20,20 L0,20 Z" fill="#64748b"/>
<circle cx="5" cy="25" r="5" stroke="#64748b" stroke-width="2" fill="none"/>
<circle cx="15" cy="25" r="5" stroke="#64748b" stroke-width="2" fill="none"/>
</g>
<path id="triangle1" d="M100,50 L250,200 L100,200 Z" fill="#86efac" stroke="#10b981" stroke-width="2" opacity="0" filter="url(#shadow)"/>
<path id="triangle2" d="M100,50 L250,50 L250,200 Z" fill="#86efac" stroke="#10b981" stroke-width="2" opacity="0" filter="url(#shadow)"/>
<rect id="combined-rect" x="50" y="100" width="200" height="75" fill="#fbbf24" stroke="#d97706" stroke-width="2" opacity="0" filter="url(#shadow)"/>
<rect id="combined-square" x="125" y="65" width="150" height="150" fill="#93c5fd" stroke="#3b82f6" stroke-width="2" opacity="0" filter="url(#shadow)"/>
<polygon id="combined-parallelogram" points="80,120 230,120 280,200 130,200" fill="#c4b5fd" stroke="#8b5cf6" stroke-width="2" opacity="0" filter="url(#shadow)"/>
<text id="message" x="200" y="260" text-anchor="middle" font-size="18" font-weight="bold" fill="#333" opacity="0">形状变了,面积不变!✨</text>
</svg>
<button class="prev-btn" @click="prevDirectStep" :disabled="directStep === 0">◀</button>
<button class="next-btn" @click="nextDirectStep" :disabled="directStep === 3">▶</button>
</div>
<div class="math-area">
<div class="math-formula">
<span v-if="directStep === 0">准备一个正方形 □</span>
<span v-if="directStep === 1">□ → 沿对角线剪1刀 → △△</span>
<span v-if="directStep === 2">△ + △ → 拼成各种新图形</span>
<span v-if="directStep === 3">形状会变,面积不变!</span>
</div>
</div>
<div class="step-explanation">
{{ directStepsText[directStep] }}
</div>
</div>
<div class="demo-section" :class="{active: demoTab === 'theory'}">
<div class="animation-area">
<svg class="svg-container" viewBox="0 0 400 280">
<defs>
<filter id="shadow2" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="2" dy="2" stdDeviation="2" flood-color="#000" flood-opacity="0.15"/>
</filter>
</defs>
<rect id="cake" x="100" y="80" width="200" height="60" rx="5" fill="#fca5a5" stroke="#ef4444" stroke-width="2" filter="url(#shadow2)"/>
<line id="cut1" x1="200" y1="80" x2="200" y2="140" stroke="#fff" stroke-width="4" stroke-dasharray="5,3" opacity="0"/>
<rect id="piece1" x="100" y="80" width="100" height="60" fill="#fca5a5" stroke="#ef4444" stroke-width="2" opacity="0" filter="url(#shadow2)"/>
<rect id="piece2" x="200" y="80" width="100" height="60" fill="#fca5a5" stroke="#ef4444" stroke-width="2" opacity="0" filter="url(#shadow2)"/>
<g id="scale" opacity="0" transform-origin="200 180">
<path d="M150 180 L250 180" stroke="#475569" stroke-width="4" stroke-linecap="round"/>
<path d="M200 180 L200 230 M180 230 L220 230" stroke="#475569" stroke-width="4" stroke-linecap="round"/>
<path d="M150 180 L150 200 M250 180 L250 200" stroke="#64748b" stroke-width="2"/>
<rect id="weight-left" x="120" y="200" width="60" height="30" fill="#93c5fd" stroke="#3b82f6" stroke-width="2"/>
<rect id="weight-right" x="220" y="200" width="60" height="30" fill="#93c5fd" stroke="#3b82f6" stroke-width="2"/>
</g>
<text id="theory-text" x="200" y="270" text-anchor="middle" font-size="18" font-weight="bold" fill="#333" opacity="0">⚖️ 左右平衡:面积守恒!</text>
</svg>
<button class="prev-btn" @click="prevTheoryStep" :disabled="theoryStep === 0">◀</button>
<button class="next-btn" @click="nextTheoryStep" :disabled="theoryStep === 2">▶</button>
</div>
<div class="math-area">
<div class="math-formula">
<span v-if="theoryStep === 0">一个完整的蛋糕</span>
<span v-if="theoryStep === 1">蛋糕 → 切成两块 → 1 + 1</span>
<span v-if="theoryStep === 2">(蛋糕面积) = (A块面积) + (B块面积)</span>
</div>
</div>
<div class="step-explanation">
{{ theoryStepsText[theoryStep] }}
</div>
</div>
</div>
<div v-show="currentPage === 3" class="explain-page">
<div class="tab-nav">
<div class="tab-item" :class="{active: explainTab === 'direct'}" @click="switchExplainTab('direct')">直接判断</div>
<div class="tab-item" :class="{active: explainTab === 'theory'}" @click="switchExplainTab('theory')">核心原理</div>
<div class="tab-item" :class="{active: explainTab === 'example'}" @click="switchExplainTab('example')">典型例题</div>
</div>
<div class="explain-section" :class="{active: explainTab === 'direct'}">
<div class="example-card">
<div class="intro-text" style="border:none; box-shadow:none; padding:0; background:none;">
<h3 style="color:#667eea; margin-top:0;">⚡️ 快速判断小技巧</h3>
<ul style="padding-left: 20px; color:#475569;">
<li style="margin-bottom:10px"><strong>对折一次?</strong> 想想折痕。对折圆形→直径,对折正方形→中线。</li>
<li style="margin-bottom:10px"><strong>剪成几块?</strong> 一般来说,剪一刀(直线)会增加一块。</li>
<li><strong>形状相同?</strong> 找对称线,比如正方形的对角线。</li>
</ul>
</div>
</div>
</div>
<div class="explain-section" :class="{active: explainTab === 'theory'}">
<div class="example-card">
<div class="intro-text" style="border:none; box-shadow:none; padding:0; background:none;">
<p><strong>📐 剪拼守恒</strong><br>图形剪开后再拼起来,面积大小不变,就像蛋糕切开再合上还是那么大。</p>
<div style="height:1px; background:#e2e8f0; margin:15px 0;"></div>
<p><strong>🍰 等分分割</strong><br>把图形分成大小相同的几份,像分蛋糕要公平。</p>
<div style="height:1px; background:#e2e8f0; margin:15px 0;"></div>
<p><strong>✨ 形状变换</strong><br>图形的形状变了,但面积可以一样大。</p>
</div>
</div>
</div>
<div class="explain-section" :class="{active: explainTab === 'example'}">
<div class="example-card" v-for="(example, index) in typicalExamples" :key="index" @click="toggleExample(index)">
<div class="example-header">
<div class="example-title">{{ example.title }}</div>
<div class="example-answer">查看解析</div>
</div>
<div class="example-content" :class="{show: example.expanded}">
<div style="font-weight:bold; color:#667eea; margin-bottom:5px;">答案:{{ example.answer }}</div>
<div style="white-space: pre-line;">{{ example.content }}</div>
</div>
</div>
</div>
</div>
<div v-show="currentPage === 4" class="practice-page">
<div v-if="!practiceCompleted">
<div class="question-card">
<div class="question-header">
<div class="question-number">📝 练习 {{currentQuestion + 1}} / {{practiceQuestions.length}}</div>
<div class="score-display">⭐ {{score}}</div>
</div>
<div class="question-text" v-html="practiceQuestions[currentQuestion].text"></div>
<div class="options-container">
<button
v-for="(option, index) in practiceQuestions[currentQuestion].options"
:key="'opt'+index"
class="option-btn"
:class="{
'correct': answered && option.correct,
'wrong': answered && selectedOption === index && !option.correct
}"
@click="selectOption(index, option.correct)"
:disabled="answered"
>
<span v-if="answered && option.correct">✅ </span>
<span v-if="answered && selectedOption === index && !option.correct">❌ </span>
{{['A.','B.','C.','D.'][index]}} {{option.text}}
</button>
</div>
<div v-if="answered" class="feedback-area" :class="isCorrect ? 'feedback-correct' : 'feedback-wrong'">
<div v-if="isCorrect">
<strong>🎉 太棒了!</strong><br>
{{practiceQuestions[currentQuestion].explanation}}
</div>
<div v-else>
<strong>💡 让我们一起分析:</strong><br>
{{practiceQuestions[currentQuestion].explanation}}
</div>
</div>
<button v-if="answered" class="next-btn" @click="nextQuestion">
{{currentQuestion < practiceQuestions.length - 1 ? '下一题 →' : '完成练习 ✓'}}
</button>
</div>
</div>
<div v-else class="completion-page">
<div class="completion-emoji">🎊</div>
<div class="completion-title">基础练习完成!</div>
<div class="final-score">{{score}}分</div>
<button class="next-btn" @click="switchPage(5)">🚀 挑战奥数题</button>
</div>
</div>
<div v-show="currentPage === 5" class="practice-page">
<div v-if="!olympiadCompleted">
<div class="question-card" style="border: 2px solid #fbbf24;">
<div class="question-header">
<div>
<span class="question-number">🏆 挑战 {{currentOlympiad + 1}} / {{olympiadQuestions.length}}</span>
<span class="difficulty-badge" :class="'difficulty-' + olympiadQuestions[currentOlympiad].difficulty">
{{olympiadQuestions[currentOlympiad].difficultyText}}
</span>
</div>
<div class="score-display">⭐ {{olympiadScore}}</div>
</div>
<div class="question-text" v-html="olympiadQuestions[currentOlympiad].text"></div>
<div class="options-container">
<button
v-for="(option, index) in olympiadQuestions[currentOlympiad].options"
:key="'olopt'+index"
class="option-btn"
:class="{
'correct': olympiadAnswered && option.correct,
'wrong': shakingIndex === index,
'shake': shakingIndex === index
}"
@click="selectOlympiadOption(index, option.correct)"
:disabled="olympiadAnswered"
>
{{['A.','B.','C.','D.'][index]}} {{option.text}}
</button>
</div>
<div v-if="wrongAttempts > 0 && !olympiadAnswered">
<div class="hint-box" v-if="wrongAttempts === 1">
<strong>💡 提示1:</strong> {{olympiadQuestions[currentOlympiad].hint1}}
</div>
<div class="hint-box" v-if="wrongAttempts === 2">
<strong>💡 提示2:</strong> {{olympiadQuestions[currentOlympiad].hint2}}
</div>
</div>
<div v-if="olympiadAnswered" class="feedback-area" :class="isOlympiadCorrect ? 'feedback-correct' : 'feedback-wrong'">
<div v-if="isOlympiadCorrect">
<strong>🏆 厉害!</strong><br>
{{olympiadQuestions[currentOlympiad].explanation}}
</div>
<div v-else>
<strong>📖 详细解析:</strong><br>
{{olympiadQuestions[currentOlympiad].explanation}}
</div>
</div>
<button v-if="olympiadAnswered || wrongAttempts >= 3" class="next-btn" @click="nextOlympiad">
{{currentOlympiad < olympiadQuestions.length - 1 ? '下一题 →' : '查看最终奖励'}}
</button>
</div>
</div>
<div v-else class="completion-page">
<div class="completion-emoji">🏆</div>
<div class="completion-title">奥数挑战通关!</div>
<div class="final-score">{{olympiadScore}}分</div>
<button class="next-btn" @click="switchPage(6)">🎁 查看通关秘籍</button>
</div>
</div>
<div v-show="currentPage === 6" class="secrets-container">
<div class="secret-card">
<div class="secret-icon">🔄</div>
<div class="secret-title">对折省力法</div>
<div class="secret-content">要分成相等的部分,用对折最省力。折痕就是我们的辅助线。</div>
</div>
<div class="secret-card">
<div class="secret-icon">⚖️</div>
<div class="secret-title">面积不变法</div>
<div class="secret-content">记住!剪开拼起来,形状虽然变了,但总面积大小永远不变。</div>
</div>
<div class="secret-card">
<div class="secret-icon">✂️</div>
<div class="secret-title">动手试试法</div>
<div class="secret-content">遇到想不出来的题,拿张废纸实际剪剪看,马上就明白了。</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,
demoTab: 'direct',
explainTab: 'direct',
directStep: 0,
theoryStep: 0,
shakingIndex: null, // 控制选项抖动
practiceQuestions: [
{ text: "题目1:圆形纸对折一次,折痕是什么线?", options: [{text: "直径", correct: true}, {text: "半径", correct: false}, {text: "圆周", correct: false}, {text: "弧线", correct: false}], explanation: "经过圆心的直线是直径。" },
{ text: "题目2:正方形沿对角线剪开,得到几个三角形?", options: [{text: "1个", correct: false}, {text: "2个", correct: true}, {text: "3个", correct: false}, {text: "4个", correct: false}], explanation: "一条对角线分成2个三角形。" },
{ text: "题目3:把长方形剪成两个相同的三角形,应该怎么剪?", options: [{text: "沿对角线剪", correct: true}, {text: "沿中线横着剪", correct: false}, {text: "沿中线竖着剪", correct: false}, {text: "随便剪", correct: false}], explanation: "沿对角线剪成两个相同的三角形。" },
{ text: "题目4:一个蛋糕平均分给4个小朋友,每人分到几分之几?", options: [{text: "1/2", correct: false}, {text: "1/3", correct: false}, {text: "1/4", correct: true}, {text: "1/5", correct: false}], explanation: "每人得1/4。" },
{ text: "题目5:正方形剪成4个相同的小正方形,要剪几刀?", options: [{text: "1刀", correct: false}, {text: "2刀", correct: true}, {text: "3刀", correct: false}, {text: "4刀", correct: false}], explanation: "2刀就够了(横1刀,竖1刀)。" },
{ text: "题目6:长方形纸剪成两个正方形,可能吗?", options: [{text: "可能", correct: true}, {text: "不可能", correct: false}, {text: "一定可以", correct: false}, {text: "需要很多刀", correct: false}], explanation: "长是宽的2倍时,中间剪1刀,可以变成2个正方形。" },
{ text: "题目7:三角形饼干对折,会变成什么形状?", options: [{text: "三角形", correct: true}, {text: "长方形", correct: false}, {text: "正方形", correct: false}, {text: "不规则形", correct: false}], explanation: "三角形对折还是三角形。" },
{ text: "题目8:用2个相同的三角形,可以拼成什么图形?", options: [{text: "只能拼正方形", correct: false}, {text: "只能拼长方形", correct: false}, {text: "可以拼多种", correct: true}, {text: "拼不成", correct: false}], explanation: "答案是可以拼多种(平行四边形、长方形、正方形、大三角形)。" }
],
olympiadQuestions: [
{
text: "题目1:用一个正方形和两个三角形(三角形是正方形对角线剪成的),可以拼成什么新图形?",
options: [{text: "大正方形", correct: false}, {text: "长方形", correct: false}, {text: "梯形", correct: false}, {text: "以上都可以", correct: true}],
hint1: "2个三角形合起来等于1个正方形。", hint2: "相当于有2个正方形的面积。", hint3: "可以拼成多种图形。",
explanation: "1个正方形+2个三角形(正好等于1个正方形大小)总面积=2个正方形。可以拼成:大正方形、长方形、梯形等多种形状。", difficulty: 1, difficultyText: "⭐"
},
{
text: "题目2:一张长方形纸,长10厘米,宽5厘米。对折后,纸的总面积是原来的多少?",
options: [{text: "一样大", correct: true}, {text: "一半大", correct: false}, {text: "两倍大", correct: false}, {text: "1/4大", correct: false}],
hint1: "对折是把纸叠起来。", hint2: "纸的总面积变了吗?", hint3: "纸还是那张纸,面积不变。",
explanation: "对折只是形状变了,纸的面积没有变!原来:10×5=50平方厘米。对折后:还是这张纸,还是50平方厘米。", difficulty: 1, difficultyText: "⭐"
},
{
text: "题目3:七巧板有7块,其中5块是三角形,1块是正方形,1块是平行四边形。如果最小的三角形面积是1,最大的三角形面积是多少?",
options: [{text: "2", correct: false}, {text: "3", correct: false}, {text: "4", correct: true}, {text: "8", correct: false}],
hint1: "观察七巧板的比例关系。", hint2: "最大三角形可以分成几个最小三角形?", hint3: "答案是4。",
explanation: "七巧板中最小三角形和最大三角形的关系:最大三角形=4个最小三角形。所以面积是:1×4=4。", difficulty: 2, difficultyText: "⭐⭐"
},
{
text: "题目4:一个披萨,第一刀切成2块,第二刀切成4块,第三刀最多切成几块?",
options: [{text: "5块", correct: false}, {text: "6块", correct: false}, {text: "7块", correct: true}, {text: "8块", correct: false}],
hint1: "每一刀都和前面的刀相交。", hint2: "第3刀可以和前2刀都相交。", hint3: "4+3=7块。",
explanation: "切披萨规律:0刀:1块;1刀:2块(增加1块);2刀:4块(增加2块);3刀:最多7块(增加3块)。规律:第N刀增加N块。", difficulty: 2, difficultyText: "⭐⭐"
},
{
text: "题目5:长方形纸剪成两个小长方形,有几种剪法?",
options: [{text: "1种", correct: false}, {text: "2种", correct: true}, {text: "3种", correct: false}, {text: "无数种", correct: false}],
hint1: "要剪成长方形,不能斜着剪。", hint2: "可以横着剪或竖着剪。", hint3: "2种方法。",
explanation: "长方形剪成两个小长方形:方法1:横着剪(平行于宽);方法2:竖着剪(平行于长)。斜着剪不行(会变成梯形或三角形)。所以是2种方法。", difficulty: 1, difficultyText: "⭐"
},
{
text: "题目6:用4个相同的小正方形,可以拼成几种不同的图形?(图形可以翻转,但形状要不同)",
options: [{text: "3种", correct: false}, {text: "4种", correct: false}, {text: "5种", correct: true}, {text: "6种", correct: false}],
hint1: "可以排成一行,也可以排成方形。", hint2: "还可以拼成各种字母形状。", hint3: "画画看,有5种。",
explanation: "4个小正方形可以拼成:1. 大正方形(2×2);2. 一字长条(1×4);3. L形;4. T形;5. Z形。一共5种。", difficulty: 3, difficultyText: "⭐⭐⭐"
},
{
text: "题目7:正方形纸对折3次,完全展开后会有几条折痕?",
options: [{text: "3条", correct: false}, {text: "4条", correct: false}, {text: "5条", correct: false}, {text: "7条", correct: true}],
hint1: "每对折一次,折痕会增加。", hint2: "对折2次试试,数数有几条折痕。", hint3: "对折3次有7条折痕。",
explanation: "对折1次:1条折痕;对折2次:3条折痕(1+2);对折3次:7条折痕(1+2+4)。规律:每次对折,折痕数量翻倍再加1。", difficulty: 2, difficultyText: "⭐⭐"
},
{
text: "题目8:圆形纸剪成两个半圆,再把每个半圆剪成两个1/4圆,一共剪了几刀?",
options: [{text: "2刀", correct: false}, {text: "3刀", correct: true}, {text: "4刀", correct: false}, {text: "5刀", correct: false}],
hint1: "先剪成两半。", hint2: "每个半圆再剪一刀。", hint3: "1+1+1=3刀。",
explanation: "第1刀:圆形→2个半圆;第2刀:一个半圆→2个1/4圆;第3刀:另一个半圆→2个1/4圆。一共3刀。", difficulty: 2, difficultyText: "⭐⭐"
}
],
typicalExamples: [
{title: "例题1:基础题", answer: "1刀", content: "第1步:想象一个正方形□\n第2步:从一个角到对角画一条线\n第3步:沿着这条线剪1刀\n第4步:就变成了两个三角形△△", expanded: false},
{title: "例题2:进阶题", answer: "长方形或正方形", content: "第1步:长方形有两种对折方法\n第2步:沿着长边对折→变成更小的长方形\n第3步:沿着短边对折→也变成长方形\n第4步:无论怎么折,都是长方形", expanded: false},
{title: "例题3:易错题", answer: "2刀", content: "【易错点】:有的小朋友会说要剪4刀,其实不用。\n【正确做法】:\n第1步:画个正方形,想象变成'田'字\n第2步:横着剪1刀(中间横切)\n第3步:竖着剪1刀(中间竖切)\n第4步:2刀就变成4个小正方形了!", expanded: false}
],
score: 0,
olympiadScore: 0,
currentQuestion: 0,
currentOlympiad: 0,
answered: false,
olympiadAnswered: false,
isCorrect: false,
isOlympiadCorrect: false,
selectedOption: null,
selectedOlympiadOption: null,
practiceCompleted: false,
olympiadCompleted: false,
wrongAttempts: 0,
directStepsText: [
"这是一个淡蓝色的正方形。",
"一把小剪刀沿着对角线将正方形剪成了两个完全一样的三角形!",
"看!两个三角形可以拼成长方形、正方形、平行四边形...形状变啦!",
"不管怎么拼,这些图形都是由原来那一个正方形变来的,它们的面积总和永远等于原来正方形的面积!"
],
theoryStepsText: [
"这是一个完整的草莓蛋糕,它的面积就是这么大。",
"我们把蛋糕从中间切成两半,变成了A块和B块。",
"看天平!A块加B块的重量,和原来整个蛋糕的重量是一样的。图形剪开再拼合,总面积就像蛋糕一样不会多也不会少!"
]
};
},
mounted() {
this.runDirectAnimation();
this.runTheoryAnimation();
},
methods: {
switchPage(page) {
this.stopSpeak();
this.currentPage = page;
window.scrollTo(0,0);
if (page === 2) {
this.directStep = 0;
this.theoryStep = 0;
this.$nextTick(() => {
this.runDirectAnimation();
this.runTheoryAnimation();
});
}
if (page === 4 || page === 5) {
this.score = 0;
this.currentQuestion = 0;
this.practiceCompleted = false;
}
},
// --- 微信语音逻辑保持原样 ---
stopSpeak() {
const isWeChat = /MicroMessenger/i.test(navigator.userAgent);
if (isWeChat) {
const audio = document.getElementById('tts-audio');
if (audio) {
audio.pause();
audio.currentTime = 0;
}
} else {
if (window.speechSynthesis) {
window.speechSynthesis.cancel();
}
}
},
speak(text) {
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(err => { console.log('语音播放失败:', err); });
} else {
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = 'zh-CN';
utterance.rate = 0.9;
window.speechSynthesis.speak(utterance);
}
},
// --- 动画逻辑优化 ---
switchDemoTab(tab) {
this.stopSpeak();
this.demoTab = tab;
},
switchExplainTab(tab) {
this.stopSpeak();
this.explainTab = tab;
},
runDirectAnimation() {
if (typeof gsap === 'undefined') return;
const tl = gsap.timeline();
tl.set("#square", {opacity: 1});
tl.set("#cut-line, #scissor, #triangle1, #triangle2, #combined-rect, #combined-square, #combined-parallelogram, #message", {opacity: 0});
if (this.directStep === 0) {
tl.to("#square", {opacity: 1, duration: 0.5});
} else if (this.directStep === 1) {
tl.to("#scissor", {opacity: 1, x: 0, y: 0, duration: 0.5})
.to("#scissor", {x: 170, y: 170, duration: 1.5, ease: "power1.inOut"})
.to("#cut-line", {opacity: 1, duration: 0.5}, "-=1.5")
.to("#square", {opacity: 0, duration: 0.1})
.to("#triangle1", {opacity: 1, duration: 0}, "-=0.1")
.to("#triangle2", {opacity: 1, duration: 0}, "-=0.1")
.to("#triangle1", {x: -10, y: 10, duration: 0.5}) // 剪开分离效果
.to("#triangle2", {x: 10, y: -10, duration: 0.5}, "<")
.to("#scissor", {opacity: 0, duration: 0.3});
} else if (this.directStep === 2) {
// 复杂的拼图动画
tl.to("#triangle1", {x: -60, y: 60, rotation: -10, duration: 0.8})
.to("#triangle2", {x: 120, y: -60, rotation: 10, duration: 0.8}, "<")
.to("#triangle1", {rotation: 180, x:0, y:0, opacity:0, duration: 0.5})
.to("#triangle2", {rotation: 180, x:0, y:0, opacity:0, duration: 0.5}, "<")
.to("#combined-rect", {opacity: 1, scale: 1.1, duration: 0.4}, "-=0.2")
.to("#combined-rect", {scale: 1, duration: 0.2})
.to("#combined-rect", {opacity: 0, duration: 0.5, delay: 1})
.to("#combined-square", {opacity: 1, scale: 1.1, duration: 0.4})
.to("#combined-square", {scale: 1, duration: 0.2})
.to("#combined-square", {opacity: 0, duration: 0.5, delay: 1})
.to("#combined-parallelogram", {opacity: 1, scale: 1.1, duration: 0.4})
.to("#combined-parallelogram", {scale: 1, duration: 0.2});
} else if (this.directStep === 3) {
tl.to("#combined-parallelogram", {opacity: 0, duration: 0.5})
.to("#square", {opacity: 1, duration: 0.8, ease: "elastic.out(1, 0.5)"})
.to("#message", {opacity: 1, y: -10, duration: 0.8});
}
},
runTheoryAnimation() {
if (typeof gsap === 'undefined') return;
const tl = gsap.timeline();
tl.set("#cake", {opacity: 1});
tl.set("#cut1, #piece1, #piece2, #scale, #theory-text", {opacity: 0});
if (this.theoryStep === 0) {
tl.to("#cake", {opacity: 1, duration: 0.5});
} else if (this.theoryStep === 1) {
tl.to("#cut1", {opacity: 1, duration: 0.3})
.to("#cake", {opacity: 0, duration: 0.1})
.to("#piece1", {opacity: 1, duration: 0}, "<")
.to("#piece2", {opacity: 1, duration: 0}, "<")
.to("#piece1", {x: -10, duration: 0.5})
.to("#piece2", {x: 10, duration: 0.5}, "<");
} else if (this.theoryStep === 2) {
tl.to("#piece1", {x: -70, y: 80, scale: 0.6, duration: 1, ease: "back.out(1.7)"})
.to("#piece2", {x: 70, y: 80, scale: 0.6, duration: 1, ease: "back.out(1.7)"}, "<")
.to("#scale", {opacity: 1, duration: 0.5}, "-=0.5")
// 天平晃动效果
.to("#scale", {rotation: 5, duration: 0.3})
.to("#scale", {rotation: -3, duration: 0.3})
.to("#scale", {rotation: 0, duration: 0.5, ease: "elastic.out(1, 0.3)"})
.to("#theory-text", {opacity: 1, scale: 1.1, duration: 0.5});
}
},
nextDirectStep() {
if (this.directStep < 3) {
this.directStep++;
this.runDirectAnimation();
}
},
prevDirectStep() {
if (this.directStep > 0) {
this.directStep--;
this.runDirectAnimation();
}
},
nextTheoryStep() {
if (this.theoryStep < 2) {
this.theoryStep++;
this.runTheoryAnimation();
}
},
prevTheoryStep() {
if (this.theoryStep > 0) {
this.theoryStep--;
this.runTheoryAnimation();
}
},
toggleExample(index) {
this.typicalExamples[index].expanded = !this.typicalExamples[index].expanded;
},
selectOption(index, correct) {
if (this.answered) return;
this.answered = true;
this.selectedOption = index;
this.isCorrect = correct;
if (correct) {
this.score += 20;
if (typeof confetti !== 'undefined') {
confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } });
}
}
},
nextQuestion() {
this.answered = false;
this.selectedOption = null;
if (this.currentQuestion < this.practiceQuestions.length - 1) {
this.currentQuestion++;
} else {
this.practiceCompleted = true;
}
},
selectOlympiadOption(index, correct) {
if (this.olympiadAnswered) return;
if (correct) {
this.selectedOlympiadOption = index;
this.olympiadAnswered = true;
this.isOlympiadCorrect = true;
this.wrongAttempts = 0;
this.olympiadScore += 20;
if (typeof confetti !== 'undefined') {
confetti({ particleCount: 150, spread: 80, origin: { y: 0.6 } });
}
} else {
// 错误处理:触发抖动
this.shakingIndex = index;
setTimeout(() => { this.shakingIndex = null; }, 500); // 移除抖动类
this.wrongAttempts++;
if (this.wrongAttempts >= 3) {
this.selectedOlympiadOption = index;
this.olympiadAnswered = true;
this.isOlympiadCorrect = false;
}
}
},
nextOlympiad() {
this.olympiadAnswered = false;
this.selectedOlympiadOption = null;
this.wrongAttempts = 0;
if (this.currentOlympiad < this.olympiadQuestions.length - 1) {
this.currentOlympiad++;
} else {
this.olympiadCompleted = true;
}
}
}
}).mount('#app');
</script>
</body>
</html>
💡 这段代码完全由 AI 生成。
登录后可复制完整代码