<!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>第04讲: 植树问题(直线、封闭图形)</title>
<style>
/* 基础重置 */
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
body { margin: 0; padding: 0; font-family: 'Arial Rounded MT Bold', 'Arial', sans-serif; background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%); overflow: hidden; height: 100vh; }
/* 隐藏滚动条 */
::-webkit-scrollbar { display: none; width: 0 !important; height: 0 !important; }
* { -ms-overflow-style: none; scrollbar-width: none; }
/* 主容器 */
#app { height: 100vh; max-width: 480px; margin: 0 auto; background: #fff; display: flex; flex-direction: column; position: relative; }
.content-area { flex: 1; overflow-y: auto; padding-bottom: 80px; scroll-behavior: smooth; background: #f9f9f9; }
/* 底部导航 - 关键! */
.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: 9999;
box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.05);
}
.nav-item { flex: 1; display: flex; flex-direction: column; align-items: center; cursor: pointer; padding: 8px 0; transition: all 0.3s ease; color: #888; }
.nav-item.active { color: #667eea; transform: translateY(-2px); }
.nav-icon { font-size: 22px; margin-bottom: 4px; }
.nav-label { font-size: 12px; font-weight: bold; }
/* Tab 导航 */
.tab-nav { display: flex; border-bottom: 2px solid #e0e0e0; background: white; margin-bottom: 0; }
.tab-item { flex: 1; padding: 15px 0; text-align: center; cursor: pointer; border-bottom: 4px solid transparent; font-weight: bold; color: #666; transition: all 0.3s; }
.tab-item.active { color: #667eea; border-bottom-color: #667eea; }
/* 页面通用样式 */
.page-container { padding: 20px; }
/* 页面1: 概念引入 */
.intro-page { text-align: center; padding: 40px 20px; background: linear-gradient(135deg, #d4fc79 0%, #96e6a1 100%); border-radius: 0 0 30px 30px; margin-bottom: 20px; }
.intro-emoji { font-size: 70px; margin-bottom: 20px; }
.intro-title { font-size: 26px; font-weight: bold; color: #2d3436; margin-bottom: 25px; }
.intro-story { background: rgba(255, 255, 255, 0.85); padding: 20px; border-radius: 20px; font-size: 17px; line-height: 1.6; color: #333; margin-bottom: 25px; text-align: left; box-shadow: 0 8px 20px rgba(0,0,0,0.1); }
.intro-reason { background: rgba(255, 255, 255, 0.85); padding: 18px; border-radius: 18px; font-size: 16px; line-height: 1.6; color: #555; margin-bottom: 30px; text-align: left; box-shadow: 0 6px 15px rgba(0,0,0,0.08); }
.speak-btn { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; padding: 16px 40px; border-radius: 30px; font-size: 18px; font-weight: bold; cursor: pointer; box-shadow: 0 10px 25px rgba(102, 126, 234, 0.4); transition: transform 0.2s; }
.speak-btn:active { transform: scale(0.97); }
/* 页面2: 演示动画 */
.demo-page { background: #f9f9f9; min-height: calc(100vh - 70px); }
.demo-section { display: none; padding: 20px; }
.demo-section.active { display: block; }
/* 动画区域 */
.animation-area {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-radius: 20px; padding: 15px; height: 360px; position: relative; overflow: hidden; margin-bottom: 15px;
box-shadow: inset 0 0 15px rgba(0,0,0,0.05);
display: flex; align-items: center; justify-content: center;
}
.svg-container { width: 100%; height: 100%; }
.counter-display { position: absolute; top: 15px; left: 0; width: 100%; display: flex; justify-content: center; gap: 30px; z-index: 10; }
.counter-item { background: rgba(255, 255, 255, 0.9); padding: 8px 20px; border-radius: 50px; font-weight: bold; font-size: 18px; color: #333; box-shadow: 0 4px 10px rgba(0,0,0,0.1); min-width: 120px; text-align: center; }
.counter-value { color: #667eea; font-size: 24px; }
/* 公式和控制栏样式 */
.math-area { background: white; border: 3px solid #667eea; border-radius: 15px; padding: 15px; margin: 20px 0; min-height: 90px; display: flex; align-items: center; justify-content: center; box-shadow: 0 6px 12px rgba(102, 126, 234, 0.2); }
.math-formula { font-size: 22px; font-weight: bold; color: #333; text-align: center; }
.step-explanation { background: #f0f7ff; padding: 15px; border-radius: 12px; color: #444; font-size: 16px; line-height: 1.5; text-align: center; margin-bottom: 20px; border-left: 5px solid #667eea; }
/* 悬浮控制按钮 */
.float-control-bar { position: absolute; top: 50%; transform: translateY(-50%); width: 100%; display: flex; justify-content: space-between; padding: 0 10px; z-index: 100; pointer-events: none; }
.float-control-bar button { pointer-events: all; }
.step-btn-circle {
background: rgba(102, 126, 234, 0.85);
color: white;
border: none;
width: 50px;
height: 50px;
border-radius: 50%;
font-size: 20px;
cursor: pointer;
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
}
.step-btn-circle:disabled { background: #ccc; cursor: not-allowed; opacity: 0.6; }
.step-btn-circle:active:not(:disabled) { transform: scale(0.9); }
/* 页面3: 讲解页 */
.explain-page { background: #f9f9f9; }
.explain-content { padding: 20px; }
.explain-card {
background: white;
border-radius: 18px;
padding: 0;
margin-bottom: 20px;
box-shadow: 0 8px 20px rgba(0,0,0,0.08);
overflow: hidden;
border: 1px solid #eee;
}
.card-header {
padding: 18px 20px;
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
font-weight: bold;
font-size: 18px;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
}
.card-header.collapsed { background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%); color: #333; }
.toggle-icon { font-size: 20px; transition: transform 0.3s; }
.card-header.active .toggle-icon { transform: rotate(180deg); }
.card-content {
padding: 0;
max-height: 0;
overflow: hidden;
transition: max-height 0.5s ease, padding 0.5s ease;
}
.card-content.active {
padding: 25px;
max-height: 1000px;
}
.example-question { font-size: 17px; font-weight: bold; color: #2d3436; margin-bottom: 15px; line-height: 1.5; }
.example-answer { background: #e8f5e9; padding: 12px 18px; border-radius: 12px; color: #1b5e20; font-size: 16px; margin-top: 15px; border-left: 4px solid #4caf50; }
.example-explanation { background: #fff3e0; padding: 12px 18px; border-radius: 12px; color: #e65100; font-size: 16px; margin-top: 15px; border-left: 4px solid #ff9800; }
/* 页面4 & 5: 练习/奥数页 */
.practice-page { background: #f9f9f9; min-height: calc(100vh - 70px); }
.question-card {
background: white;
margin: 20px;
border-radius: 25px;
padding: 25px;
box-shadow: 0 12px 30px rgba(0,0,0,0.1);
}
.question-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 25px;
padding-bottom: 15px;
border-bottom: 2px dashed #e0e0e0;
}
.question-number { font-size: 16px; color: #666; font-weight: bold; }
.score-display { font-size: 18px; color: #ff9800; font-weight: bold; }
.question-text {
font-size: 19px;
line-height: 1.6;
color: #2d3436;
margin-bottom: 30px;
font-weight: bold;
}
.options-container { display: grid; grid-template-columns: 1fr; gap: 12px; margin-bottom: 25px; }
.option-btn {
background: #f5f5f5;
border: 2px solid transparent;
border-radius: 15px;
padding: 18px 20px;
font-size: 17px;
text-align: left;
cursor: pointer;
transition: all 0.3s;
font-weight: bold;
color: #444;
}
.option-btn:active:not(:disabled) { transform: scale(0.98); }
.option-btn.correct { background: #d4edda; border-color: #28a745; color: #155724; animation: pulseCorrect 0.6s ease; }
.option-btn.wrong { background: #f8d7da; border-color: #dc3545; color: #721c24; animation: shakeWrong 0.5s ease; }
.option-btn:disabled { cursor: not-allowed; opacity: 0.8; }
@keyframes shakeWrong {
0%, 100% { transform: translateX(0); }
20%, 60% { transform: translateX(-8px); }
40%, 80% { transform: translateX(8px); }
}
@keyframes pulseCorrect {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.feedback-area {
padding: 20px;
border-radius: 15px;
margin-top: 20px;
font-size: 16px;
line-height: 1.6;
}
.feedback-correct { background: #d4edda; color: #155724; border-left: 5px solid #28a745; }
.feedback-wrong { background: #fff3cd; color: #856404; border-left: 5px solid #ffc107; }
.next-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
width: 100%;
padding: 18px;
border-radius: 15px;
font-size: 18px;
font-weight: bold;
cursor: pointer;
margin-top: 25px;
transition: transform 0.2s;
}
.next-btn:active { transform: scale(0.97); }
/* 奥数页特有样式 */
.difficulty-badge {
display: inline-block;
margin-left: 15px;
padding: 4px 12px;
border-radius: 20px;
font-size: 14px;
font-weight: bold;
color: white;
}
.difficulty-1 { background: #4caf50; }
.difficulty-2 { background: #ff9800; }
.difficulty-3 { background: #f44336; }
.hint-box {
background: #e3f2fd;
border-left: 5px solid #2196f3;
padding: 15px;
border-radius: 10px;
margin: 15px 0;
color: #0d47a1;
font-size: 16px;
}
/* 完成页面 */
.completion-page {
text-align: center;
padding: 60px 30px;
}
.completion-emoji { font-size: 80px; margin-bottom: 20px; }
.completion-title { font-size: 28px; font-weight: bold; color: #2d3436; margin-bottom: 15px; }
.final-score { font-size: 46px; color: #ff6b6b; font-weight: bold; margin: 25px 0; }
.restart-btn {
background: linear-gradient(135deg, #ff9a9e 0%, #fad0c4 100%);
color: #333;
border: none;
padding: 20px 50px;
border-radius: 30px;
font-size: 20px;
font-weight: bold;
cursor: pointer;
margin-top: 20px;
box-shadow: 0 10px 25px rgba(255, 154, 158, 0.4);
transition: transform 0.2s;
}
.restart-btn:active { transform: scale(0.97); }
/* 页面6: 通关秘籍 */
.secrets-container {
padding: 20px;
overflow-x: hidden;
overflow-y: auto;
height: calc(100vh - 140px);
}
.secret-card {
width: 100%;
min-height: 300px;
background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
border-radius: 30px;
padding: 35px 30px;
margin-bottom: 25px;
box-shadow: 0 15px 35px rgba(0,0,0,0.15);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
border: 8px solid white;
}
.secret-card:nth-child(2) { background: linear-gradient(135deg, #fad0c4 0%, #ffd1ff 100%); }
.secret-card:nth-child(3) { background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%); }
.secret-icon { font-size: 70px; margin-bottom: 25px; }
.secret-title { font-size: 26px; font-weight: bold; color: #2d3436; margin-bottom: 20px; }
.secret-content { font-size: 20px; line-height: 1.6; color: #444; }
/* 点阵背景 (概念页) */
.dot-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: radial-gradient(#cceeff 2px, transparent 2px);
background-size: 30px 30px;
opacity: 0.3;
z-index: 0;
}
.intro-content { position: relative; z-index: 1; }
</style>
</head>
<body>
<div id="app">
<div class="content-area">
<!-- 页面1: 概念引入 -->
<div v-show="currentPage === 1" class="intro-page">
<div class="dot-bg"></div>
<div class="intro-content">
<div class="intro-emoji">🌳</div>
<div class="intro-title">植树问题</div>
<div class="intro-story">
植树节到了,老师带同学们去路边种树。小路长20米,要求每隔5米种一棵树,头和尾都要种。小明发愁了:到底需要准备多少棵树苗呢?这就要用到我们今天学习的“植树问题”啦!
</div>
<div class="intro-reason">
<strong>为什么要学习植树问题?</strong><br>
学会它,我们不仅能解决种树的问题,还能计算爬楼梯的时间、锯木头的次数、排队的人数,甚至是时钟敲响的间隔!它让我们的数学思维更严密。
</div>
<button class="speak-btn" @click="speak('植树节到了,老师带同学们去路边种树。小路长20米,要求每隔5米种一棵树,头和尾都要种。小明发愁了:到底需要准备多少棵树苗呢?')">听老师讲解 👂</button>
</div>
</div>
<!-- 页面2: 演示动画 -->
<div v-show="currentPage === 2" class="demo-page">
<div class="tab-nav">
<div class="tab-item" :class="{active: demoTab === 'line'}" @click="switchDemoTab('line')">直线植树</div>
<div class="tab-item" :class="{active: demoTab === 'circle'}" @click="switchDemoTab('circle')">封闭图形</div>
</div>
<!-- 直线植树 Tab -->
<div class="demo-section" :class="{active: demoTab === 'line'}">
<div class="animation-area">
<div class="counter-display">
<div class="counter-item">胡萝卜: <span class="counter-value" id="carrot-count">1</span></div>
<div class="counter-item">间隔: <span class="counter-value" id="gap-count">0</span></div>
</div>
<svg class="svg-container" viewBox="0 0 400 330" id="line-svg">
<!-- 路径 -->
<path id="straight-path" d="M50,250 L350,250" stroke="#aaa" stroke-width="4" stroke-dasharray="5,5" fill="none"/>
<!-- 胡萝卜 (初始状态隐藏) -->
<g id="carrot-0" opacity="0">
<circle cx="50" cy="250" r="15" fill="#FF9800"/>
<path d="M50,235 L50,220" stroke="#4CAF50" stroke-width="3" stroke-linecap="round"/>
</g>
<g id="carrot-1" opacity="0">
<circle cx="150" cy="250" r="15" fill="#FF9800"/>
<path d="M150,235 L150,220" stroke="#4CAF50" stroke-width="3" stroke-linecap="round"/>
</g>
<g id="carrot-2" opacity="0">
<circle cx="250" cy="250" r="15" fill="#FF9800"/>
<path d="M250,235 L250,220" stroke="#4CAF50" stroke-width="3" stroke-linecap="round"/>
</g>
<g id="carrot-3" opacity="0">
<circle cx="350" cy="250" r="15" fill="#FF9800"/>
<path d="M350,235 L350,220" stroke="#4CAF50" stroke-width="3" stroke-linecap="round"/>
</g>
<!-- 小兔子 -->
<g id="rabbit">
<circle cx="50" cy="180" r="20" fill="#FFCCBC"/>
<ellipse cx="45" cy="175" rx="3" ry="5" fill="#333"/>
<ellipse cx="55" cy="175" rx="3" ry="5" fill="#333"/>
<path d="M40,190 Q50,210 60,190" stroke="#333" stroke-width="2" fill="none"/>
<ellipse cx="50" cy="195" rx="8" ry="4" fill="#FF8A80" />
</g>
<!-- 间隔标记 -->
<g id="gap-line-0" opacity="0">
<line x1="50" y1="230" x2="150" y2="230" stroke="#667eea" stroke-width="2"/>
<text x="100" y="225" text-anchor="middle" fill="#667eea" font-size="14" font-weight="bold">间隔1</text>
</g>
<g id="gap-line-1" opacity="0">
<line x1="150" y1="230" x2="250" y2="230" stroke="#667eea" stroke-width="2"/>
<text x="200" y="225" text-anchor="middle" fill="#667eea" font-size="14" font-weight="bold">间隔2</text>
</g>
<g id="gap-line-2" opacity="0">
<line x1="250" y1="230" x2="350" y2="230" stroke="#667eea" stroke-width="2"/>
<text x="300" y="225" text-anchor="middle" fill="#667eea" font-size="14" font-weight="bold">间隔3</text>
</g>
</svg>
<div class="float-control-bar">
<button class="step-btn-circle" @click="prevDirectStep" :disabled="directStep === 0">◀</button>
<button class="step-btn-circle" @click="nextDirectStep" :disabled="directStep === 3">▶</button>
</div>
</div>
<div class="math-area">
<div class="math-formula" id="line-formula">准备开始...</div>
</div>
<div class="step-explanation" id="line-explanation">点击"下一步"开始演示直线植树的过程。</div>
</div>
<!-- 封闭图形 Tab -->
<div class="demo-section" :class="{active: demoTab === 'circle'}">
<div class="animation-area">
<div class="counter-display">
<div class="counter-item">胡萝卜: <span class="counter-value" id="circle-carrot-count">1</span></div>
<div class="counter-item">间隔: <span class="counter-value" id="circle-gap-count">0</span></div>
</div>
<svg class="svg-container" viewBox="0 0 400 330" id="circle-svg">
<!-- 圆形路径 -->
<circle id="circle-path" cx="200" cy="165" r="100" stroke="#aaa" stroke-width="4" stroke-dasharray="5,5" fill="none"/>
<!-- 胡萝卜 (初始状态隐藏) -->
<g id="circle-carrot-0" opacity="0">
<circle cx="300" cy="165" r="15" fill="#FF9800"/>
<path d="M300,150 L300,135" stroke="#4CAF50" stroke-width="3" stroke-linecap="round"/>
</g>
<g id="circle-carrot-1" opacity="0">
<circle cx="200" cy="265" r="15" fill="#FF9800"/>
<path d="M200,250 L200,235" stroke="#4CAF50" stroke-width="3" stroke-linecap="round"/>
</g>
<g id="circle-carrot-2" opacity="0">
<circle cx="100" cy="165" r="15" fill="#FF9800"/>
<path d="M100,150 L100,135" stroke="#4CAF50" stroke-width="3" stroke-linecap="round"/>
</g>
<g id="circle-carrot-3" opacity="0">
<circle cx="200" cy="65" r="15" fill="#FF9800"/>
<path d="M200,50 L200,35" stroke="#4CAF50" stroke-width="3" stroke-linecap="round"/>
</g>
<!-- 小兔子 (初始在起点) -->
<g id="circle-rabbit">
<circle cx="300" cy="165" r="20" fill="#FFCCBC"/>
<ellipse cx="295" cy="160" rx="3" ry="5" fill="#333"/>
<ellipse cx="305" cy="160" rx="3" ry="5" fill="#333"/>
<path d="M290,175 Q300,195 310,175" stroke="#333" stroke-width="2" fill="none"/>
<ellipse cx="300" cy="180" rx="8" ry="4" fill="#FF8A80" />
</g>
<!-- 间隔标记 -->
<g id="circle-gap-0" opacity="0">
<path d="M300,165 A100,100 0 0,1 200,265" stroke="#667eea" stroke-width="2" fill="none"/>
<text x="250" y="215" text-anchor="middle" fill="#667eea" font-size="14" font-weight="bold">间隔1</text>
</g>
<g id="circle-gap-1" opacity="0">
<path d="M200,265 A100,100 0 0,1 100,165" stroke="#667eea" stroke-width="2" fill="none"/>
<text x="150" y="215" text-anchor="middle" fill="#667eea" font-size="14" font-weight="bold">间隔2</text>
</g>
<g id="circle-gap-2" opacity="0">
<path d="M100,165 A100,100 0 0,1 200,65" stroke="#667eea" stroke-width="2" fill="none"/>
<text x="150" y="115" text-anchor="middle" fill="#667eea" font-size="14" font-weight="bold">间隔3</text>
</g>
<g id="circle-gap-3" opacity="0">
<path d="M200,65 A100,100 0 0,1 300,165" stroke="#667eea" stroke-width="2" fill="none"/>
<text x="250" y="115" text-anchor="middle" fill="#667eea" font-size="14" font-weight="bold">间隔4</text>
</g>
</svg>
<div class="float-control-bar">
<button class="step-btn-circle" @click="prevCircleStep" :disabled="circleStep === 0">◀</button>
<button class="step-btn-circle" @click="nextCircleStep" :disabled="circleStep === 4">▶</button>
</div>
</div>
<div class="math-area">
<div class="math-formula" id="circle-formula">准备开始...</div>
</div>
<div class="step-explanation" id="circle-explanation">点击"下一步"开始演示封闭图形植树的过程。</div>
</div>
</div>
<!-- 页面3: 讲解页 -->
<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-content">
<div v-if="explainTab === 'direct'">
<div class="explain-card">
<div class="card-header" :class="{'active': openedCard === 'rule1', 'collapsed': openedCard !== 'rule1'}" @click="toggleCard('rule1')">
判断1:直线植树,两端都种
<span class="toggle-icon">▼</span>
</div>
<div class="card-content" :class="{'active': openedCard === 'rule1'}">
<div class="example-question">如何判断?</div>
<div class="example-explanation">
题目中出现“马路两边”、“道路两侧”、“两端都栽”、“头和尾都要种”等描述时,就是“两端都种”的情况。<br><br>
<strong>公式:树的棵数 = 间隔数 + 1</strong>
</div>
</div>
</div>
<div class="explain-card">
<div class="card-header" :class="{'active': openedCard === 'rule2', 'collapsed': openedCard !== 'rule2'}" @click="toggleCard('rule2')">
判断2:直线植树,两端都不种
<span class="toggle-icon">▼</span>
</div>
<div class="card-content" :class="{'active': openedCard === 'rule2'}">
<div class="example-question">如何判断?</div>
<div class="example-explanation">
题目中出现“两端不放”、“两端不插”、“两头都不种”、“起点和终点没有”等描述时,就是“两端不种”的情况。锯木头、剪绳子问题也属于这一类。<br><br>
<strong>公式:树的棵数 = 间隔数 - 1</strong>
</div>
</div>
</div>
<div class="explain-card">
<div class="card-header" :class="{'active': openedCard === 'rule3', 'collapsed': openedCard !== 'rule3'}" @click="toggleCard('rule3')">
判断3:封闭图形植树
<span class="toggle-icon">▼</span>
</div>
<div class="card-content" :class="{'active': openedCard === 'rule3'}">
<div class="example-question">如何判断?</div>
<div class="example-explanation">
题目中出现“圆形”、“正方形”、“长方形”、“池塘周围”、“花坛四周”、“围成一圈”等描述时,就是封闭图形植树问题。<br><br>
<strong>公式:树的棵数 = 间隔数</strong>
</div>
</div>
</div>
</div>
<div v-if="explainTab === 'theory'">
<div class="explain-card">
<div class="card-header active" style="background:linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
核心原理:间隔与物体
</div>
<div class="card-content active">
<div class="example-question">为什么树和间隔数量不同?</div>
<div class="example-explanation">
<strong>间隔:</strong>两棵树中间的空隙叫做“间隔”。<br><br>
<strong>两端都种:</strong>路的头和尾都要种树,这时候树比间隔多 1。<br>
(想象一条路:树 | 空 | 树 | 空 | 树,3棵树,2个空)<br><br>
<strong>封闭图形:</strong>像圆圈、正方形这样首尾相连的图形,树的数量等于间隔的数量。<br>
(想象一个圆圈:树-空-树-空-树-空,起点和终点重合了)
</div>
</div>
</div>
<div class="explain-card">
<div class="card-header active" style="background:linear-gradient(135deg, #f093fb 0%, #f5576c 100%);">
手指法则
</div>
<div class="card-content active">
<div class="example-question">小朋友们,伸出你的一只手,张开 5 根手指。手指就像是“树”,手指之间的缝隙就是“间隔”。</div>
<div class="example-explanation">
数一数,5 根手指有几个缝隙?对,是 4 个!这就是最简单的植树问题:<strong>手指树 = 缝隙数 + 1</strong>。
</div>
</div>
</div>
</div>
<div v-if="explainTab === 'example'">
<div class="explain-card">
<div class="card-header" :class="{'active': openedExample === 'ex1', 'collapsed': openedExample !== 'ex1'}" @click="toggleExample('ex1')">
例题1:基础题
<span class="toggle-icon">▼</span>
</div>
<div class="card-content" :class="{'active': openedExample === 'ex1'}">
<div class="example-question">在一条长 10 米的路上种树,每隔 2 米种一棵,两端都种,一共要种几棵?</div>
<div class="example-answer"><strong>答案:</strong>6 棵</div>
<div class="example-explanation">先求间隔数:10 ÷ 2 = 5 个间隔。两端都种,树 = 间隔 + 1 = 6 棵。</div>
</div>
</div>
<div class="explain-card">
<div class="card-header" :class="{'active': openedExample === 'ex2', 'collapsed': openedExample !== 'ex2'}" @click="toggleExample('ex2')">
例题2:进阶题
<span class="toggle-icon">▼</span>
</div>
<div class="card-content" :class="{'active': openedExample === 'ex2'}">
<div class="example-question">在一个圆形池塘周围种树,池塘一圈长 20 米,每隔 4 米种一棵,一共种几棵?</div>
<div class="example-answer"><strong>答案:</strong>5 棵</div>
<div class="example-explanation">封闭图形,树的数量 = 间隔数量。20 ÷ 4 = 5 棵。</div>
</div>
</div>
<div class="explain-card">
<div class="card-header" :class="{'active': openedExample === 'ex3', 'collapsed': openedExample !== 'ex3'}" @click="toggleExample('ex3')">
例题3:易错题
<span class="toggle-icon">▼</span>
</div>
<div class="card-content" :class="{'active': openedExample === 'ex3'}">
<div class="example-question">把一根木头锯成 3 段,需要锯几次?</div>
<div class="example-answer"><strong>答案:</strong>2 次</div>
<div class="example-explanation">【易错点】段数不等于次数。锯木头问题其实就是“两端不种”的植树问题。次数 = 段数 - 1。3 - 1 = 2 次。</div>
</div>
</div>
</div>
</div>
</div>
<!-- 页面4: 课内练习 -->
<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"
>
{{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="restart-btn" @click="switchPage(5)">挑战奥数题 →</button>
</div>
</div>
<!-- 页面5: 奥数挑战 -->
<div v-show="currentPage === 5" class="practice-page">
<div v-if="!olympiadCompleted">
<div class="question-card">
<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': olympiadAnswered && selectedOlympiadOption === index && !option.correct
}"
@click="selectOlympiadOption(index, option.correct)"
:disabled="olympiadAnswered"
>
{{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="restart-btn" @click="switchPage(6)">查看通关秘籍 →</button>
</div>
</div>
<!-- 页面6: 通关秘籍 -->
<div v-show="currentPage === 6" class="secrets-container">
<div class="secret-card">
<div class="secret-icon">✋</div>
<div class="secret-title">秘籍1:手指法则</div>
<div class="secret-content">伸出手指数一数,手指是树缝是空,手指数=间隔数+1。</div>
</div>
<div class="secret-card">
<div class="secret-icon">✂️</div>
<div class="secret-title">秘籍2:剪刀法则</div>
<div class="secret-content">锯木头、爬楼梯,次数/层数总是比段数/楼层少 1。</div>
</div>
<div class="secret-card">
<div class="secret-icon">⭕</div>
<div class="secret-title">秘籍3:围圈法则</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 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: 'line',
explainTab: 'direct',
openedCard: 'rule1',
openedExample: 'ex1',
directStep: 0,
directSteps: [
'小兔子在起点种下第一棵胡萝卜,开始跳跃...',
'小兔子跳过一个间隔,种下第二棵胡萝卜。',
'小兔子再跳过一个间隔,种下第三棵胡萝卜。',
'小兔子跳到终点,种下第四棵胡萝卜。直线植树完成!'
],
circleStep: 0,
circleSteps: [
'小兔子在起点种下第一棵胡萝卜,开始绕圈...',
'小兔子跳过一个间隔,种下第二棵胡萝卜。',
'小兔子再跳过一个间隔,种下第三棵胡萝卜。',
'小兔子继续跳跃,种下第四棵胡萝卜。',
'小兔子回到起点,发现起点已有一棵胡萝卜!封闭图形植树完成!'
],
// 练习页数据
practiceQuestions: [
{
text: "一条路长 20 米,每 5 米种一棵树(两端都种),一共几棵?",
options: [
{text: "A. 4", correct: false},
{text: "B. 5", correct: true},
{text: "C. 6", correct: false},
{text: "D. 3", correct: false}
],
explanation: "先算间隔数:20 ÷ 5 = 4。两端都种,树 = 4 + 1 = 5。"
},
{
text: "在 10 米长的路上,每隔 2 米放一盆花(两端不放),放几盆?",
options: [
{text: "A. 4", correct: true},
{text: "B. 5", correct: false},
{text: "C. 6", correct: false},
{text: "D. 3", correct: false}
],
explanation: "间隔数是 5。两端不放,花比间隔少 1。5 - 1 = 4。"
},
{
text: "时钟 3 点钟敲 3 下,6 秒钟敲完。问 5 点钟敲 5 下,几秒敲完?",
options: [
{text: "A. 10", correct: false},
{text: "B. 12", correct: true},
{text: "C. 15", correct: false},
{text: "D. 9", correct: false}
],
explanation: "敲 3 下有 2 个间隔,6 ÷ 2 = 3 秒(每个间隔)。敲 5 下有 4 个间隔。4 × 3 = 12 秒。"
},
{
text: "把一根木头锯成 5 段,锯一次用 2 分钟,一共用几分钟?",
options: [
{text: "A. 10", correct: false},
{text: "B. 8", correct: true},
{text: "C. 6", correct: false},
{text: "D. 12", correct: false}
],
explanation: "锯成 5 段要锯 4 次。4 × 2 = 8。不要直接 5 × 2。"
},
{
text: "同学们排队,每两个同学之间相隔 1 米,队伍长 10 米。一共有几个同学?",
options: [
{text: "A. 10", correct: false},
{text: "B. 11", correct: true},
{text: "C. 9", correct: false},
{text: "D. 12", correct: false}
],
explanation: "间隔数是 10。排队就是两端都种。10 + 1 = 11。"
},
{
text: "正方形花坛四周种花,每边种 3 棵,四个角都要种,一共种几棵?",
options: [
{text: "A. 12", correct: false},
{text: "B. 8", correct: true},
{text: "C. 10", correct: false},
{text: "D. 9", correct: false}
],
explanation: "不要直接 3 × 4。角上的花被多算了一次。(3 - 1) × 4 = 8。"
},
{
text: "一段路一侧种了 10 棵树(两端都种),每两棵树之间隔 3 米,这段路多长?",
options: [
{text: "A. 30", correct: false},
{text: "B. 27", correct: true},
{text: "C. 33", correct: false},
{text: "D. 24", correct: false}
],
explanation: "10 棵树有 9 个间隔。每个间隔 3 米。9 × 3 = 27。"
},
{
text: "1 楼到 4 楼有 48 级台阶,每层台阶一样多,一层到二楼有几级?",
options: [
{text: "A. 12", correct: false},
{text: "B. 16", correct: true},
{text: "C. 24", correct: false},
{text: "D. 10", correct: false}
],
explanation: "1 楼到 4 楼要爬 3 层。48 ÷ 3 = 16。不要除以 4。"
}
],
currentQuestion: 0,
answered: false,
selectedOption: null,
isCorrect: false,
score: 0,
practiceCompleted: false,
// 奥数页数据
olympiadQuestions: [
{
text: "一条马路长 100 米,在马路一侧每隔 2 米种一棵杨树,在每两棵杨树之间种一棵柳树。一共种了多少棵树?(两端都种杨树)",
options: [
{text: "A. 51杨, 50柳", correct: false},
{text: "B. 50杨, 50柳", correct: false},
{text: "C. 101棵", correct: true},
{text: "D. 100棵", correct: false}
],
hint1: "先算杨树的数量。",
hint2: "再算柳树的数量(等于间隔数)。",
hint3: "加起来。",
explanation: "杨树:100÷2+1=51棵。间隔50个,每个间隔种1棵柳树,柳树50棵。总数51+50=101。",
difficulty: 2,
difficultyText: "⭐⭐"
},
{
text: "一个圆形花坛周长 40 米,每隔 4 米种一棵树,如果把两棵树之间的距离改成 5 米,有几棵树不用移动?",
options: [
{text: "A. 2", correct: true},
{text: "B. 3", correct: false},
{text: "C. 4", correct: false},
{text: "D. 5", correct: false}
],
hint1: "原来种树的位置是 0, 4, 8, 12...",
hint2: "现在种树的位置是 0, 5, 10, 15...",
hint3: "找 4 和 5 的公倍数:0, 20, 40(回到起点)。共3个位置(0, 20, 40即0)。实际上如果不算起点重合算1个,20米处算1个。0和40是同一点。所以是2棵(0和20)。等一下,起点算1棵,20米处算1棵。回到起点算0。所以是2棵。",
explanation: "修正:题目通常问几处。0, 20。共2处。答案选A。重新审题:0, 4, 8, 12, 16, 20, 24, 28, 32, 36。新:0, 5, 10, 15, 20, 25, 30, 35。重合点:0, 20。共2棵。答案选A。(原答案B修正为A)最终答案:A(2棵)",
difficulty: 3,
difficultyText: "⭐⭐⭐"
},
{
text: "在一条长 50 米的跑道两旁插彩旗,每隔 5 米插一面(两端都不插),一共需要多少面彩旗?",
options: [
{text: "A. 9", correct: false},
{text: "B. 18", correct: true},
{text: "C. 10", correct: false},
{text: "D. 20", correct: false}
],
hint1: "一旁间隔数 50÷5=10。",
hint2: "一旁旗子数 10-1=9。",
hint3: "两旁 9×2=18。",
explanation: "两旁!两端不插。",
difficulty: 2,
difficultyText: "⭐⭐"
},
{
text: "大钟 6 点敲 6 下,10 秒敲完。12 点敲 12 下,需要几秒?",
options: [
{text: "A. 20", correct: false},
{text: "B. 22", correct: true},
{text: "C. 24", correct: false},
{text: "D. 12", correct: false}
],
hint1: "6下有5个间隔,10÷5=2秒/间隔。",
hint2: "12下有11个间隔。",
hint3: "11×2=22秒。",
explanation: "求间隔时间。",
difficulty: 2,
difficultyText: "⭐⭐"
},
{
text: "一根木料,锯成 3 段要付费 6 元,锯成 6 段要付费多少元?",
options: [
{text: "A. 12", correct: false},
{text: "B. 15", correct: true},
{text: "C. 18", correct: false},
{text: "D. 10", correct: false}
],
hint1: "锯3段=锯2次,6元÷2=3元/次。",
hint2: "锯6段=锯5次。",
hint3: "5×3=15元。",
explanation: "按锯的次数付费。",
difficulty: 1,
difficultyText: "⭐"
},
{
text: "电梯从 1 楼到 3 楼用了 6 秒,照这样计算,从 1 楼到 7 楼需要几秒?",
options: [
{text: "A. 12", correct: false},
{text: "B. 14", correct: false},
{text: "C. 18", correct: true},
{text: "D. 21", correct: false}
],
hint1: "1到3楼走了2层,6÷2=3秒/层。",
hint2: "1到7楼要走6层。",
hint3: "6×3=18秒。",
explanation: "爬楼梯模型。",
difficulty: 1,
difficultyText: "⭐"
},
{
text: "18 个小朋友排成一路纵队,每两个小朋友之间相距 1 米,这支队伍长多少米?",
options: [
{text: "A. 17", correct: true},
{text: "B. 18", correct: false},
{text: "C. 19", correct: false},
{text: "D. 20", correct: false}
],
hint1: "18人有17个间隔。",
hint2: "每个间隔1米。",
hint3: "17×1=17米。",
explanation: "间距数=人数-1。",
difficulty: 1,
difficultyText: "⭐"
},
{
text: "在一个正方形水池四周植树,四个角都种,每边种 10 棵,一共种多少棵?",
options: [
{text: "A. 40", correct: false},
{text: "B. 36", correct: true},
{text: "C. 38", correct: false},
{text: "D. 44", correct: false}
],
hint1: "(10-1)×4。",
hint2: "9×4=36。",
hint3: "或者 10×4-4=36。",
explanation: "封闭方阵。",
difficulty: 2,
difficultyText: "⭐⭐"
}
],
currentOlympiad: 0,
olympiadAnswered: false,
selectedOlympiadOption: null,
isOlympiadCorrect: false,
olympiadScore: 0,
olympiadCompleted: false,
wrongAttempts: 0
};
},
methods: {
switchPage(page) {
// 停止语音
this.stopSpeak();
this.currentPage = page;
if (page === 2) {
this.directStep = 0;
this.circleStep = 0;
this.runDirectAnimation();
}
// 重置练习/奥数状态
if (page !== 4) {
this.practiceCompleted = false;
this.currentQuestion = 0;
this.answered = false;
this.score = 0;
}
if (page !== 5) {
this.olympiadCompleted = false;
this.currentOlympiad = 0;
this.olympiadAnswered = false;
this.olympiadScore = 0;
this.wrongAttempts = 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) {
this.stopSpeak();
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;
if (tab === 'line') {
this.directStep = 0;
this.runDirectAnimation();
} else {
this.circleStep = 0;
this.runCircleAnimation();
}
},
switchExplainTab(tab) { this.explainTab = tab; },
toggleCard(cardId) { this.openedCard = this.openedCard === cardId ? null : cardId; },
toggleExample(exampleId) { this.openedExample = this.openedExample === exampleId ? null : exampleId; },
// GSAP 动画逻辑
runDirectAnimation() {
if (typeof gsap === 'undefined') return;
const tl = gsap.timeline();
const step = this.directStep;
// 重置所有元素(除了起点胡萝卜)
gsap.set(['#carrot-1', '#carrot-2', '#carrot-3', '#gap-line-0', '#gap-line-1', '#gap-line-2', '#rabbit'], { opacity: 0, x: 0, y: 0 });
gsap.set('#carrot-0', { opacity: 1 });
gsap.set('#rabbit', { x: 0, y: 0 });
document.getElementById('carrot-count').textContent = '1';
document.getElementById('gap-count').textContent = '0';
if (step >= 1) {
// 步骤1:兔子跳跃,种第二棵胡萝卜,显示间隔1
tl.to('#rabbit', { x: 100, duration: 0.8, ease: "power2.out" })
.to('#carrot-1', { opacity: 1, duration: 0.5, scale: 1.2, ease: "bounce.out" }, '-=0.3')
.to('#gap-line-0', { opacity: 1, duration: 0.5 }, '-=0.2');
document.getElementById('carrot-count').textContent = '2';
document.getElementById('gap-count').textContent = '1';
}
if (step >= 2) {
// 步骤2:继续跳跃,种第三棵胡萝卜,显示间隔2
tl.to('#rabbit', { x: 200, duration: 0.8, ease: "power2.out" })
.to('#carrot-2', { opacity: 1, duration: 0.5, scale: 1.2, ease: "bounce.out" }, '-=0.3')
.to('#gap-line-1', { opacity: 1, duration: 0.5 }, '-=0.2');
document.getElementById('carrot-count').textContent = '3';
document.getElementById('gap-count').textContent = '2';
}
if (step >= 3) {
// 步骤3:跳到终点,种第四棵胡萝卜,显示间隔3
tl.to('#rabbit', { x: 300, duration: 0.8, ease: "power2.out" })
.to('#carrot-3', { opacity: 1, duration: 0.5, scale: 1.2, ease: "bounce.out" }, '-=0.3')
.to('#gap-line-2', { opacity: 1, duration: 0.5 }, '-=0.2');
document.getElementById('carrot-count').textContent = '4';
document.getElementById('gap-count').textContent = '3';
}
// 更新公式和讲解文字
const formulas = ['准备开始...', '起点种了1棵胡萝卜。', '又种1棵,现在有2棵胡萝卜,1个间隔。', '再种1棵,有3棵胡萝卜,2个间隔。', '终点种下第4棵!总共有4棵胡萝卜,3个间隔。树(4) = 间隔(3) + 1!'];
document.getElementById('line-formula').textContent = formulas[step];
document.getElementById('line-explanation').textContent = this.directSteps[step] || '演示完成。';
},
runCircleAnimation() {
if (typeof gsap === 'undefined') return;
const tl = gsap.timeline();
const step = this.circleStep;
// 重置所有元素(除了起点胡萝卜)
gsap.set(['#circle-carrot-1', '#circle-carrot-2', '#circle-carrot-3', '#circle-gap-0', '#circle-gap-1', '#circle-gap-2', '#circle-gap-3', '#circle-rabbit'], { opacity: 0, rotate: 0 });
gsap.set('#circle-carrot-0', { opacity: 1 });
gsap.set('#circle-rabbit', { x: 0, y: 0 });
document.getElementById('circle-carrot-count').textContent = '1';
document.getElementById('circle-gap-count').textContent = '0';
gsap.set('#circle-path', { attr: { d: 'M300,165 A100,100 0 0,1 300,165' } }); // 重置为点
if (step >= 1) {
// 步骤1:兔子跳跃,种第二棵胡萝卜,显示间隔1
tl.to('#circle-rabbit', { rotate: -90, duration: 1, ease: "power2.out", transformOrigin: "200px 165px" })
.to('#circle-carrot-1', { opacity: 1, duration: 0.5, scale: 1.2, ease: "bounce.out" }, '-=0.3')
.to('#circle-gap-0', { opacity: 1, duration: 0.5 }, '-=0.2');
document.getElementById('circle-carrot-count').textContent = '2';
document.getElementById('circle-gap-count').textContent = '1';
}
if (step >= 2) {
// 步骤2:继续跳跃,种第三棵胡萝卜,显示间隔2
tl.to('#circle-rabbit', { rotate: -180, duration: 1, ease: "power2.out", transformOrigin: "200px 165px" })
.to('#circle-carrot-2', { opacity: 1, duration: 0.5, scale: 1.2, ease: "bounce.out" }, '-=0.3')
.to('#circle-gap-1', { opacity: 1, duration: 0.5 }, '-=0.2');
document.getElementById('circle-carrot-count').textContent = '3';
document.getElementById('circle-gap-count').textContent = '2';
}
if (step >= 3) {
// 步骤3:继续跳跃,种第四棵胡萝卜,显示间隔3
tl.to('#circle-rabbit', { rotate: -270, duration: 1, ease: "power2.out", transformOrigin: "200px 165px" })
.to('#circle-carrot-3', { opacity: 1, duration: 0.5, scale: 1.2, ease: "bounce.out" }, '-=0.3')
.to('#circle-gap-2', { opacity: 1, duration: 0.5 }, '-=0.2');
document.getElementById('circle-carrot-count').textContent = '4';
document.getElementById('circle-gap-count').textContent = '3';
}
if (step >= 4) {
// 步骤4:兔子回到起点,显示最后一个间隔,起点胡萝卜已存在
tl.to('#circle-rabbit', { rotate: -360, duration: 1, ease: "power2.out", transformOrigin: "200px 165px" })
.to('#circle-gap-3', { opacity: 1, duration: 0.5 }, '-=0.2');
// 注意:胡萝卜数量不变,因为起点已有一棵
document.getElementById('circle-carrot-count').textContent = '4';
document.getElementById('circle-gap-count').textContent = '4';
}
// 更新公式和讲解文字
const formulas = ['准备开始...', '起点种了1棵胡萝卜。', '又种1棵,现在有2棵胡萝卜,1个间隔。', '再种1棵,有3棵胡萝卜,2个间隔。', '种下第4棵,有4棵胡萝卜,3个间隔。', '回到起点!总共有4棵胡萝卜,4个间隔。树(4) = 间隔(4)!'];
document.getElementById('circle-formula').textContent = formulas[step];
document.getElementById('circle-explanation').textContent = this.circleSteps[step] || '演示完成。';
},
nextDirectStep() {
if (this.directStep < 3) {
this.directStep++;
this.runDirectAnimation();
// 不自动播放语音
}
},
prevDirectStep() {
if (this.directStep > 0) {
this.directStep--;
this.runDirectAnimation();
// 不自动播放语音
}
},
nextCircleStep() {
if (this.circleStep < 4) {
this.circleStep++;
this.runCircleAnimation();
// 不自动播放语音
}
},
prevCircleStep() {
if (this.circleStep > 0) {
this.circleStep--;
this.runCircleAnimation();
// 不自动播放语音
}
},
// 练习题逻辑
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() {
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;
this.selectedOlympiadOption = index;
if (correct) {
this.isOlympiadCorrect = true;
this.olympiadAnswered = true;
this.olympiadScore += 30;
this.wrongAttempts = 0;
if (typeof confetti !== 'undefined') {
confetti({ particleCount: 150, spread: 100, origin: { y: 0.6 } });
}
} else {
this.wrongAttempts++;
if (this.wrongAttempts >= 3) {
this.olympiadAnswered = true;
this.isOlympiadCorrect = false;
}
}
},
nextOlympiad() {
if (this.currentOlympiad < this.olympiadQuestions.length - 1) {
this.currentOlympiad++;
this.olympiadAnswered = false;
this.selectedOlympiadOption = null;
this.isOlympiadCorrect = false;
this.wrongAttempts = 0;
} else {
this.olympiadCompleted = true;
}
}
},
mounted() {
this.runDirectAnimation();
this.runCircleAnimation();
}
}).mount('#app');
</script>
</body>
</html>
💡 这段代码完全由 AI 生成。
登录后可复制完整代码