<!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>第12讲:间隔问题(植树问题雏形)</title>
<style>
/* ================= 基础重置与全局样式 ================= */
:root {
--primary: #a29bfe; /* 薰衣草紫 */
--primary-dark: #6c5ce7;
--accent: #ffeaa7; /* 奶油黄 */
--success: #00b894; /* 薄荷绿 */
--error: #ff7675; /* 珊瑚红 */
--bg-color: #f0f3f5;
--text-main: #2d3436;
--text-sub: #636e72;
--stick-wood: #f1c40f;
--stick-head: #c0392b;
}
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; font-family: "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif; }
::-webkit-scrollbar { display: none; }
html, body { margin: 0; padding: 0; background: var(--bg-color); overflow: hidden; height: 100vh; }
/* 动态背景图案 */
body {
background-image: radial-gradient(#dfe6e9 1px, transparent 1px);
background-size: 20px 20px;
}
#app { height: 100vh; max-width: 480px; margin: 0 auto; background: rgba(255,255,255,0.95); display: flex; flex-direction: column; position: relative; box-shadow: 0 0 40px rgba(0,0,0,0.08); }
.content-area { flex: 1; overflow-y: auto; padding-bottom: 90px; scroll-behavior: smooth; padding-top: 10px; }
/* 通用动画类 */
.fade-in { animation: fadeIn 0.4s ease-out; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
.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); } }
/* ================= 底部导航 (App Bar) ================= */
.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 rgba(0,0,0,0.05);
display: flex; justify-content: space-around; align-items: center;
z-index: 9999; box-shadow: 0 -5px 20px rgba(0,0,0,0.03);
backdrop-filter: blur(10px);
padding-bottom: 10px;
}
.nav-item { flex: 1; display: flex; flex-direction: column; align-items: center; cursor: pointer; padding: 5px; color: #b2bec3; transition: all 0.3s; }
.nav-item.active { color: var(--primary-dark); transform: translateY(-3px); }
.nav-icon { font-size: 24px; margin-bottom: 2px; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1)); }
.nav-label { font-size: 11px; font-weight: 600; }
/* ================= 顶部 Tab 导航 ================= */
.tab-nav {
display: flex; background: white; margin: 10px 20px 20px;
border-radius: 16px; padding: 5px; box-shadow: 0 4px 15px rgba(0,0,0,0.05);
}
.tab-item {
flex: 1; padding: 10px; text-align: center; cursor: pointer;
font-weight: 600; color: var(--text-sub); border-radius: 12px;
transition: all 0.3s; font-size: 14px;
}
.tab-item.active { background: #e0e7ff; color: var(--primary-dark); }
/* ================= 页面通用 ================= */
.page-title { font-size: 24px; font-weight: 800; color: var(--text-main); margin: 20px 20px 10px; text-align: center; letter-spacing: 1px; }
.page-subtitle { color: var(--primary-dark); font-size: 16px; margin: 25px 20px 15px; font-weight: 800; display: flex; align-items: center; gap: 8px; justify-content: center; }
.page-subtitle::before, .page-subtitle::after { content: ''; display: block; width: 20px; height: 2px; background: var(--primary); opacity: 0.5; }
/* ================= 概念页 ================= */
.intro-page { padding: 30px 20px; }
.intro-emoji { font-size: 80px; margin-bottom: 20px; animation: float 3s infinite ease-in-out; }
@keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
.story-box {
background: white; border-radius: 24px; padding: 30px 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.08); text-align: left;
border: 1px solid rgba(0,0,0,0.02); margin-bottom: 20px;
line-height: 1.8; font-size: 16px; color: var(--text-sub);
}
.concept-box {
background: #f8f9fa; border-radius: 16px; padding: 20px;
text-align: left; font-size: 15px; color: var(--text-main);
margin-bottom: 25px; line-height: 1.6; border-left: 5px solid var(--primary);
}
.concept-box strong { color: var(--primary-dark); }
.concept-box ul { margin: 10px 0 10px 20px; padding: 0; }
.concept-box li { margin-bottom: 8px; }
.speak-btn {
background: linear-gradient(135deg, var(--primary) 0%, #ff6b6b 100%);
color: white; border: none; padding: 16px 40px; border-radius: 50px;
font-size: 18px; font-weight: bold; cursor: pointer;
box-shadow: 0 8px 20px rgba(255, 107, 107, 0.4);
transition: transform 0.2s; width: 80%; margin: 0 auto; display: flex; justify-content: center; align-items: center; gap: 10px;
}
.speak-btn:active { transform: scale(0.96); }
/* ================= 动画演示区 ================= */
.demo-page { padding: 0 15px; }
.demo-section { display: none; }
.demo-section.active { display: block; animation: fadeIn 0.5s ease; }
.animation-area {
background: #ffffff; border-radius: 24px; padding: 10px;
min-height: 320px; position: relative; overflow: hidden;
box-shadow: inset 0 0 30px rgba(0,0,0,0.02), 0 10px 20px rgba(0,0,0,0.05);
border: 1px solid rgba(0,0,0,0.05); margin-bottom: 20px;
}
.svg-container { width: 100%; height: 100%; min-height: 280px; }
/* SVG 阴影滤镜 */
.svg-shadow { filter: drop-shadow(2px 4px 6px rgba(0,0,0,0.2)); }
.math-area {
background: white; border-left: 5px solid var(--accent);
border-radius: 0 12px 12px 0; padding: 15px; margin: 10px 0 20px;
display: flex; align-items: center; justify-content: center;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
}
.math-formula { font-size: 24px; font-weight: 800; color: var(--text-main); font-family: monospace; }
.step-explanation {
background: #eef2ff; padding: 15px; border-radius: 12px;
color: var(--primary-dark); font-size: 15px; text-align: center;
margin-bottom: 90px; line-height: 1.6; font-weight: 500;
}
/* 悬浮控制按钮 */
.step-btn-floating {
position: absolute; top: 50%; transform: translateY(-50%); z-index: 100;
background: rgba(255,255,255,0.9); backdrop-filter: blur(5px);
color: var(--primary-dark); border: 1px solid rgba(0,0,0,0.1);
width: 44px; height: 44px; border-radius: 50%; font-size: 18px; font-weight: bold;
cursor: pointer; transition: all 0.2s; box-shadow: 0 4px 10px rgba(0,0,0,0.1);
display: flex; align-items: center; justify-content: center;
}
.step-btn-prev { left: 10px; }
.step-btn-next { right: 10px; }
.step-btn-floating:disabled { opacity: 0.5; cursor: not-allowed; box-shadow: none; }
.step-btn-floating:active:not(:disabled) { transform: translateY(-50%) scale(0.95); }
/* ================= 讲解页 ================= */
.explain-page { padding: 20px; }
.example-card {
background: white; border-radius: 20px; padding: 20px; margin-bottom: 20px;
box-shadow: 0 5px 15px rgba(0,0,0,0.05); transition: transform 0.2s;
border: 1px solid #f1f2f6;
}
.example-card:active { transform: scale(0.98); }
.example-header {
display: flex; justify-content: space-between; align-items: center;
cursor: pointer; padding-bottom: 10px; border-bottom: 1px dashed #eee;
margin-bottom: 10px;
}
.example-title { font-weight: 800; color: var(--primary-dark); font-size: 16px; }
.toggle-btn { font-size: 14px; color: #b2bec3; transition: transform 0.3s; }
.toggle-btn.open { transform: rotate(90deg); }
.example-body { display: none; padding-top: 5px; }
.example-body.show { display: block; animation: slideDown 0.3s ease; }
@keyframes slideDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
.example-a {
background: #eafff3; padding: 12px; border-radius: 10px;
font-size: 14px; color: var(--text-sub); border-left: 4px solid var(--success); margin-top: 10px;
font-weight: bold;
}
.example-q { font-weight: bold; color: #555; margin-bottom: 10px; }
.example-exp { color: #666; line-height: 1.6; font-size: 14px; margin-top: 10px; }
/* ================= 练习/奥数 ================= */
.practice-page { padding: 20px; }
.question-card {
background: white; border-radius: 24px; padding: 25px;
box-shadow: 0 10px 25px rgba(0,0,0,0.08);
}
.question-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; border-bottom: 2px solid #f1f2f6; padding-bottom: 15px; }
.question-number { font-weight: 800; color: var(--primary); font-size: 16px; }
.score-display { color: var(--stick-wood); font-weight: 900; font-size: 18px; text-shadow: 1px 1px 0 rgba(0,0,0,0.1); }
.question-text { font-size: 18px; line-height: 1.6; color: var(--text-main); margin-bottom: 25px; font-weight: 600; }
.option-btn {
display: block; width: 100%; padding: 16px; margin-bottom: 12px;
text-align: left; border: 2px solid #f1f2f6; border-radius: 16px;
background: white; font-size: 16px; cursor: pointer; transition: all 0.2s;
color: var(--text-sub); position: relative; overflow: hidden;
}
.option-btn:active:not(:disabled) { transform: scale(0.98); background: #f1f2f6; }
.option-btn.correct { background: #eafff3; border-color: var(--success); color: #009432; font-weight: bold; }
.option-btn.wrong { background: #fff5f5; border-color: var(--error); color: #c0392b; }
.feedback-area {
padding: 15px; border-radius: 12px; margin-bottom: 20px;
font-size: 15px; line-height: 1.6; animation: fadeIn 0.3s;
}
.feedback-correct { background: #eafff3; color: #009432; border: 1px solid #b8e994; }
.feedback-wrong { background: #fff5f5; color: #c0392b; border: 1px solid #ffcccc; }
.next-btn {
background: linear-gradient(135deg, var(--accent) 0%, #fab1a0 100%);
color: #d35400; border: none; padding: 16px; width: 100%; border-radius: 16px;
font-size: 18px; font-weight: 800; cursor: pointer;
box-shadow: 0 8px 20px rgba(253, 203, 110, 0.4);
}
.next-btn:active { transform: scale(0.97); }
.completion-page { text-align: center; padding: 60px 20px; }
.completion-emoji { font-size: 80px; margin-bottom: 20px; animation: float 3s infinite; }
.final-score { font-size: 48px; font-weight: 900; color: var(--primary); margin: 20px 0 40px; text-shadow: 2px 2px 0px rgba(0,0,0,0.1); }
.restart-btn {
background: linear-gradient(135deg, #2ecc71 0%, #26de81 100%);
color: white; border: none; padding: 16px 50px; border-radius: 50px;
font-size: 18px; font-weight: bold; cursor: pointer; box-shadow: 0 10px 20px rgba(0, 184, 148, 0.3);
}
.hint-box { background: #fff7e6; border-left: 5px solid var(--primary); padding: 15px; border-radius: 8px; margin: 15px 0; font-size: 14px; color: #e67e22; font-weight: 500; }
.difficulty-badge {
display: inline-block; background: #ffeaa7; color: #d35400;
border-radius: 8px; padding: 3px 8px; font-size: 12px; margin-left: 10px; font-weight: bold;
}
/* ================= 秘籍页 ================= */
.secrets-container { padding: 20px; padding-bottom: 40px; }
/* 全宽卡片布局,支持横向滑动 */
.secrets-scroll {
display: flex;
overflow-x: auto;
gap: 15px;
scroll-snap-type: x mandatory;
padding-bottom: 20px; /* 留出滚动条或底部空间 */
width: 100%;
}
.secrets-scroll::-webkit-scrollbar { display: none; } /* 隐藏滚动条 */
.secret-card {
flex: 0 0 100%; /* 宽度占视口 100%,一张就是一页 */
width: 100%;
min-height: 500px; /* 满足最小高度500px的要求 */
background: white;
border-radius: 24px;
padding: 30px 25px;
box-shadow: 0 15px 40px rgba(0,0,0,0.1);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
scroll-snap-align: center; /* 滑动吸附 */
border-top: 8px solid var(--accent);
}
/* 渐变背景 */
.secret-card:nth-child(1) { background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%); border: none; }
.secret-card:nth-child(2) { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); border: none; }
.secret-card:nth-child(3) { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); border: none; }
.secret-icon { font-size: 80px; margin-bottom: 25px; animation: float 3s infinite; }
.secret-title { font-size: 26px; font-weight: 800; color: white; margin-bottom: 20px; text-shadow: 0 2px 5px rgba(0,0,0,0.1); }
.secret-content { font-size: 18px; line-height: 1.8; color: white; font-weight: 500; }
</style>
</head>
<body>
<div id="app">
<div class="content-area">
<div v-show="currentPage === 1" class="intro-page fade-in">
<div class="page-title">第12讲:间隔问题</div>
<div class="intro-emoji">📏</div>
<div class="story-box">
<strong>💭 生活小故事:数栏杆</strong><br><br>
小明放学回家,看到马路边的栏杆。他数了数,有5根栏杆:| | | | |。他发现栏杆之间有空隙!<br><br>
<strong>🤔 想一想:</strong>5根栏杆中间有几个空隙呢?
</div>
<div class="concept-box">
<strong>📚 核心概念</strong>
<ul>
<li><strong>间隔与物体</strong>:栏杆和栏杆之间的空隙叫间隔,间隔数通常比物体数少1</li>
<li><strong>两端情况</strong>:两端都有物体,间隔数=物体数-1;两端都没有,间隔数=物体数+1</li>
<li><strong>植树问题</strong>:在路的两边种树,要数清楚间隔和树的数量关系</li>
</ul>
</div>
<button class="teacher-btn speak-btn" @click="speak('同学们,大家好!今天我们来学习间隔问题。看看马路边的栏杆,栏杆和栏杆之间的空隙,就叫做间隔。')">
<span>🎤</span> 听老师讲解
</button>
</div>
<div v-show="currentPage === 2" class="demo-page fade-in">
<div class="page-subtitle">间隔公式演示</div>
<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 330" preserveAspectRatio="xMidYMid meet">
<rect x="50" y="200" width="300" height="20" fill="#8B4513"/>
<rect x="50" y="180" width="300" height="20" fill="#D2691E"/>
<g id="trees">
</g>
<g id="intervals">
</g>
<text id="title-text" x="200" y="40" text-anchor="middle" font-size="18" font-weight="bold" fill="#333" opacity="0">5棵树,4个间隔</text>
<text id="formula-text" x="200" y="70" text-anchor="middle" font-size="16" fill="#667eea" opacity="0">间隔数 = 树的棵数 - 1</text>
</svg>
<button class="step-btn-floating step-btn-prev" @click="prevDirectStep" :disabled="directStep === 0">◀</button>
<button class="step-btn-floating step-btn-next" @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">5棵树</span>
<span v-if="directStep === 2">4个间隔</span>
<span v-if="directStep === 3">间隔数 = 5 - 1 = 4</span>
</div>
</div>
<div class="step-explanation">
<div v-if="directStep === 0">画面上出现一条笔直的小路。</div>
<div v-if="directStep === 1">小树苗从天上掉下来,种在小路的两端和中间,一共5棵。</div>
<div v-if="directStep === 2">闪烁显示树之间的空隙。每两棵树之间是一个间隔,有4个间隔,每个间隔5米。</div>
<div v-if="directStep === 3">得出结论:5棵树,4个间隔。公式:间隔数 = 树的棵数 - 1。</div>
</div>
</div>
<div class="demo-section" :class="{active: demoTab === 'theory'}">
<div class="animation-area" style="display: flex; align-items: center; justify-content: center; flex-direction: column; padding: 40px;">
<div style="font-size: 60px; margin-bottom: 20px;">🔍</div>
<div style="text-align: center; font-size: 18px; line-height: 1.6;">
<strong>两端都种树(最常见情况)</strong><br>
间隔数 = 树的棵数 - 1<br><br>
<strong>两端都不种树</strong><br>
间隔数 = 树的棵数 + 1<br><br>
<strong>围成一圈(环形)</strong><br>
间隔数 = 树的棵数
</div>
</div>
<div class="step-explanation">
记住这三种情况的公式,就能解决大部分间隔问题!
</div>
</div>
</div>
<div v-show="currentPage === 3" class="explain-page fade-in">
<div class="page-subtitle">典型例题讲解</div>
<div class="tab-nav">
<div class="tab-item" :class="{active: explainTab === 'direct'}" @click="explainTab = 'direct'">基础题</div>
<div class="tab-item" :class="{active: explainTab === 'theory'}" @click="explainTab = 'theory'">进阶题</div>
<div class="tab-item" :class="{active: explainTab === 'example'}" @click="explainTab = 'example'">易错题</div>
</div>
<div class="explain-content">
<div class="explain-section" :class="{active: explainTab === 'direct'}">
<div class="concept-box">
间隔问题的基本公式:<strong>间隔数 = 物体数 - 1</strong><br>
适用于:路灯、柱子、排队的人等两端都有的情况。
</div>
<div class="example-card">
<div class="example-header" @click="toggleExample('exp1')">
<div class="example-title">例题1:基础题</div>
<div class="toggle-btn" :class="{open: openExample === 'exp1'}">▶</div>
</div>
<div class="example-body" :class="{show: openExample === 'exp1'}">
<div class="example-q"><strong>题目:</strong>马路一边有6根路灯,路灯之间有几个间隔?</div>
<div class="example-a"><strong>答案:</strong>5个</div>
<div class="example-exp">
<strong>解析:</strong><br>
第1步:画个图:○○○○○○(6根路灯)<br>
第2步:数间隔:○_○_○_○_○_○(5个间隔)<br>
第3步:公式:间隔数=物体数-1=6-1=5个
</div>
</div>
</div>
</div>
<div class="explain-section" :class="{active: explainTab === 'theory'}">
<div class="concept-box">
<strong>“两端都种”植树问题</strong><br>
总长度 ÷ 间隔距离 = 间隔数<br>
树的棵数 = 间隔数 + 1
</div>
<div class="example-card">
<div class="example-header" @click="toggleExample('exp2')">
<div class="example-title">例题2:进阶题</div>
<div class="toggle-btn" :class="{open: openExample === 'exp2'}">▶</div>
</div>
<div class="example-body" :class="{show: openExample === 'exp2'}">
<div class="example-q"><strong>题目:</strong>在20米长的路一边种树,每隔5米种一棵(两端都种),要种几棵?</div>
<div class="example-a"><strong>答案:</strong>5棵</div>
<div class="example-exp">
<strong>解析:</strong><br>
第1步:总长20米,每隔5米一棵<br>
第2步:间隔数:20÷5=4个间隔<br>
第3步:两端都种:树的棵数=间隔数+1=4+1=5棵
</div>
</div>
</div>
</div>
<div class="explain-section" :class="{active: explainTab === 'example'}">
<div class="concept-box">
<strong>易错点提示:</strong><br>
一定要看清题目是“两端都种”还是“两端都不种”!公式不一样。
</div>
<div class="example-card">
<div class="example-header" @click="toggleExample('exp3')">
<div class="example-title">例题3:易错题</div>
<div class="toggle-btn" :class="{open: openExample === 'exp3'}">▶</div>
</div>
<div class="example-body" :class="{show: openExample === 'exp3'}">
<div class="example-q"><strong>题目:</strong>在20米长的路一边种树,每隔5米种一棵(两端都不种),要种几棵?</div>
<div class="example-a"><strong>答案:</strong>3棵</div>
<div class="example-exp">
<strong>解析:</strong><br>
【易错点】:有的小朋友会像上一题一样算成5棵<br>
【正确做法】:<br>
第1步:总长20米,每隔5米一棵<br>
第2步:间隔数:20÷5=4个间隔<br>
第3步:两端都不种:树的棵数=间隔数-1=4-1=3棵<br>
第4步:验证:○树_5米_树_5米_树_5米_树○,确实是3棵
</div>
</div>
</div>
</div>
</div>
</div>
<div v-show="currentPage === 4" class="practice-page fade-in">
<div v-if="!practiceCompleted">
<div class="question-card">
<div class="question-header">
<span class="question-number">📝 练习 {{currentQuestion + 1}}/{{practiceQuestions.length}}</span>
<span class="score-display">⭐ {{score}}</span>
</div>
<div class="question-text">{{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,
'shake': answered && selectedOption === index && !option.correct
}"
@click="selectOption(index, option.correct)"
:disabled="answered"
>
{{['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 fade-in">
<div class="completion-emoji">🎉</div>
<div class="completion-title">练习完成!</div>
<div class="final-score">+{{score}}</div>
<button class="restart-btn" @click="switchPage(5)">🚀 挑战奥数题</button>
</div>
</div>
<div v-show="currentPage === 5" class="practice-page fade-in">
<div v-if="!olympiadCompleted">
<div class="question-card" style="border-top: 5px solid #ff9f43;">
<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>
<span class="score-display">⭐ {{olympiadScore}}</span>
</div>
<div class="question-text">{{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': olympiadAnswered && selectedOlympiadOption === index && !option.correct,
'shake': olympiadAnswered && selectedOlympiadOption === index && !option.correct
}"
@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">
<strong>💡 提示:</strong>
{{ wrongAttempts === 1 ? olympiadQuestions[currentOlympiad].hint1 : (wrongAttempts === 2 ? olympiadQuestions[currentOlympiad].hint2 : olympiadQuestions[currentOlympiad].hint3) }}
</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 fade-in">
<div class="completion-emoji">🏆</div>
<div class="completion-title">通关奥数挑战!</div>
<div class="final-score">+{{olympiadScore}}</div>
<button class="restart-btn" @click="switchPage(6)">🎁 查看通关秘籍</button>
</div>
</div>
<div v-show="currentPage === 6" class="secrets-container fade-in">
<div class="page-subtitle">🗝️ 通关秘籍</div>
<div class="secrets-scroll">
<div class="secret-card">
<div class="secret-icon">📝</div>
<div class="secret-title">秘籍1:间隔公式</div>
<div class="secret-content">
两端都有:棵数 = 间隔数 + 1<br><br>
两端都没有:棵数 = 间隔数 - 1
</div>
</div>
<div class="secret-card">
<div class="secret-icon">🌀</div>
<div class="secret-title">秘籍2:环形特殊</div>
<div class="secret-content">
围成圈时,物体数 = 间隔数<br><br>
(没有端点,首尾相连)
</div>
</div>
<div class="secret-card">
<div class="secret-icon">🎨</div>
<div class="secret-title">秘籍3:画图理解</div>
<div class="secret-content">
遇到复杂问题,<br>
画个简单的图,<br>
马上就懂了!
</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 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>
<script src="https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/assets/js/confetti.browser.min.js"></script>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
currentPage: 1,
demoTab: 'direct',
explainTab: 'direct',
openExample: '',
directStep: 0,
theoryStep: 0,
// 练习题
currentQuestion: 0,
answered: false,
selectedOption: null,
isCorrect: false,
score: 0,
practiceCompleted: false,
practiceQuestions: [
{ text: '5根柱子,柱子之间有几个间隔?', options: [{text: '3个', correct: false}, {text: '4个', correct: true}, {text: '5个', correct: false}, {text: '6个', correct: false}], explanation: '间隔数=5-1=4个' },
{ text: '把一根木头锯成4段,要锯几次?', options: [{text: '2次', correct: false}, {text: '3次', correct: true}, {text: '4次', correct: false}, {text: '5次', correct: false}], explanation: '3个切口,锯3次' },
{ text: '从1楼到5楼,要爬几层楼梯?', options: [{text: '3层', correct: false}, {text: '4层', correct: true}, {text: '5层', correct: false}, {text: '6层', correct: false}], explanation: '5-1=4层楼梯' },
{ text: '路边每隔10米有一棵树,从第1棵到第5棵有多远?', options: [{text: '30米', correct: false}, {text: '40米', correct: true}, {text: '50米', correct: false}, {text: '60米', correct: false}], explanation: '5-1=4个间隔,4×10=40米' },
{ text: '10米的绳子,每2米剪一刀,剪成若干段,要剪几刀?', options: [{text: '3刀', correct: false}, {text: '4刀', correct: true}, {text: '5刀', correct: false}, {text: '6刀', correct: false}], explanation: '10÷2=5段,5段需要4刀' },
{ text: '在一条直路上,每隔3米插一面旗,插了6面旗,路长多少米?', options: [{text: '12米', correct: false}, {text: '15米', correct: true}, {text: '18米', correct: false}, {text: '21米', correct: false}], explanation: '6-1=5个间隔,5×3=15米' },
{ text: '排队照相,5个人站成一排,相邻两人间隔1米,队伍长几米?', options: [{text: '3米', correct: false}, {text: '4米', correct: true}, {text: '5米', correct: false}, {text: '6米', correct: false}], explanation: '5-1=4个间隔,4×1=4米' },
{ text: '小明家到学校有200米,每隔50米有一棵树(两端都有),一共几棵树?', options: [{text: '3棵', correct: false}, {text: '4棵', correct: false}, {text: '5棵', correct: true}, {text: '6棵', correct: false}], explanation: '200÷50=4个间隔,两端都有:4+1=5棵' }
],
// 奥数题
currentOlympiad: 0,
olympiadAnswered: false,
selectedOlympiadOption: null,
isOlympiadCorrect: false,
wrongAttempts: 0,
olympiadScore: 0,
olympiadCompleted: false,
olympiadQuestions: [
{ text: '在正方形花坛的四条边上,每边种5棵树(四个角都种),一共种几棵树?', options: [{text: '16棵', correct: true}, {text: '20棵', correct: false}, {text: '18棵', correct: false}, {text: '24棵', correct: false}], hint1: '每边5棵,四边共20棵', hint2: '四个角被重复数了', hint3: '20-4=16棵', explanation: '每边5棵,四条边:5×4=20棵。但是!四个角的树被数了两次。实际:20-4=16棵', difficulty: 3, difficultyText: '⭐⭐⭐' },
{ text: '一条环形跑道,每隔10米插一面旗,共插了30面旗。跑道周长多少米?', options: [{text: '290米', correct: false}, {text: '300米', correct: true}, {text: '310米', correct: false}, {text: '320米', correct: false}], hint1: '环形问题,旗子数=间隔数', hint2: '30个间隔', hint3: '30×10=300米', explanation: '环形跑道:旗子数=间隔数(因为是围成圈的)。30面旗=30个间隔。周长:30×10=300米', difficulty: 2, difficultyText: '⭐⭐' },
{ text: '小朋友围成一圈做游戏,每两个小朋友之间相隔2米,一共12个小朋友。圆圈周长多少米?', options: [{text: '20米', correct: false}, {text: '22米', correct: false}, {text: '24米', correct: true}, {text: '26米', correct: false}], hint1: '围成圈,人数等于间隔数', hint2: '12个间隔', hint3: '12×2=24米', explanation: '围成圈:人数=间隔数。12个人=12个间隔。周长:12×2=24米', difficulty: 2, difficultyText: '⭐⭐' },
{ text: '钟楼的钟敲6下用了5秒,敲12下要用多少秒?', options: [{text: '10秒', correct: false}, {text: '11秒', correct: true}, {text: '12秒', correct: false}, {text: '13秒', correct: false}], hint1: '敲6下有几个间隔?', hint2: '5个间隔,每个1秒', hint3: '敲12下有11个间隔,11秒', explanation: '敲6下有5个间隔(6-1=5)。5秒敲5个间隔,每个间隔:5÷5=1秒。敲12下有11个间隔(12-1=11)。总时间:11×1=11秒', difficulty: 3, difficultyText: '⭐⭐⭐' },
{ text: '一根20厘米的绳子,每隔4厘米打一个结(两端不打),要打几个结?', options: [{text: '3个', correct: false}, {text: '4个', correct: true}, {text: '5个', correct: false}, {text: '6个', correct: false}], hint1: '能分成几段?', hint2: '20÷4=5段,有5个间隔', hint3: '两端不打,4个结', explanation: '20÷4=5个间隔。两端不打:结数=间隔数-1=5-1=4个', difficulty: 2, difficultyText: '⭐⭐' },
{ text: '马路两边种树,一边种10棵,两边一共种多少棵?如果每隔5米一棵,一边的路长多少米?', options: [{text: '20棵,45米', correct: true}, {text: '19棵,45米', correct: false}, {text: '20棵,50米', correct: false}, {text: '20棵,40米', correct: false}], hint1: '两边各10棵', hint2: '一边有9个间隔', hint3: '20棵,路长45米', explanation: '两边:10×2=20棵。一边10棵,间隔数:10-1=9个。路长:9×5=45米', difficulty: 2, difficultyText: '⭐⭐' },
{ text: '锯木头,每锯一次需要3分钟。把一根木头锯成8段,总共要多少分钟?', options: [{text: '18分钟', correct: false}, {text: '21分钟', correct: true}, {text: '24分钟', correct: false}, {text: '27分钟', correct: false}], hint1: '锯成8段要锯几次?', hint2: '8-1=7次', hint3: '7×3=21分钟', explanation: '锯成8段需要:8-1=7次。每次3分钟,总时间:7×3=21分钟', difficulty: 1, difficultyText: '⭐' },
{ text: '在100米的跑道两边,每隔10米插一面旗(两端都插),两边一共插多少面旗?', options: [{text: '18面', correct: false}, {text: '20面', correct: false}, {text: '22面', correct: true}, {text: '24面', correct: false}], hint1: '一边有多少个间隔?', hint2: '100÷10=10个,两端都插是11面', hint3: '两边:11×2=22面', explanation: '一边:100÷10=10个间隔。两端都插:10+1=11面旗。两边:11×2=22面旗', difficulty: 2, difficultyText: '⭐⭐' }
]
};
},
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();
});
}
if (page === 4 && this.practiceCompleted) {
this.practiceCompleted = false; this.currentQuestion = 0; this.score = 0;
}
if (page === 5 && this.olympiadCompleted) {
this.olympiadCompleted = false; this.currentOlympiad = 0; this.olympiadScore = 0;
}
},
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.demoTab = tab;
if(tab === 'direct') { this.directStep = 0; this.$nextTick(() => this.runDirectAnimation()); }
// theory tab is static text
},
toggleExample(ex) {
this.openExample = this.openExample === ex ? '' : ex;
},
// 动画逻辑:植树问题
runDirectAnimation() {
if (typeof gsap === 'undefined') return;
const tl = gsap.timeline();
// Reset
gsap.set("#trees > *", { opacity: 0 });
gsap.set("#intervals > *", { opacity: 0 });
gsap.set("#title-text, #formula-text", { opacity: 0 });
// Draw items dynamically if not already (simplified for logic)
// In HTML template, trees and intervals are built dynamically in JS below
// Clear previous
const treesGroup = document.getElementById('trees');
const intervalsGroup = document.getElementById('intervals');
if(treesGroup) treesGroup.innerHTML = '';
if(intervalsGroup) intervalsGroup.innerHTML = '';
// Create Trees
const treePositions = [80, 140, 200, 260, 320];
treePositions.forEach((x, i) => {
// Trunk
const trunk = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
trunk.setAttribute('x', x-3); trunk.setAttribute('y', 160);
trunk.setAttribute('width', 6); trunk.setAttribute('height', 30);
trunk.setAttribute('fill', '#8B4513'); trunk.setAttribute('opacity', 0);
treesGroup.appendChild(trunk);
// Crown
const crown = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
crown.setAttribute('cx', x); crown.setAttribute('cy', 145);
crown.setAttribute('r', 15); crown.setAttribute('fill', '#228B22');
crown.setAttribute('opacity', 0);
treesGroup.appendChild(crown);
});
// Create Intervals
const intervalPositions = [95, 155, 215, 275];
intervalPositions.forEach((x, i) => {
const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
g.setAttribute('opacity', 0);
// Line
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', x); line.setAttribute('y1', 200);
line.setAttribute('x2', x+30); line.setAttribute('y2', 200);
line.setAttribute('stroke', '#667eea'); line.setAttribute('stroke-width', 2);
line.setAttribute('stroke-dasharray', '5,5');
// Text
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
text.setAttribute('x', x+15); text.setAttribute('y', 195);
text.setAttribute('text-anchor', 'middle'); text.setAttribute('fill', '#333');
text.setAttribute('font-size', 12); text.textContent = '5米';
g.appendChild(line); g.appendChild(text);
intervalsGroup.appendChild(g);
});
// Step 0: Only background (already static)
if (this.directStep >= 1) {
// Show trees
const trees = treesGroup.children;
for(let i=0; i<trees.length; i+=2) { // trunk and crown pairs
tl.to(trees[i], {opacity: 1, duration: 0.3, y: 10, ease: "bounce.out"}, i*0.1);
tl.to(trees[i+1], {opacity: 1, duration: 0.3}, "<");
}
}
if (this.directStep >= 2) {
// Show intervals
const intervals = intervalsGroup.children;
tl.to(intervals, {opacity: 1, duration: 0.5, stagger: 0.2});
tl.to("#title-text", {opacity: 1, duration: 0.5}, "+=0.2");
}
if (this.directStep >= 3) {
// Show formula
tl.to("#formula-text", {opacity: 1, duration: 0.5, scale: 1.1, ease: "elastic.out"});
}
},
nextDirectStep() { if(this.directStep < 3) { this.directStep++; this.runDirectAnimation(); } },
prevDirectStep() { if(this.directStep > 0) { this.directStep--; this.runDirectAnimation(); } },
// 练习题逻辑
selectOption(index, correct) {
if (this.answered) return;
this.answered = true;
this.selectedOption = index;
this.isCorrect = correct;
if (correct) {
this.score += 20;
confetti({ particleCount: 60, spread: 60, origin: { y: 0.7 } });
}
},
nextQuestion() {
if (this.currentQuestion < this.practiceQuestions.length - 1) {
this.currentQuestion++;
this.answered = false;
this.selectedOption = null;
} else {
this.practiceCompleted = true;
}
},
// 奥数题逻辑
selectOlympiadOption(index, correct) {
if (this.olympiadAnswered) return;
if (correct) {
this.olympiadAnswered = true;
this.selectedOlympiadOption = index;
this.isOlympiadCorrect = true;
this.olympiadScore += 25;
this.wrongAttempts = 0;
confetti({ particleCount: 150, spread: 100, origin: { y: 0.6 } });
} else {
this.wrongAttempts++;
if (this.wrongAttempts >= 3) {
this.olympiadAnswered = true;
this.selectedOlympiadOption = index;
this.isOlympiadCorrect = false;
}
}
},
nextOlympiad() {
if (this.currentOlympiad < this.olympiadQuestions.length - 1) {
this.currentOlympiad++;
this.olympiadAnswered = false;
this.selectedOlympiadOption = null;
this.wrongAttempts = 0;
} else {
this.olympiadCompleted = true;
}
}
}
}).mount('#app');
</script>
</body>
</html>
💡 这段代码完全由 AI 生成。
登录后可复制完整代码