<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>因数与倍数 - 深度精讲</title>
<style>
/* ================= 3.1 微信/移动端兼容性 (🚨 必须遵守) ================= */
* {
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
html, body {
margin: 0;
padding: 0;
background: #F0F0F0;
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: #7C3AED;
}
.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: bold;
color: #1E293B;
margin: 20px 0 15px 0;
display: flex;
align-items: center;
gap: 8px;
}
.card {
background: white;
border-radius: 12px;
padding: 20px;
margin-bottom: 15px;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
border: 1px solid #F1F5F9;
}
.speak-btn {
background: linear-gradient(135deg, #7C3AED 0%, #6D28D9 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;
width: fit-content;
}
/* ================= 动画演示样式 (Page 2 - 增强版) ================= */
.demo-nav {
display: flex;
overflow-x: auto;
gap: 10px;
padding-bottom: 10px;
margin-bottom: 10px;
-webkit-overflow-scrolling: touch;
}
.demo-nav::-webkit-scrollbar { display: none; }
.demo-tab {
flex-shrink: 0;
padding: 8px 16px;
background: #F1F5F9;
border-radius: 20px;
font-size: 13px;
color: #64748B;
font-weight: bold;
cursor: pointer;
white-space: nowrap;
}
.demo-tab.active {
background: #7C3AED;
color: white;
box-shadow: 0 4px 10px rgba(124, 58, 237, 0.3);
}
.step-controls {
display: flex;
gap: 15px;
margin-bottom: 15px;
justify-content: center;
}
.step-btn {
background: #7C3AED;
color: white;
border: none;
padding: 10px 30px;
border-radius: 25px;
font-size: 15px;
font-weight: bold;
cursor: pointer;
display: flex;
align-items: center;
gap: 8px;
box-shadow: 0 4px 10px rgba(124, 58, 237, 0.3);
transition: transform 0.1s;
}
.step-btn:active { transform: scale(0.95); }
.step-btn:disabled { background: #E2E8F0; color: #94A3B8; cursor: not-allowed; box-shadow: none; }
.anim-stage {
background: #1E293B;
border-radius: 16px;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
min-height: 360px;
position: relative;
overflow: hidden;
margin-bottom: 15px;
border: 2px solid #334155;
}
.blocks-container {
height: 240px;
width: 100%;
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
/* 积木样式 */
.block {
width: 32px;
height: 32px;
background: #FCD34D;
border: 2px solid #D97706;
border-radius: 6px;
position: absolute;
box-shadow: 0 4px 0 rgba(0,0,0,0.2);
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
color: #92400E;
font-size: 14px;
}
.block.multiple-mode { background: #60A5FA; border-color: #1D4ED8; color: white; }
/* 找朋友游戏的数字球 */
.num-ball {
width: 50px;
height: 50px;
border-radius: 50%;
background: white;
color: #334155;
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
font-size: 18px;
position: absolute;
cursor: pointer;
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
border: 2px solid #E2E8F0;
transition: all 0.3s;
}
.num-ball.selected { background: #10B981; color: white; border-color: #059669; transform: scale(1.1); }
.num-ball.wrong { background: #EF4444; color: white; border-color: #B91C1C; animation: shake 0.5s; }
.anim-text {
color: white;
margin-top: 15px;
font-size: 15px;
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);
line-height: 1.4;
}
.concept-box {
background: #FFFBEB;
border-left: 4px solid #F59E0B;
padding: 15px;
border-radius: 0 8px 8px 0;
margin-top: 10px;
font-size: 14px;
line-height: 1.6;
color: #475569;
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
}
/* ================= 概念对比表 (Page 6) ================= */
.compare-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
border-radius: 12px;
overflow: hidden;
border: 1px solid #E2E8F0;
}
.compare-table th {
background: #F8FAFC;
padding: 12px;
font-weight: bold;
color: #475569;
border-bottom: 1px solid #E2E8F0;
}
.compare-table td {
padding: 12px;
border-bottom: 1px solid #E2E8F0;
font-size: 13px;
line-height: 1.4;
text-align: center;
}
.compare-table tr:last-child td { border-bottom: none; }
.bg-blue { background: #EFF6FF; color: #1E40AF; }
.bg-green { background: #F0FDF4; color: #166534; }
/* ================= 例题 & 练习 (Page 3,4,5) ================= */
.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);
flex: 1;
display: flex;
flex-direction: column;
margin: 10px;
}
.q-tag {
background: #F3E8FF;
color: #7C3AED;
padding: 4px 10px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
align-self: flex-start;
margin-bottom: 10px;
}
.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;
}
.option-btn.correct { border-color: #10B981; background: #ECFDF5; color: #047857; }
.option-btn.wrong { border-color: #EF4444; background: #FEF2F2; color: #B91C1C; }
.next-btn {
margin-top: auto;
background: #7C3AED;
color: white;
border: none;
padding: 15px;
border-radius: 12px;
font-size: 16px;
font-weight: bold;
width: 100%;
cursor: pointer;
}
@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">2. 核心概念:什么是因数与倍数?</div>
<div class="card">
<div style="font-size: 16px; font-weight: bold; margin-bottom: 10px; color: #1E293B;">2.1 “拼长方形”游戏 (图形化理解)</div>
<p style="font-size: 14px; color: #475569; line-height: 1.6;">
想象我们手中有若干个小正方形积木(比如12个)。我们要用它们拼成一个实心的长方形。
</p>
<ul style="font-size: 14px; color: #475569; line-height: 1.8; padding-left: 20px;">
<li><b>能不能拼成长条?</b> 能!摆成 1 行,每行 12 个。</li>
<li><b>能不能拼宽一点?</b> 能!摆成 2 行,每行 6 个。</li>
<li><b>还能更方一点吗?</b> 能!摆成 3 行,每行 4 个。</li>
<li><b style="color:#EF4444;">摆成5行行不行?</b> 不行!12 ÷ 5 有余数,多出来的积木拼不成完整的长方形。</li>
</ul>
<div style="background: #F0FDF4; border: 1px solid #10B981; padding: 10px; border-radius: 8px; margin-top: 10px; font-size: 14px; color: #047857;">
<b>结论:</b>凡是能正好拼成长方形的边长数字,就是这个数的<b>因数</b>。
</div>
</div>
<div class="card">
<div style="font-size: 16px; font-weight: bold; margin-bottom: 10px; color: #1E293B;">2.2 数学定义</div>
<p style="font-size: 14px; color: #475569; line-height: 1.6;">
如果整数 a 除以整数 b (b ≠ 0),商是整数且没有余数(即整除),我们就说:
</p>
<div style="background: #EFF6FF; padding: 15px; border-radius: 8px; margin: 10px 0;">
<ul style="font-size: 15px; color: #1E40AF; line-height: 1.8; margin: 0; padding-left: 20px;">
<li><b>a 是 b 的倍数</b></li>
<li><b>b 是 a 的因数 (也叫约数)</b></li>
</ul>
</div>
<div style="background: #FFFBEB; border-left: 4px solid #F59E0B; padding: 10px; font-size: 14px; color: #92400E; line-height: 1.6;">
<b>口诀:</b>大数是小数的倍数,小数是大数的因数。它们是成对出现的,不能单独说“3是因数”,要说“3是12的因数”。
</div>
<button class="speak-btn" @click="speakConcept">🔊 听老师讲解</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 === 'def'}" @click="setMode('def')">
1. 定义演示
</div>
<div class="demo-tab" :class="{active: demoMode === 'rect'}" @click="setMode('rect')">
2. 拼长方形
</div>
<div class="demo-tab" :class="{active: demoMode === 'multi'}" @click="setMode('multi')">
3. 倍数增长
</div>
<div class="demo-tab" :class="{active: demoMode === 'find'}" @click="setMode('find')">
4. 找朋友(互动)
</div>
</div>
<div class="step-controls" v-if="demoMode !== 'find'">
<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 class="blocks-container" id="blocks-container">
<div v-if="demoMode === 'def'" style="color: white; font-size: 24px; font-weight: bold;">
{{ defContent }}
</div>
<div v-else-if="demoMode === 'rect' || demoMode === 'multi'">
<div v-for="(b, i) in blocks" :key="i"
class="block"
:class="{'multiple-mode': demoMode === 'multi'}"
:id="'b-'+i">
</div>
</div>
<div v-else-if="demoMode === 'find'">
<div style="color: white; font-size: 18px; position: absolute; top: 10px;">
找出 <b>18</b> 的因数
</div>
<div v-for="(ball, i) in balls" :key="i"
class="num-ball"
:class="{selected: ball.selected, wrong: ball.wrong}"
:style="{left: ball.x + 'px', top: ball.y + 'px'}"
@click="checkFactor(i)">
{{ ball.num }}
</div>
</div>
</div>
<div class="anim-text">{{ animText }}</div>
</div>
<div class="concept-box" v-if="demoMode === 'rect'">
<b>🧩 拼图原理:</b><br>
12个积木能拼成 1x12, 2x6, 3x4 的长方形。<br>
所以 1, 2, 3, 4, 6, 12 都是12的因数。<br>
拼不成5行,说明5不是12的因数。
</div>
<div class="concept-box" style="border-left-color: #3B82F6; background: #EFF6FF;" v-if="demoMode === 'multi'">
<b>🚀 增长原理:</b><br>
2的倍数就是 2, 4, 6, 8...<br>
每增加一层,就多一个2。<br>
倍数是无限的,可以一直堆到天上去!
</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: 500;">{{ ex.question }}</div>
<div style="background: #F3E8FF; padding: 10px; border-radius: 6px; color: #4C1D95; font-size: 13px;">
<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" style="height: 100%; display: flex; flex-direction: column;">
<div class="question-card">
<div class="q-tag">基础巩固 {{ currentBasicIndex + 1 }}/10</div>
<div class="q-text">{{ 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: #F8FAFC; 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;">{{ 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" style="height: 100%; display: flex; flex-direction: column;">
<div class="question-card" style="border: 2px solid #F59E0B;">
<div class="q-tag" style="background: #FFFBEB; color: #D97706;">🏆 奥数真题 {{ currentOlympiadIndex + 1 }}/10</div>
<div class="q-text" v-html="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">
<div style="font-weight: bold; margin-bottom: 10px; text-align: center;">因数 vs 倍数</div>
<table class="compare-table">
<tr>
<th>比较项目</th>
<th>因数 (零件)</th>
<th>倍数 (产物)</th>
</tr>
<tr>
<td>形象</td>
<td class="bg-blue">拆分</td>
<td class="bg-green">放大</td>
</tr>
<tr>
<td>大小</td>
<td class="bg-blue">比原数小<br>(或相等)</td>
<td class="bg-green">比原数大<br>(或相等)</td>
</tr>
<tr>
<td>数量</td>
<td class="bg-blue">有限</td>
<td class="bg-green">无限</td>
</tr>
<tr>
<td>极值</td>
<td class="bg-blue">最小是1<br>最大是本身</td>
<td class="bg-green">最小是本身<br>没有最大</td>
</tr>
</table>
</div>
<div class="card" style="border-left: 4px solid #EC4899;">
<div style="font-weight: bold; color: #BE185D;">🔑 寻找技巧 (成对找)</div>
<p style="font-size: 14px; margin-top: 10px;">
找因数时,从1开始,一对一对找,直到相遇。<br>
例如找36的因数:<br>
1×36, 2×18, 3×12, 4×9, 6×6<br>
不要漏掉哦!
</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: 'def', // def, rect, multi, find
animStep: 0,
totalSteps: 0,
animText: '请选择上方模式开始演示',
blocks: [],
defContent: '', // 定义演示内容
balls: [], // 找朋友小球
// 例题
activeExample: null,
examples: [
{
title: '例1: 概念判断',
question: '关于算式 4×9=36,下列说法正确的是?',
analysis: '因数倍数要成对出现。<br>A错(没说是谁的)。B漏了4。D错(4是36的因数)。<br>C正确:4是36的因数,36是9的倍数。'
},
{
title: '例2: 找因数',
question: '数字 18 的所有因数有哪些?',
analysis: '成对找:1×18, 2×9, 3×6。<br>答案:1, 2, 3, 6, 9, 18。'
},
{
title: '例3: 找倍数',
question: '50以内 7 的倍数有哪些?',
analysis: '7×1=7, 7×2=14, 7×3=21... 7×7=49。<br>答案:7, 14, 21, 28, 35, 42, 49。'
},
{
title: '例4: 完美数',
question: '6 的所有因数(除了它本身)之和是多少?',
analysis: '6的因数:1, 2, 3, 6。<br>除了本身:1+2+3=6。<br>像这样和等于本身的数叫完美数。'
},
{
title: '例5: 分组问题',
question: '24个同学排队,每排人数一样多,有几种排法?',
analysis: '其实就是找24的因数。<br>1×24, 2×12, 3×8, 4×6。<br>一共8个因数,所以有8种排法。'
}
],
// 基础练习
currentBasicIndex: 0,
basicScore: 0,
basicAnswered: false,
isBasicCorrect: false,
selectedBasicOpt: null,
basicDone: false,
basicQuestions: [
{ text: '【判断】因为8÷0.5=16,所以16是8的倍数。', options: [{text:'对',correct:false}, {text:'错',correct:true}], expl: '错。因数和倍数研究的对象必须是整数(0除外)。' },
{ text: '【判断】1是所有非零自然数的因数。', options: [{text:'对',correct:true}, {text:'错',correct:false}], expl: '对。任何非0自然数除以1都得它本身。' },
{ text: '【判断】一个数的倍数一定比它的因数大。', options: [{text:'对',correct:false}, {text:'错',correct:true}], expl: '错。例如6的倍数6,和6的因数6,是相等的。' },
{ text: '24的最小因数和最大因数分别是?', options: [{text:'1, 24',correct:true}, {text:'2, 12',correct:false}, {text:'1, 无限',correct:false}], expl: '最小因数是1,最大因数是它本身24。' },
{ text: '7的最小倍数是?', options: [{text:'1',correct:false}, {text:'7',correct:true}, {text:'14',correct:false}], expl: '最小倍数是它本身,即7。' },
{ text: '下面哪个数既是2的倍数,又是3的倍数?', options: [{text:'15',correct:false}, {text:'16',correct:false}, {text:'18',correct:true}], expl: '18是偶数(2倍数),18÷3=6(3倍数)。' },
{ text: '12的倍数中,最小的两位数是?', options: [{text:'12',correct:true}, {text:'24',correct:false}, {text:'10',correct:false}], expl: '12的倍数:12, 24... 最小的两位数就是12。' },
{ text: '一个数既是15的倍数,又是15的因数,它是?', options: [{text:'1',correct:false}, {text:'15',correct:true}, {text:'30',correct:false}], expl: '一个数既是倍数又是因数,这个数只能是它本身。' },
{ text: '36的因数一共有几个?', options: [{text:'8个',correct:false}, {text:'9个',correct:true}, {text:'10个',correct:false}], expl: '1,2,3,4,6,9,12,18,36。注意6×6只算一个。' },
{ text: '下列哪组数中,第二个数是第一个数的倍数?', options: [{text:'6和3',correct:false}, {text:'2和10',correct:true}, {text:'0.5和1',correct:false}], expl: '10 ÷ 2 = 5 (整除)。' }
],
// 奥数题 (纯因数倍数逻辑)
currentOlympiadIndex: 0,
olympiadScore: 0,
olympiadAnswered: false,
selectedOlympiadOpt: null,
olympiadDone: false,
olympiadQuestions: [
{ text: '一个自然数的最大因数和最小因数之和是51,这个数是?', options: [{text:'51',correct:false}, {text:'50',correct:true}, {text:'49',correct:false}], expl: '最小因数是1。所以最大因数(本身) = 51-1=50。' },
{ text: '100以内,8和12的公倍数中最大的是?', options: [{text:'96',correct:true}, {text:'72',correct:false}, {text:'48',correct:false}], expl: '8和12的最小公倍数是24。24×4=96,24×5=120(超了)。' },
{ text: '甲数是乙数的因数,乙数是丙数的因数,那么甲数___丙数的因数。', options: [{text:'一定是',correct:true}, {text:'不一定是',correct:false}], expl: '传递性。甲|乙,乙|丙 → 甲|丙。' },
{ text: '有一箱苹果,3个3个拿正好拿完,5个5个拿也正好拿完。这箱苹果至少有?', options: [{text:'10个',correct:false}, {text:'15个',correct:true}, {text:'30个',correct:false}], expl: '既是3的倍数又是5的倍数,最小公倍数是15。' },
{ text: '一个数在20到40之间,它是3的倍数,且因数个数是奇数,它是?', options: [{text:'27',correct:false}, {text:'36',correct:true}, {text:'30',correct:false}], expl: '因数个数是奇数说明是完全平方数。20-40间的完全平方数有25(不是3倍数), 36(是)。' },
{ text: 'A和B都是自然数,A÷B=5,A和B的最大公因数是?', options: [{text:'A',correct:false}, {text:'B',correct:true}, {text:'5',correct:false}], expl: 'A是B的倍数,B是A的因数。存在倍数关系时,最大公因数是较小数(B)。' },
{ text: '两个质数的积是39,这两个质数的和是?', options: [{text:'16',correct:true}, {text:'40',correct:false}, {text:'39',correct:false}], expl: '39 = 3 × 13 (3和13都是质数)。3+13=16。' },
{ text: '幼儿园老师发糖果,如果不发给小红,平均每人分4块;如果不发给小明,平均每人分5块。糖果至少?', options: [{text:'20',correct:true}, {text:'40',correct:false}, {text:'10',correct:false}], expl: '总数减1是4的倍数,也是5的倍数。4和5最小公倍数20。总数至少是20+1=21? 不,题目意思是总数是4的倍数(不算小红),也是5的倍数(不算小明)。这里指总数能被4整除也能被5整除。所以至少20块。' },
{ text: '一个数是10的倍数,也是15的倍数,这个数最小是?', options: [{text:'30',correct:true}, {text:'60',correct:false}, {text:'150',correct:false}], expl: '10和15的最小公倍数。10=2×5, 15=3×5 -> 2×3×5=30。' },
{ text: '有三个连续自然数,其中一个是5的倍数,一个是7的倍数,一个是9的倍数,这三个数最小是?', options: [{text:'158,159,160',correct:false}, {text:'159,160,161',correct:true}, {text:'153,154,155',correct:false}, {text:'157,158,159',correct:false}], expl: '159(3倍数非9), 160(5), 161(7)。注意题目说只要是倍数即可,不要求是最小倍数。' }
]
}
},
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 themePath = 'https://www.xinghuo.tv/wp-content/themes/xinghuo-tv';
const url = `${themePath}/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);
}
}
},
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) {
if(typeof gsap !== 'undefined') gsap.killTweensOf('.block');
} else {
this.setMode('def');
}
},
speakConcept() {
this.speak("凡是能正好拼成长方形的边长数字,就是这个数的因数。比如12能拼成1行、2行、3行,所以1、2、3都是12的因数。大数是小数的倍数,小数是大数的因数,它们是成对出现的。");
},
toggleExample(index) {
this.activeExample = this.activeExample === index ? null : index;
},
// ================= 动画演示逻辑 (4种模式) =================
setMode(mode) {
this.demoMode = mode;
this.animStep = 0;
this.blocks = [];
this.balls = [];
this.animText = "点击下一步开始演示";
if(typeof gsap !== 'undefined') gsap.killTweensOf('*');
if (mode === 'def') {
this.totalSteps = 1;
this.animText = "点击下一步查看定义动画";
this.defContent = "";
} else if (mode === 'rect') {
this.totalSteps = 3;
this.blocks = Array(12).fill(1);
this.$nextTick(() => {
gsap.set('.block', {x: 0, y: 0, opacity: 1});
gsap.to('.block', {x: (i)=>Math.random()*200-100, y: (i)=>Math.random()*100-50, duration: 0.5});
});
this.animText = "12个积木怎么拼?点击下一步";
} else if (mode === 'multi') {
this.totalSteps = 4;
this.blocks = [];
this.animText = "点击下一步,开始堆积木";
} else if (mode === 'find') {
// 找朋友互动游戏初始化
const numbers = [1, 2, 3, 4, 5, 6, 9, 10, 12, 18]; // 混淆项
this.balls = numbers.map(n => ({
num: n,
x: Math.random() * 260 - 130, // 范围
y: Math.random() * 200 - 100,
selected: false,
wrong: false
}));
this.animText = "点击泡泡,找出18的因数!";
}
},
nextStep() {
if (this.animStep < this.totalSteps) {
this.animStep++;
this.renderScene();
}
},
prevStep() {
if (this.animStep > 0) {
this.animStep--;
this.renderScene();
}
},
renderScene() {
if(typeof gsap === 'undefined') return;
// 1. 定义演示
if (this.demoMode === 'def') {
if (this.animStep === 1) {
this.defContent = "12 ÷ 2 = 6 (整除)";
this.animText = "2和6是因数,12是倍数";
this.speak("12除以2等于6,没有余数。所以2和6是12的因数,12是2和6的倍数。");
}
}
// 2. 拼长方形
else if (this.demoMode === 'rect') {
const targets = gsap.utils.toArray('.block');
if (this.animStep === 1) {
this.animText = "拼法1:1行12个 → 1和12是因数";
gsap.to(targets, { x: (i) => (i - 5.5) * 34, y: 0, duration: 0.5 });
} else if (this.animStep === 2) {
this.animText = "拼法2:2行6个 → 2和6是因数";
gsap.to(targets, { x: (i) => (i % 6 - 2.5) * 34, y: (i) => (Math.floor(i / 6) - 0.5) * 34, duration: 0.5 });
} else if (this.animStep === 3) {
this.animText = "拼法3:3行4个 → 3和4是因数";
gsap.to(targets, { x: (i) => (i % 4 - 1.5) * 34, y: (i) => (Math.floor(i / 4) - 1) * 34, duration: 0.5 });
}
}
// 3. 倍数增长
else if (this.demoMode === 'multi') {
const targetCount = this.animStep * 2;
if (this.blocks.length < targetCount) {
for(let k=0; k<2; k++) this.blocks.push(1);
}
this.$nextTick(() => {
this.blocks.forEach((_, index) => {
const row = Math.floor(index / 2);
const col = index % 2;
const el = document.getElementById('b-'+index);
if(el) gsap.to(el, { x: (col - 0.5) * 34, y: (3 - row) * 34 - 50, duration: 0.5 });
});
const num = this.animStep * 2;
this.animText = `第${this.animStep}层:2的${this.animStep}倍是${num}`;
});
}
},
// 找朋友互动逻辑
checkFactor(index) {
const ball = this.balls[index];
const factorsOf18 = [1, 2, 3, 6, 9, 18];
if (factorsOf18.includes(ball.num)) {
ball.selected = true;
this.animText = `对!${ball.num} 是 18 的因数。`;
if(typeof confetti !== 'undefined') confetti({particleCount: 50, spread: 50, origin: { y: 0.5 }});
// 检查是否找全
const foundCount = this.balls.filter(b => b.selected).length;
if (foundCount === factorsOf18.length) {
this.animText = "太棒了!你找全了所有因数!";
this.speak("恭喜你,18的因数找全了!");
}
} else {
ball.wrong = true;
this.animText = `不对哦,18 ÷ ${ball.num} 有余数。`;
setTimeout(() => { ball.wrong = false; }, 500);
}
},
// 练习题逻辑
handleBasicAnswer(index, correct) {
if (this.basicAnswered) return;
this.selectedBasicOpt = index;
this.basicAnswered = true;
this.isBasicCorrect = correct;
if(correct) {
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(index, correct) {
if(this.olympiadAnswered) return;
this.selectedOlympiadOpt = index;
this.olympiadAnswered = true;
if(correct) {
this.olympiadScore += 10;
if(typeof confetti !== 'undefined') confetti({particleCount:150, spread:90, colors:['#D97706']});
}
},
nextOlympiad() {
if(this.currentOlympiadIndex < 9) {
this.currentOlympiadIndex++;
this.olympiadAnswered = false;
this.selectedOlympiadOpt = null;
} else {
this.olympiadDone = true;
}
}
},
mounted() {
this.setMode('def');
}
}).mount('#app');
</script>
</body>
</html>
💡 这段代码完全由 claude 生成。
登录后可复制完整代码