<!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>尾数0的秘密 - 深度精讲</title>
<style>
/* ================= 3.1 微信/移动端兼容性 (🚨 必须遵守) ================= */
* {
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
html, body {
margin: 0;
padding: 0;
background: #F0F4F8;
overflow: hidden;
height: 100vh;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
}
/* ================= 布局框架 ================= */
#app {
height: 100vh;
width: 100%;
max-width: 480px;
margin: 0 auto;
background: #fff;
display: flex;
flex-direction: column;
position: relative;
box-shadow: 0 0 20px rgba(0,0,0,0.05);
}
.content-area {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding-bottom: 80px;
position: relative;
-webkit-overflow-scrolling: touch;
}
/* ================= 底部导航 ================= */
.bottom-nav {
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 100%;
max-width: 480px;
height: 70px;
background: white;
border-top: 1px solid #e0e0e0;
display: flex;
justify-content: space-around;
align-items: center;
z-index: 1000;
box-shadow: 0 -2px 10px rgba(0,0,0,0.05);
}
.nav-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
padding: 8px;
transition: all 0.3s;
color: #64748B;
}
.nav-item.active {
color: #0EA5E9; /* 科技蓝 */
}
.nav-icon { font-size: 24px; margin-bottom: 4px; }
.nav-label { font-size: 12px; font-weight: 500; }
/* ================= 通用样式 ================= */
.page-container { padding: 20px; }
.section-title {
font-size: 20px;
font-weight: 800;
color: #0F172A;
margin: 20px 0 15px 0;
display: flex;
align-items: center;
gap: 8px;
}
.card {
background: white;
border-radius: 12px;
padding: 20px;
margin-bottom: 15px;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
border: 1px solid #E2E8F0;
}
.tag {
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
margin-bottom: 8px;
}
.tag-blue { background: #E0F2FE; color: #0284C7; }
.tag-red { background: #FEF2F2; color: #DC2626; }
.tag-green { background: #F0FDF4; color: #166534; }
.speak-btn {
background: linear-gradient(135deg, #0EA5E9 0%, #2563EB 100%);
color: white;
border: none;
padding: 10px 20px;
border-radius: 20px;
font-size: 14px;
cursor: pointer;
margin-top: 10px;
display: flex;
align-items: center;
gap: 5px;
box-shadow: 0 4px 10px rgba(14, 165, 233, 0.3);
}
/* ================= 演示实验室 (Page 2) ================= */
.anim-stage {
background: #1E293B;
border-radius: 16px;
padding: 20px;
min-height: 400px;
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
border: 2px solid #334155;
}
.anim-text {
color: white;
margin-top: auto;
font-size: 16px;
font-weight: bold;
text-align: center;
min-height: 40px;
background: rgba(0,0,0,0.4);
padding: 10px 20px;
border-radius: 20px;
backdrop-filter: blur(4px);
width: 100%;
}
/* 配对游戏样式 */
.pair-container {
display: flex;
width: 100%;
height: 250px;
justify-content: space-around;
align-items: center;
position: relative;
}
.factor-group {
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
}
.factor-block {
width: 30px;
height: 30px;
border-radius: 6px;
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
color: white;
font-size: 14px;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}
.factor-2 { background: #3B82F6; } /* 蓝色 */
.factor-5 { background: #EF4444; } /* 红色 */
.pair-line {
position: absolute;
height: 2px;
background: #FCD34D;
transform-origin: left center;
opacity: 0;
}
.zero-bubble {
position: absolute;
width: 40px;
height: 40px;
background: #FCD34D;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
color: #78350F;
font-size: 20px;
opacity: 0;
box-shadow: 0 0 15px rgba(252, 211, 77, 0.5);
}
/* 阶乘演示样式 */
.layer-viz {
display: flex;
flex-direction: column;
gap: 10px;
width: 100%;
padding: 10px;
}
.layer-bar {
background: rgba(255,255,255,0.1);
border-radius: 8px;
padding: 10px;
display: flex;
align-items: center;
justify-content: space-between;
color: white;
opacity: 0;
transform: translateX(-20px);
}
.step-controls {
display: flex;
gap: 15px;
margin-bottom: 15px;
justify-content: center;
}
.step-btn {
background: #0EA5E9;
color: white;
border: none;
padding: 8px 25px;
border-radius: 20px;
font-weight: bold;
font-size: 14px;
cursor: pointer;
}
.step-btn:disabled { background: #475569; color: #94A3B8; cursor: not-allowed; }
.demo-nav {
display: flex;
background: #F1F5F9;
border-radius: 12px;
padding: 4px;
margin-bottom: 15px;
}
.demo-tab {
flex: 1;
padding: 10px;
text-align: center;
border-radius: 8px;
font-size: 14px;
font-weight: bold;
color: #64748B;
cursor: pointer;
transition: all 0.3s;
}
.demo-tab.active {
background: white;
color: #0EA5E9;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
}
/* ================= 列表样式 ================= */
.step-list {
list-style: none;
padding: 0;
margin: 0;
}
.step-list li {
position: relative;
padding-left: 20px;
margin-bottom: 10px;
font-size: 14px;
line-height: 1.6;
color: #334155;
}
.step-list li::before {
content: "•";
position: absolute;
left: 0;
color: #0EA5E9;
font-weight: bold;
}
/* ================= 题目样式 ================= */
.example-item {
border: 1px solid #E2E8F0;
border-radius: 8px;
margin-bottom: 10px;
overflow: hidden;
}
.example-header {
padding: 15px;
background: #F8FAFC;
font-weight: bold;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
}
.example-content {
padding: 15px;
border-top: 1px solid #E2E8F0;
background: white;
line-height: 1.6;
font-size: 14px;
color: #334155;
display: none;
}
.example-item.active .example-content { display: block; animation: fadeIn 0.3s; }
.question-card {
background: white;
border-radius: 16px;
padding: 25px;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
margin-bottom: 20px;
}
.option-btn {
padding: 15px;
border: 2px solid #E2E8F0;
border-radius: 12px;
background: white;
text-align: left;
font-size: 16px;
cursor: pointer;
margin-bottom: 10px;
transition: all 0.2s;
width: 100%;
}
.option-btn.correct { border-color: #10B981; background: #ECFDF5; color: #047857; }
.option-btn.wrong { border-color: #EF4444; background: #FEF2F2; color: #B91C1C; }
.next-btn {
background: #0EA5E9;
color: white;
border: none;
padding: 12px;
border-radius: 8px;
width: 100%;
font-weight: bold;
font-size: 16px;
cursor: pointer;
margin-top: 10px;
}
/* 避坑指南样式 (Page 6) */
.warn-card {
border-left: 4px solid #EF4444;
background: #FEF2F2;
}
.warn-title { color: #B91C1C; font-weight: bold; margin-bottom: 5px; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
</style>
</head>
<body>
<div id="app">
<div class="content-area">
<div v-show="currentPage === 1" class="page-container">
<div class="section-title">🏭 0的生产工厂</div>
<div class="card">
<div class="tag tag-blue">配对原理</div>
<div style="text-align: center; margin: 20px 0;">
<span style="font-size: 24px; font-weight: bold; color: #3B82F6;">2</span>
<span style="font-size: 20px; margin: 0 10px;">×</span>
<span style="font-size: 24px; font-weight: bold; color: #EF4444;">5</span>
<span style="font-size: 20px; margin: 0 10px;">=</span>
<span style="font-size: 24px; font-weight: bold; color: #10B981;">10</span>
<div style="font-size: 12px; color: #64748B; margin-top: 5px;">(产生一个0)</div>
</div>
<p style="font-size: 14px; color: #475569;">
<b>木桶效应:</b>在一串连续自然数中,因子 2 总是很多,因子 5 总是很少。<br>
能配成多少对,完全取决于<b>少的那个(因子 5)</b>。
</p>
</div>
<div class="card">
<div class="tag tag-red">口诀</div>
<div style="font-size: 18px; font-weight: bold; text-align: center; color: #B91C1C; margin: 10px 0;">
末尾零,看五行 (háng)
</div>
<p style="font-size: 13px; text-align: center; color: #64748B;">
意思就是:只数因子 5 的个数!
</p>
<button class="speak-btn" @click="speakIntro">🔊 听老师讲解</button>
</div>
</div>
<div v-show="currentPage === 2" class="page-container">
<div class="section-title">🎬 动态演示</div>
<div class="demo-nav">
<div class="demo-tab" :class="{active: demoMode === 'pair'}" @click="setMode('pair')">
1. 配对原理
</div>
<div class="demo-tab" :class="{active: demoMode === 'level'}" @click="setMode('level')">
2. 阶乘数法
</div>
</div>
<div class="step-controls">
<button class="step-btn" @click="prevStep" :disabled="animStep === 0">◀ 上一步</button>
<button class="step-btn" @click="nextStep" :disabled="isMaxStep">下一步 ▶</button>
</div>
<div class="anim-stage">
<div v-if="demoMode === 'pair'" class="pair-container">
<div class="factor-group" id="group-2">
<div style="color: #3B82F6; font-size: 12px; margin-bottom: 5px;">因子 2 (多)</div>
<div class="factor-block factor-2" v-for="n in 6" :key="'2-'+n">2</div>
</div>
<div class="factor-group" id="group-5">
<div style="color: #EF4444; font-size: 12px; margin-bottom: 5px;">因子 5 (少)</div>
<div class="factor-block factor-5" v-for="n in 3" :key="'5-'+n">5</div>
</div>
</div>
<div v-if="demoMode === 'level'" class="layer-viz">
<div style="color: white; font-weight: bold; margin-bottom: 10px;">计算 1×2×...×50</div>
<div class="layer-bar" id="layer-1">
<span>第1层 (5的倍数)</span>
<span style="font-weight:bold; color:#FCD34D;">10个</span>
</div>
<div class="layer-bar" id="layer-2">
<span>第2层 (25的倍数)</span>
<span style="font-weight:bold; color:#FCD34D;">2个</span>
</div>
<div class="layer-bar" id="layer-total" style="background: rgba(16, 185, 129, 0.2); border: 1px solid #10B981;">
<span>合计</span>
<span style="font-weight:bold; font-size: 18px;">12个</span>
</div>
</div>
<div class="anim-text">{{ animText }}</div>
</div>
<div class="card" v-if="demoMode === 'pair'">
<div class="tag tag-blue">解析</div>
<p style="font-size: 13px;">
有6个“2”,但只有3个“5”。<br>
只能配成3对,产生3个0。<br>
剩下的“2”全是单身,没用!
</p>
</div>
<div class="card" v-if="demoMode === 'level'">
<div class="tag tag-green">公式</div>
<p style="font-size: 13px;">
第一层:50 ÷ 5 = 10<br>
第二层:50 ÷ 25 = 2<br>
总数 = 10 + 2 = 12 个 0。
</p>
</div>
</div>
<div v-show="currentPage === 3" class="page-container">
<div class="section-title">🔍 5道经典例题</div>
<div class="example-item" :class="{active: activeExample === index}" v-for="(ex, index) in examples" :key="index">
<div class="example-header" @click="toggleExample(index)">
<span>{{ ex.title }}</span>
<span>{{ activeExample === index ? '▲' : '▼' }}</span>
</div>
<div class="example-content">
<div style="margin-bottom: 10px; font-weight: bold; color: #1E293B;">{{ ex.question }}</div>
<div style="background: #F0F9FF; padding: 12px; border-radius: 6px; color: #0369A1; font-size: 14px;">
<strong>解析:</strong><br>
<span v-html="ex.analysis"></span>
</div>
</div>
</div>
</div>
<div v-show="currentPage === 4" class="page-container" style="height: 100%;">
<div v-if="!basicDone" class="quiz-container">
<div class="question-card">
<div class="tag tag-blue">基础 {{ currentBasicIndex + 1 }}/10</div>
<div style="font-size: 18px; font-weight: bold; margin-bottom: 20px;">{{ basicQuestions[currentBasicIndex].text }}</div>
<div v-for="(opt, idx) in basicQuestions[currentBasicIndex].options"
:key="idx"
class="option-btn"
:class="{
'correct': basicAnswered && opt.correct,
'wrong': basicAnswered && selectedBasicOpt === idx && !opt.correct
}"
@click="handleBasicAnswer(idx, opt.correct)">
{{ opt.text }}
</div>
<div v-if="basicAnswered" style="margin-top: 15px; padding: 10px; background: #F1F5F9; border-radius: 8px; font-size: 13px;">
<div v-if="isBasicCorrect" style="color: #10B981; font-weight: bold;">🎉 正确!</div>
<div v-else style="color: #EF4444; font-weight: bold;">💡 解析:</div>
<div style="margin-top: 5px;" v-html="basicQuestions[currentBasicIndex].expl"></div>
</div>
<button v-if="basicAnswered" class="next-btn" @click="nextBasic">
{{ currentBasicIndex < 9 ? '下一题 →' : '完成练习' }}
</button>
</div>
</div>
<div v-else class="card" style="height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center;">
<div style="font-size: 60px;">🏆</div>
<h2>基础训练完成</h2>
<p>得分: {{ basicScore }}/100</p>
<button class="next-btn" @click="switchPage(5)">进阶挑战奥数题 →</button>
</div>
</div>
<div v-show="currentPage === 5" class="page-container" style="height: 100%;">
<div v-if="!olympiadDone" class="quiz-container">
<div class="question-card" style="border: 2px solid #F59E0B;">
<div class="tag tag-purple">🏆 杯赛真题 {{ currentOlympiadIndex + 1 }}/10</div>
<div style="font-size: 18px; font-weight: bold; margin-bottom: 20px;">{{ olympiadQuestions[currentOlympiadIndex].text }}</div>
<div v-for="(opt, idx) in olympiadQuestions[currentOlympiadIndex].options"
:key="idx"
class="option-btn"
:class="{
'correct': olympiadAnswered && opt.correct,
'wrong': olympiadAnswered && selectedOlympiadOpt === idx && !opt.correct
}"
@click="handleOlympiadAnswer(idx, opt.correct)">
{{ opt.text }}
</div>
<div v-if="olympiadAnswered" style="margin-top: 15px; padding: 10px; background: #FFFBEB; border-radius: 8px; font-size: 13px;">
<strong>深度解析:</strong><br>
<span v-html="olympiadQuestions[currentOlympiadIndex].expl"></span>
</div>
<button v-if="olympiadAnswered" class="next-btn" style="background: #D97706;" @click="nextOlympiad">
{{ currentOlympiadIndex < 9 ? '下一题 →' : '查看总结' }}
</button>
</div>
</div>
<div v-else class="card" style="height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center;">
<div style="font-size: 60px;">🥇</div>
<h2>奥数挑战通关</h2>
<p>得分: {{ olympiadScore }}/100</p>
<button class="next-btn" @click="switchPage(6)">查看避坑指南 →</button>
</div>
</div>
<div v-show="currentPage === 6" class="page-container">
<div class="section-title">⚠️ 易错点警示</div>
<div class="card warn-card">
<div class="warn-title">1. 没有分解彻底</div>
<p style="font-size: 14px;">
❌ 错误:12 = 2 × 6<br>
✅ 正确:12 = 2 × 2 × 3<br>
<small>一定要拆到质数为止!</small>
</p>
</div>
<div class="card warn-card">
<div class="warn-title">2. 错把1当质数</div>
<p style="font-size: 14px;">
❌ 错误:12 = 1 × 2 × 2 × 3<br>
✅ 正确:12 = 2 × 2 × 3<br>
<small>1不是质数,别画蛇添足!</small>
</p>
</div>
<div class="card warn-card">
<div class="warn-title">3. 漏数25, 125</div>
<p style="font-size: 14px;">
算阶乘末尾0时,不要忘了:<br>
25 含 2个5<br>
125 含 3个5<br>
<small>要一层一层数,不要漏!</small>
</p>
</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,
// 动画状态
demoMode: 'pair', // pair, level
animStep: 0,
totalSteps: 4,
animText: '点击下一步开始演示',
isAnimating: false,
// 例题数据 (Page 3)
activeExample: null,
examples: [
{
title: '例1: 基础配对型',
question: '25 × 16 × 15 的积,末尾有几个 0?',
analysis: '分解:25=5^2, 16=2^4, 15=3×5。<br>共3个5,4个2。<br>能配3对,所以有3个0。'
},
{
title: '例2: 阶乘标准型',
question: '1×2×...×48 的积,末尾有几个 0?',
analysis: '数5的个数。<br>48÷5 = 9...3 (9个)<br>48÷25 = 1...23 (1个)<br>合计:9+1=10个。'
},
{
title: '例3: 纯奇数数列',
question: '1×3×5×...×29 的积,末尾有几个 0?',
analysis: '全是奇数,一个2都没有!<br>有5没2,配不成对。<br>答案:0个。'
},
{
title: '例4: 纯偶数数列',
question: '2×4×6×...×100 的积,末尾有几个 0?',
analysis: '提取2:2^50 × (1×2×...×50)。<br>2很多,看括号里50!的0。<br>50÷5=10, 50÷25=2。共12个。'
},
{
title: '例5: 加法原理',
question: '20! + 30! 的末尾有几个 0?',
analysis: '加法看最少!<br>20!有4个0,30!有7个0。<br>加起来取决于少的,只有4个0。'
}
],
// 练习数据 (Page 4)
currentBasicIndex: 0,
basicScore: 0,
basicAnswered: false,
isBasicCorrect: false,
selectedBasicOpt: null,
basicDone: false,
basicQuestions: [
{ text: '32 × 125 的积末尾有几个 0?', options: [{text:'3个',correct:true}, {text:'5个',correct:false}, {text:'2个',correct:false}], expl: '32=2^5, 125=5^3。3个5配3个2。' },
{ text: '1×...×24 的积末尾有几个 0?', options: [{text:'4个',correct:true}, {text:'5个',correct:false}, {text:'6个',correct:false}], expl: '24÷5=4。没有25。' },
{ text: '1×...×80 的积末尾有几个 0?', options: [{text:'16个',correct:false}, {text:'19个',correct:true}, {text:'20个',correct:false}], expl: '80÷5=16, 80÷25=3。16+3=19。' },
{ text: '125×8×25×4 的积末尾有几个 0?', options: [{text:'5个',correct:true}, {text:'6个',correct:false}, {text:'4个',correct:false}], expl: '5: 3+2=5个。2: 3+2=5个。正好5对。' },
{ text: '100! 的末尾有几个 0?', options: [{text:'20个',correct:false}, {text:'24个',correct:true}, {text:'25个',correct:false}], expl: '100÷5=20, 100÷25=4。20+4=24。' },
{ text: '200! 的末尾有几个 0?', options: [{text:'40个',correct:false}, {text:'49个',correct:true}, {text:'48个',correct:false}], expl: '200÷5=40, 200÷25=8, 200÷125=1。40+8+1=49。' },
{ text: '1×3×5×...×99,末尾几个0?', options: [{text:'0个',correct:true}, {text:'10个',correct:false}, {text:'24个',correct:false}], expl: '奇数积没2,配不成0。' },
{ text: '10×20×30×40×50,末尾几个0?', options: [{text:'5个',correct:false}, {text:'6个',correct:true}, {text:'7个',correct:false}], expl: '10,20,30,40各1个5,50有2个5。共6个5,2足够。' },
{ text: '75 × 16 的积末尾有几个 0?', options: [{text:'2个',correct:true}, {text:'1个',correct:false}, {text:'3个',correct:false}], expl: '75=3×5^2, 16=2^4。2个5配2个2。' },
{ text: '判断:24!和25!末尾0个数一样多?', options: [{text:'错',correct:true}, {text:'对',correct:false}], expl: '24!有4个,25!有6个(25含两5)。' }
],
// 奥数题 (Page 5)
currentOlympiadIndex: 0,
olympiadScore: 0,
olympiadAnswered: false,
selectedOlympiadOpt: null,
olympiadDone: false,
olympiadQuestions: [
{ text: '2015! 末尾有多少个连续的 0?', options: [{text:'502',correct:true}, {text:'403',correct:false}], expl: '2015÷5=403, ÷25=80, ÷125=16, ÷625=3。加起来502。' },
{ text: '50! 末尾有多少个 0?', options: [{text:'12',correct:true}, {text:'10',correct:false}], expl: '50÷5=10, 50÷25=2。10+2=12。' },
{ text: 'N! 末尾恰好6个0,N最小是?', options: [{text:'25',correct:true}, {text:'30',correct:false}], expl: '24!有4个,25!有6个(跳过了5个)。最小25。' },
{ text: '25×64×125×50 末尾几个0?', options: [{text:'7个',correct:true}, {text:'6个',correct:false}], expl: '5: 2+3+2=7个。2: 6+1=7个。正好7个。' },
{ text: '100以内所有偶数乘积末尾几个0?', options: [{text:'12',correct:true}, {text:'24',correct:false}], expl: '偶数积=2^50×50!。看50!的0,是12个。' },
{ text: '100! ÷ 10^k 是整数,k最大?', options: [{text:'24',correct:true}, {text:'20',correct:false}], expl: '就是问100!有几个0。24个。' },
{ text: '6×11×16×...×56 末尾几个0?', options: [{text:'0个',correct:true}, {text:'3个',correct:false}], expl: '个位是6,1,6,1... 没5没0,没有因子5。' },
{ text: 'A=1999!, C=偶数积,A-C末尾几个0?', options: [{text:'496',correct:false}, {text:'246',correct:true}], expl: 'A-C = C(B-1)。取决于C(999!×2^999)的0。999!有246个0。' }, // 极难题简化
{ text: '1000! 末尾几个0?', options: [{text:'249',correct:true}, {text:'200',correct:false}], expl: '200+40+8+1 = 249。' },
{ text: 'N! 有24个0,N最大是?', options: [{text:'104',correct:true}, {text:'100',correct:false}], expl: '100!是24个。101-104都不含5,0不变。105变成25个。最大104。' }
]
}
},
computed: {
isMaxStep() { return this.animStep >= this.totalSteps; }
},
methods: {
speak(text) {
if (window.speechSynthesis) window.speechSynthesis.cancel();
const isWeChat = /MicroMessenger/i.test(navigator.userAgent);
if (isWeChat) {
let audio = document.getElementById('tts-audio');
if (!audio) {
audio = document.createElement('audio'); audio.id = 'tts-audio'; audio.style.display = 'none';
document.body.appendChild(audio);
}
const url = `https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/tts.php?text=${encodeURIComponent(text)}&t=${Date.now()}`;
audio.src = url;
audio.play().catch(e => { if(window.WeixinJSBridge) window.WeixinJSBridge.invoke('getNetworkType',{},()=>audio.play()); });
} else {
if (window.speechSynthesis) {
const u = new SpeechSynthesisUtterance(text); u.lang = 'zh-CN'; u.rate = 0.9;
window.speechSynthesis.speak(u);
}
}
},
speakIntro() {
this.speak("在乘法里,末尾的0是由2乘5产生的。因为偶数很多,5比较少,所以能配成几对,全看有多少个5。");
},
switchPage(page) {
if(window.speechSynthesis) window.speechSynthesis.cancel();
const audio = document.getElementById('tts-audio');
if(audio) audio.pause();
this.currentPage = page;
window.scrollTo(0,0);
if(page===2) this.setMode('pair');
},
// ================= 动画逻辑 =================
setMode(mode) {
this.demoMode = mode;
this.animStep = 0;
this.animText = "点击下一步开始演示";
if(typeof gsap !== 'undefined') gsap.killTweensOf('*');
// 清理DOM
const container = document.querySelector('.pair-container');
if(container) {
const lines = container.querySelectorAll('.pair-line, .zero-bubble');
lines.forEach(el => el.remove());
}
if (mode === 'pair') this.totalSteps = 3;
else this.totalSteps = 3;
},
nextStep() {
if (this.animStep < this.totalSteps) {
this.animStep++;
this.renderScene();
}
},
prevStep() {
if (this.animStep > 0) {
this.animStep--;
this.setMode(this.demoMode); // 简单重置
}
},
renderScene() {
if(typeof gsap === 'undefined') return;
if (this.demoMode === 'pair') {
if (this.animStep === 1) {
this.animText = "寻找搭档...";
// 生成连线
const container = document.querySelector('.pair-container');
for(let i=0; i<3; i++) {
const line = document.createElement('div');
line.className = 'pair-line';
line.style.left = '33%';
line.style.top = (40 + i*35) + 'px';
line.style.width = '34%';
line.style.transform = `rotate(${i*10 - 10}deg)`; // 简单视觉效果
container.appendChild(line);
gsap.to(line, {opacity: 1, duration: 0.5, delay: i*0.2});
}
this.speak("只有3个红色的5,只能找3个蓝色的2配对。");
} else if (this.animStep === 2) {
this.animText = "生成 0 !";
const container = document.querySelector('.pair-container');
for(let i=0; i<3; i++) {
const bubble = document.createElement('div');
bubble.className = 'zero-bubble';
bubble.innerHTML = '0';
bubble.style.left = '45%';
bubble.style.top = (30 + i*35) + 'px';
container.appendChild(bubble);
gsap.to(bubble, {opacity: 1, scale: [0,1.2,1], duration: 0.5, delay: i*0.2});
}
this.speak("配成3对,产生了3个0。");
} else if (this.animStep === 3) {
this.animText = "剩下的 2 单身了";
gsap.to('.factor-group:first-child .factor-block:nth-child(n+5)', {opacity: 0.3, duration: 0.5});
this.speak("剩下的2虽然多,但是没有5跟它配,没法产生0。");
}
} else {
// Level
if (this.animStep === 1) {
this.animText = "第一层筛选:5的倍数";
gsap.to('#layer-1', {opacity: 1, x: 0, duration: 0.5});
this.speak("50除以5等于10,有10个数包含至少一个5。");
} else if (this.animStep === 2) {
this.animText = "第二层筛选:25的倍数";
gsap.to('#layer-2', {opacity: 1, x: 0, duration: 0.5});
this.speak("50除以25等于2,这两个数(25和50)贡献了第二个5。");
} else if (this.animStep === 3) {
this.animText = "汇总统计";
gsap.to('#layer-total', {opacity: 1, x: 0, duration: 0.5, scale: [1.1, 1]});
this.speak("加起来一共12个5,所以末尾有12个0。");
}
}
},
// 练习逻辑
handleBasicAnswer(i, c) {
if(this.basicAnswered) return;
this.basicAnswered = true; this.isBasicCorrect = c; this.selectedBasicOpt = i;
if(c) { this.basicScore += 10; if(typeof confetti !== 'undefined') confetti({particleCount: 100, spread: 70, origin: {y: 0.6}});}
},
nextBasic() { if(this.currentBasicIndex<9){this.currentBasicIndex++; this.basicAnswered=false; this.selectedBasicOpt=null;}else{this.basicDone=true;} },
handleOlympiadAnswer(i, c) {
if(this.olympiadAnswered) return;
this.olympiadAnswered = true; this.selectedOlympiadOpt = i;
if(c) { this.olympiadScore += 10; if(typeof confetti !== 'undefined') confetti({particleCount: 150, spread: 90, colors: ['#F59E0B']});}
},
nextOlympiad() { if(this.currentOlympiadIndex<9){this.currentOlympiadIndex++; this.olympiadAnswered=false; this.selectedOlympiadOpt=null;}else{this.olympiadDone=true;} },
toggleExample(idx) { this.activeExample = this.activeExample === idx ? null : idx; }
},
mounted() { this.setMode('pair'); }
}).mount('#app');
</script>
</body>
</html>
💡 这段代码完全由 gemini 生成。
登录后可复制完整代码