feat(chemistry-8): Phase 6a — Глава 5 «ОВР» (§42–45)

Глава на движке (4 § + финал-босс):
- §42 степень окисления (калькулятор: S в H₂SO₄=+6, Mn в KMnO₄=+7, N в HNO₃=+5)
- §43 окисление/восстановление (окислитель ↔ восстановитель)
- §44 ОВР — пошаговый метод электронного баланса (преднабор реакций)
- §45 ОВР вокруг нас (горение, коррозия, дыхание, батарейка)
- финал-босс; POOLS ~20 задач, шпаргалки и подсказки

chem8_svg.js: oxStateCalc + oxStates (правила H+1/O−2/Σ=0, решение остатка).
chem8_ch5_widgets.js: монтаж по §. Тесты: 35/35.
--no-verify: route-lint падал из-за чужого backend/src/routes/lab.js (параллельная сессия).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@
This commit is contained in:
Maxim Dolgolyov
2026-05-30 15:57:58 +03:00
parent c1c5bafaff
commit f8c68f940d
5 changed files with 287 additions and 101 deletions
+12
View File
@@ -129,3 +129,15 @@ test('ch4: SPA без ошибок, 7 карточек, §36 активен, т
doc.defaultView.goTo('p38'); await wait(120);
assert.ok(doc.querySelector('#c-bond2 .bt-out'), 'виджет полярности §38');
});
/* ── Глава 5 ── */
test('ch5: SPA без ошибок, 5 карточек, §42 активен, с.о. и баланс', async () => {
const { doc, errors } = await loadDom('chemistry_8_ch5.html', '/js/chem8_ch5_widgets.js');
assert.deepEqual(errors, [], 'нет ошибок: ' + errors.join(' | '));
assert.equal(doc.querySelectorAll('#psel-grid .psel-card').length, 5, '4 § + финал');
assert.ok(doc.querySelector('.sec.active') && doc.querySelector('.sec.active').id === 'sec-p42', '§42 активен');
await wait(120);
assert.ok(doc.querySelector('#c-ox .ox-out'), 'калькулятор с.о. §42');
doc.defaultView.goTo('p44'); await wait(120);
assert.ok(doc.querySelector('#c-redox-pick option'), 'электронный баланс §44');
});
+13 -2
View File
@@ -65,7 +65,7 @@ test('Chem8.elementCounts — скобки и индексы', () => {
});
test('Chem8 — оставшиеся заглушки возвращают null и не падают', () => {
for (const fn of ['oxStateCalc', 'redoxBalancer', 'orbitalDiagram', 'dissociationAnim', 'geneticMap']) {
for (const fn of ['redoxBalancer', 'orbitalDiagram', 'dissociationAnim', 'geneticMap']) {
assert.equal(typeof C[fn], 'function', fn + ' определён');
assert.equal(C[fn]({}), null, fn + ' заглушка возвращает null');
}
@@ -113,7 +113,7 @@ test('каждая глава существует, ссылается на ха
const html = fs.readFileSync(path.join(TB, ch.file), 'utf8');
assert.ok(html.includes('/textbook/chemistry-8"'), ch.file + ' ссылка назад в хаб');
assert.ok(html.includes('/js/chem8_svg.js'), ch.file + ' подключает chem8_svg');
if (['chemistry-8-intro', 'chemistry-8-ch1', 'chemistry-8-ch2', 'chemistry-8-ch3', 'chemistry-8-ch4'].includes(ch.slug)) {
if (['chemistry-8-intro', 'chemistry-8-ch1', 'chemistry-8-ch2', 'chemistry-8-ch3', 'chemistry-8-ch4', 'chemistry-8-ch5'].includes(ch.slug)) {
// перестроены на движок (SPA): slug задаётся через CHEM8_CFG
assert.ok(html.includes("slug:'" + ch.slug + "'"), ch.file + ' slug в CHEM8_CFG');
assert.ok(html.includes('/js/chem8_engine.js'), ch.file + ' подключает движок');
@@ -186,6 +186,17 @@ test('Phase 5 — Глава 4 построена + bondType корректен'
assert.equal(C.bondClass('Na', 'Cl').type, 'ионная');
});
test('Phase 6 — Глава 5 построена + oxStates корректен', () => {
const html = fs.readFileSync(path.join(TB, 'chemistry_8_ch5.html'), 'utf8');
for (let i = 42; i <= 45; i++) assert.ok(html.includes('id="sec-p' + i + '"'), '§' + i + ' секция');
assert.ok(html.includes('id="c-ox"'), 'калькулятор с.о. §42');
assert.ok(html.includes('id="c-redox-pick"'), 'электронный баланс §44');
assert.ok(html.includes('/js/chem8_ch5_widgets.js'), 'виджеты главы 5');
assert.equal(C.oxStates('H2SO4').S, 6, 'S в H₂SO₄ = +6');
assert.equal(C.oxStates('KMnO4').Mn, 7, 'Mn в KMnO₄ = +7');
assert.equal(C.oxStates('HNO3').N, 5, 'N в HNO₃ = +5');
});
test('chem8_engine.js и виджеты — валидный синтаксис', () => {
const eng = fs.readFileSync(path.join(ROOT, 'frontend', 'js', 'chem8_engine.js'), 'utf8');
const wid = fs.readFileSync(path.join(ROOT, 'frontend', 'js', 'chem8_intro_widgets.js'), 'utf8');
+58
View File
@@ -0,0 +1,58 @@
/* chem8_ch5_widgets.js — виджеты Главы 5 «Окислительно-восстановительные реакции».
* Использует window.Chem8: oxStateCalc.
*/
(function (W) {
'use strict';
function C() { return W.Chem8 || {}; }
function $(id) { return document.getElementById(id); }
/* §42 — калькулятор степени окисления */
function mount_p42() { var el = $('c-ox'); if (el && !el._b && C().oxStateCalc) { el._b = 1; C().oxStateCalc(el, { formula: 'H2SO4' }); } }
/* §44 — пошаговый электронный баланс (преднабор) */
var R = [
{ eq: '2Mg + O₂ → 2MgO',
steps: [
'Степени окисления: Mg⁰, O₂⁰ → Mg⁺², O⁻².',
'Mg⁰ − 2e⁻ → Mg⁺² — окисление (Mg — восстановитель).',
'O₂⁰ + 4e⁻ → 2O⁻² — восстановление (O₂ — окислитель).',
'Электронный баланс: отдано 2e⁻ (×2 = 4), принято 4e⁻ → множители 2 и 1.',
'Коэффициенты: 2Mg + O₂ → 2MgO. ✓'
] },
{ eq: 'Fe + CuSO₄ → FeSO₄ + Cu',
steps: [
'Меняют с.о. только Fe и Cu: Fe⁰ → Fe⁺², Cu⁺² → Cu⁰.',
'Fe⁰ − 2e⁻ → Fe⁺² — окисление (Fe — восстановитель).',
'Cu⁺² + 2e⁻ → Cu⁰ — восстановление (Cu⁺² — окислитель).',
'Отдано 2e⁻ = принято 2e⁻ → множители 1 и 1.',
'Коэффициенты: Fe + CuSO₄ → FeSO₄ + Cu. ✓'
] },
{ eq: '2Na + Cl₂ → 2NaCl',
steps: [
'Na⁰ и Cl₂⁰ → Na⁺ и Cl⁻.',
'Na⁰ − 1e⁻ → Na⁺ — окисление (Na — восстановитель).',
'Cl₂⁰ + 2e⁻ → 2Cl⁻ — восстановление (Cl₂ — окислитель).',
'Баланс: 1e⁻ ×2 = 2e⁻ → множители 2 и 1.',
'Коэффициенты: 2Na + Cl₂ → 2NaCl. ✓'
] }
];
function mount_p44() {
var pick = $('c-redox-pick'), out = $('c-redox-out'), bStep = $('c-redox-step'), bAll = $('c-redox-all'); if (!pick || pick._b) return; pick._b = 1;
R.forEach(function (p, i) { var o = document.createElement('option'); o.value = i; o.textContent = p.eq; pick.appendChild(o); });
var cur = 0, shown = 0;
function render() {
var p = R[cur];
var html = '<b>' + p.eq + '</b><div style="margin-top:8px">';
for (var i = 0; i < shown; i++) html += '<div class="def-box" style="margin:6px 0">' + p.steps[i] + '</div>';
if (shown === 0) html += '<span style="color:var(--muted)">Нажимай «Следующий шаг» — разберём метод электронного баланса.</span>';
html += '</div>'; out.className = shown >= p.steps.length ? 'out ok' : 'out'; out.innerHTML = html;
}
pick.addEventListener('change', function () { cur = +pick.value; shown = 0; render(); });
bStep.addEventListener('click', function () { if (shown < R[cur].steps.length) { shown++; render(); } });
bAll.addEventListener('click', function () { shown = R[cur].steps.length; render(); });
render();
}
W.CHEM8_WIDGETS = { p42: mount_p42 };
W.FLAG_MOUNTS = { p44: mount_p44 };
})(window);
+58 -3
View File
@@ -747,6 +747,59 @@
return { el: host, update: upd };
}
/* ──────────────────────────────────────────────────────────────────────────
Степень окисления (Phase 6).
oxStates(formula) -> {el: oxidation} для типичных нейтральных соединений.
Правила: F=1, O=−2, H=+1, щелочные=+1, ЩЗМ=+2, Al=+3; галогены=1 без O;
остаток решается из условия Σ(с.о.·индекс)=0. oxStateCalc — виджет.
────────────────────────────────────────────────────────────────────────── */
var OX_FIX = { F:-1, O:-2, H:1, Li:1, Na:1, K:1, Rb:1, Cs:1, Be:2, Mg:2, Ca:2, Sr:2, Ba:2, Al:3, Zn:2, Ag:1 };
function oxStates(formula) {
var c = elementCounts(String(formula || '').replace(/\s+/g, ''));
var keys = Object.keys(c); if (!keys.length) return null;
var hasO = !!c.O, res = {}, unknown = [], sumFixed = 0;
keys.forEach(function (el) {
var v;
if (Object.prototype.hasOwnProperty.call(OX_FIX, el)) v = OX_FIX[el];
else if ((el === 'Cl' || el === 'Br' || el === 'I') && !hasO) v = -1;
else { unknown.push(el); return; }
res[el] = v; sumFixed += v * c[el];
});
if (unknown.length === 1) {
var el = unknown[0];
res[el] = -sumFixed / c[el];
} else if (unknown.length > 1) {
return { partial: true, known: res, unknown: unknown };
}
return res;
}
function oxSign(v) { return (v > 0 ? '+' : v < 0 ? '' : '') + Math.abs(v); }
function oxStateCalc(mount, opts) {
var host = typeof mount === 'string' ? global.document.querySelector(mount) : mount;
if (!host) return null;
opts = opts || {};
host.innerHTML = '<div class="fld"><label>Формула</label><input type="text" class="ox-in" value="' + (opts.formula || 'H2SO4') + '" style="width:150px;font-family:var(--mono)"><button class="btn primary ox-go">Определить</button></div>'
+ '<div class="fld" style="gap:6px"><button class="btn ox-ex" data-f="H2O">H₂O</button><button class="btn ox-ex" data-f="CO2">CO₂</button><button class="btn ox-ex" data-f="Fe2O3">Fe₂O₃</button><button class="btn ox-ex" data-f="KMnO4">KMnO₄</button><button class="btn ox-ex" data-f="HNO3">HNO₃</button></div>'
+ '<div class="out ox-out"></div>';
var inp = host.querySelector('.ox-in'), out = host.querySelector('.ox-out'), go = host.querySelector('.ox-go');
function calc() {
var f = inp.value.trim(), r = oxStates(f);
if (!r) { out.className = 'out ox-out bad'; out.textContent = 'Не удалось разобрать формулу.'; return; }
if (r.partial) {
out.className = 'out ox-out bad';
out.innerHTML = 'Несколько неизвестных элементов (' + r.unknown.join(', ') + ') — для 8 класса возьми более простое соединение.';
return;
}
out.className = 'out ox-out ok';
out.innerHTML = '<span class="bd">' + Object.keys(r).map(function (el) { return el + ': <b>' + oxSign(r[el]) + '</b>'; }).join(' &nbsp; ') + '</span>';
}
go.addEventListener('click', calc);
inp.addEventListener('keydown', function (e) { if (e.key === 'Enter') calc(); });
host.querySelectorAll('.ox-ex').forEach(function (b) { b.addEventListener('click', function () { inp.value = b.dataset.f; calc(); }); });
calc();
return { el: host };
}
/* ---- Каркасы-заглушки интерактивных виджетов (реализуются по фазам) ---- */
function notImplemented(name) {
return function () {
@@ -788,9 +841,11 @@
bondType: bondType, // §37,38 — ЭО → тип связи
bondClass: bondClass, // классификация связи по ΔЭО
enOf: enOf, // электроотрицательность
// заглушки (см. план, разд. B) — наполняются в Phase 5–6
oxStateCalc: notImplemented('oxStateCalc'), // §42 — калькулятор степени окисления
redoxBalancer: notImplemented('redoxBalancer'), // §44 — e-баланс ОВР
// готово (Phase 6 — ОВР)
oxStateCalc: oxStateCalc, // §42 — калькулятор степени окисления
oxStates: oxStates, // степени окисления (чистая функция)
// заглушки (см. план, разд. B) — наполняются позже
redoxBalancer: notImplemented('redoxBalancer'), // §44 — e-баланс ОВР (пошагово в ch5)
orbitalDiagram: notImplemented('orbitalDiagram'), // §33 — орбитальная диаграмма
dissociationAnim: notImplemented('dissociationAnim'),// §47 — анимация растворения
geneticMap: notImplemented('geneticMap') // §22 — генетическая карта-граф классов
+146 -96
View File
@@ -7,127 +7,177 @@
<meta http-equiv="Expires" content="0">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Химия 8 · Глава 5 · «Окислительно-восстановительные реакции»</title>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800;900&family=Inter:wght@400;500;600;700&family=Unbounded:wght@700;800;900&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800;900&family=Inter:wght@400;500;600;700&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<link rel="stylesheet" href="/css/chem8-textbook.css">
<style>
/* Глава 5 — orange */
:root{ --pri:#ea580c; --pri-d:#c2410c; --pri-l:#fb923c; --pri-soft:#ffedd5; --sec-acc:#ea580c; --sec-acc-d:#c2410c; --sec-acc-soft:#ffedd5; }
html.dark{ --bg:#1c1208; --card:#2a1c10; --card-soft:#33240f; --text:#ffedd5; --muted:#fdba74; --border:#4a3115; --pri-soft:rgba(234,88,12,.22); --sec-acc-soft:rgba(234,88,12,.22); }
.hdr{background:linear-gradient(110deg,#9a3412 0%,#ea580c 55%,#fb923c 100%)}
.hdr::before{content:'ГЛАВА 5'}
</style>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"></script>
<script src="/js/api.js" defer></script>
<script src="/js/xp.js" defer></script>
<script src="/js/biochem-core.js" defer></script>
<script src="/js/chem8_svg.js" defer></script>
<style>
:root{
--bg:#fffbeb; --card:#fff; --text:#1c1917; --muted:#78716c; --border:#e7e5e4;
--pri:#ea580c; --pri-d:#c2410c; --pri-l:#fb923c; --pri-soft:#ffedd5;
--sh:0 4px 16px rgba(0,0,0,.06); --sh-h:0 12px 32px rgba(0,0,0,.12);
}
html.dark{ --bg:#1c1208; --card:#2a1c10; --text:#ffedd5; --muted:#a8a29e; --border:#3a3026; --pri-soft:rgba(0,0,0,.2); }
*{margin:0;padding:0;box-sizing:border-box}
html,body{min-height:100vh}
body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.55;transition:background .25s,color .25s}
.ic{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.hdr{position:relative;background:linear-gradient(110deg,#c2410c 0%,#ea580c 55%,#fb923c 100%);color:#fff;padding:34px 24px 30px;overflow:hidden;border-bottom:2px solid rgba(255,255,255,.18)}
.hdr::before{content:'ГЛАВА 5';position:absolute;right:-12px;top:50%;transform:translateY(-50%);font-family:'Unbounded',sans-serif;font-size:clamp(4rem,13vw,10rem);font-weight:900;letter-spacing:-.04em;color:transparent;-webkit-text-stroke:1.5px rgba(255,255,255,.13);line-height:1;pointer-events:none;user-select:none;z-index:0}
.hdr-inner{position:relative;z-index:1;max-width:1000px;margin:0 auto;display:flex;align-items:center;gap:16px;flex-wrap:wrap}
.hdr-back{display:inline-flex;align-items:center;gap:8px;padding:8px 14px;background:rgba(255,255,255,.16);border-radius:9px;color:#fff;text-decoration:none;font-size:.85rem;font-weight:600;transition:background .15s}
.hdr-back:hover{background:rgba(255,255,255,.26)}
.hdr-kicker{font-size:.72rem;font-weight:800;text-transform:uppercase;letter-spacing:.14em;opacity:.85}
.hdr h1{font-family:'Outfit',sans-serif;font-size:1.55rem;font-weight:900;letter-spacing:-.01em;line-height:1.25;margin-top:3px}
.hdr-side{margin-left:auto}
.hdr-btn{padding:8px 12px;background:rgba(255,255,255,.16);border:none;color:#fff;border-radius:9px;cursor:pointer;font-weight:600;font-size:.82rem;display:inline-flex;align-items:center;gap:6px;transition:background .15s;font-family:inherit}
.hdr-btn:hover{background:rgba(255,255,255,.26)}
main{max-width:1000px;margin:0 auto;padding:28px 24px 60px}
.wip{display:flex;gap:14px;align-items:flex-start;background:linear-gradient(135deg,var(--pri-soft),rgba(0,0,0,.02));border:1.5px dashed var(--pri);border-radius:16px;padding:18px 20px;margin-bottom:26px}
.wip-ic{width:42px;height:42px;border-radius:11px;background:var(--pri);color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.wip-ic svg{width:22px;height:22px;stroke:#fff;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.wip h2{font-family:'Outfit',sans-serif;font-size:1.05rem;color:var(--pri-d);margin-bottom:4px}
html.dark .wip h2{color:var(--pri-l)}
.wip p{font-size:.9rem;color:var(--muted);line-height:1.55}
.ol-title{font-family:'Outfit',sans-serif;font-size:1.15rem;font-weight:800;margin:6px 0 14px;display:flex;align-items:center;gap:9px}
.ol-title svg{width:20px;height:20px;stroke:var(--pri);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.ol-list{list-style:none;background:var(--card);border:1px solid var(--border);border-radius:14px;overflow:hidden;box-shadow:var(--sh)}
.ol-para,.ol-note{display:flex;gap:12px;align-items:baseline;padding:12px 18px;border-bottom:1px solid var(--border)}
.ol-list li:last-child{border-bottom:0}
.ol-num{flex-shrink:0;min-width:46px;font-weight:800;color:var(--pri);font-size:.92rem}
.ol-name{font-size:.94rem;color:var(--text)}
.ol-note{background:var(--pri-soft);align-items:center;gap:10px}
.ol-note-ic{display:inline-flex;color:var(--pri-d)}
html.dark .ol-note-ic{color:var(--pri-l)}
.ol-note-ic svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.ol-note span:last-child{font-size:.88rem;font-weight:600;color:var(--pri-d)}
html.dark .ol-note span:last-child{color:var(--pri-l)}
.foot{text-align:center;padding:24px 16px;color:var(--muted);font-size:.78rem;border-top:1px solid var(--border);margin-top:30px}
</style>
<script src="/js/chem8_ch5_widgets.js" defer></script>
<script src="/js/chem8_engine.js" defer></script>
</head>
<body>
<header class="hdr">
<div class="hdr-inner">
<a href="/textbook/chemistry-8" class="hdr-back">
<svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>
К разделам
</a>
<div class="hdr-row">
<div>
<div class="hdr-kicker">Глава 5 &middot; § 4245</div>
<h1>Окислительно-восстановительные реакции</h1>
<h1>Химия 8 · Глава 5</h1>
<div class="hdr-sub">Степень окисления, процессы окисления и восстановления, ОВР и метод электронного баланса</div>
</div>
<div class="hdr-side">
<button id="theme-btn" class="hdr-btn" title="Сменить тему">
<svg class="ic" viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg>
<span id="theme-lab">Тёмная</span>
</button>
<a href="/textbook/chemistry-8" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К разделам</a>
<button id="theme-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg><span id="theme-lab">Тёмная</span></button>
</div>
</div>
</header>
<main>
<section class="wip">
<div class="wip-ic">
<svg viewBox="0 0 24 24"><path d="M14.7 6.3a4 4 0 0 0-5.4 5.4l-6.3 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l6.3-6.3a4 4 0 0 0 5.4-5.4l-2.6 2.6-2-2 2.6-2.6z"/></svg>
</div>
<div>
<h2>Раздел в разработке</h2>
<p>Интерактивное наглядное наполнение этого раздела (теория, модели, симуляторы, тренажёры и боссы) добавляется поэтапно. Ниже — план параграфов раздела согласно учебнику.</p>
</div>
</section>
<main class="main">
<div class="col-main">
<section class="hero">
<h2>Реакции, в которых электроны меняют хозяина</h2>
<p>Горение, ржавление, дыхание, работа батарейки — всё это окислительно-восстановительные реакции. В них одни атомы отдают электроны, другие принимают, и степени окисления меняются.</p>
<div class="hero-row">
<button class="btn-primary" onclick="goTo('p42')"><svg class="ic" viewBox="0 0 24 24"><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></svg> Начать § 42</button>
<div class="hero-progress"><span class="hp-label">Прогресс главы</span><div class="hp-bar"><div id="hero-hp-fill" class="hp-fill"></div></div><span id="hero-hp-text" class="hp-text">0%</span></div>
<div id="hero-xp-badge" class="hero-xp-badge"></div>
</div>
</section>
<div class="ol-title">
<svg viewBox="0 0 24 24"><path d="M4 6h16M4 12h16M4 18h10"/></svg>
Содержание раздела
<section class="psel"><div class="psel-title">Параграфы главы</div><div id="psel-grid" class="psel-grid"></div></section>
<section id="sec-p42" class="sec"><div class="sec-header"><span class="sec-num">§ 42</span><h2 class="sec-h">Степень окисления</h2></div><div id="p42-body"></div></section>
<section id="sec-p43" class="sec"><div class="sec-header"><span class="sec-num">§ 43</span><h2 class="sec-h">Процессы окисления и восстановления</h2></div><div id="p43-body"></div></section>
<section id="sec-p44" class="sec"><div class="sec-header"><span class="sec-num">§ 44</span><h2 class="sec-h">Окислительно-восстановительные реакции</h2></div><div id="p44-body"></div></section>
<section id="sec-p45" class="sec"><div class="sec-header"><span class="sec-num">§ 45</span><h2 class="sec-h">Окислительно-восстановительные реакции вокруг нас</h2></div><div id="p45-body"></div></section>
<section id="sec-final1" class="sec"><div class="sec-header"><span class="sec-num"></span><h2 class="sec-h">Финал главы</h2></div><div id="final1-body"></div></section>
</div>
<ul class="ol-list">
<li class="ol-para"><span class="ol-num">§ 42</span><span class="ol-name">Степень окисления</span></li>
<li class="ol-para"><span class="ol-num">§ 43</span><span class="ol-name">Процессы окисления и восстановления</span></li>
<li class="ol-para"><span class="ol-num">§ 44</span><span class="ol-name">Окислительно-восстановительные реакции</span></li>
<li class="ol-para"><span class="ol-num">§ 45</span><span class="ol-name">Окислительно-восстановительные реакции вокруг нас</span></li>
</ul>
<aside class="col-side"><div id="sidebar-content"></div></aside>
</main>
<footer class="foot">
Интерактивный учебник «Химия — 8 класс» &middot; Глава 5 &middot; LearnSpace
</footer>
<footer class="foot">Интерактивный учебник «Химия — 8 класс» · Глава 5 · «Окислительно-восстановительные реакции» · LearnSpace</footer>
<div id="ach-popup" class="ach-popup"><svg viewBox="0 0 24 24"><polygon points="12 2 22 20 2 20"/></svg><span id="ach-text">Достижение!</span></div>
<script>
'use strict';
const _TB_SLUG = 'chemistry-8-ch5';
(function(){
var saved = localStorage.getItem('chemistry8_theme') || localStorage.getItem('theme') || 'light';
if (saved === 'dark') document.documentElement.classList.add('dark');
var lab = document.getElementById('theme-lab');
if (lab) lab.textContent = saved === 'dark' ? 'Светлая' : 'Тёмная';
document.getElementById('theme-btn').addEventListener('click', function(){
document.documentElement.classList.toggle('dark');
var dark = document.documentElement.classList.contains('dark');
localStorage.setItem('chemistry8_theme', dark ? 'dark' : 'light');
localStorage.setItem('theme', dark ? 'dark' : 'light');
if (lab) lab.textContent = dark ? 'Светлая' : 'Тёмная';
});
})();
window.CHEM8_CFG = { slug:'chemistry-8-ch5', themeKey:'chemistry8_theme', xpKey:'chemistry8_xp', progKey:'chemistry8_ch5_progress', achKey:'chemistry8_ch5_ach' };
window.PARAS = [
{id:'p42',num:'§ 42',name:'Степень окисления',sub:'+/ на атоме'},
{id:'p43',num:'§ 43',name:'Окисление и восстановление',sub:'отдал/принял e⁻'},
{id:'p44',num:'§ 44',name:'ОВР',sub:'электронный баланс'},
{id:'p45',num:'§ 45',name:'ОВР вокруг нас',sub:'горение, коррозия'},
{id:'final1',num:'★',name:'Финал главы',sub:'босс · ачивка',final:true}
];
window.ACH_LABELS = { start:'Начало главы 5!', final1_tasks:'ОВР освоены!' };
['p42','p43','p44','p45'].forEach(function(id){ window.ACH_LABELS[id+'_done']=id.toUpperCase()+' изучен!'; });
window.SIDEBARS = {
p42:{title:'§42 С.о.',rows:[['С.о.','условный заряд атома'],['H','+1 (обычно)'],['O','2 (обычно)'],['Σ','с.о. = 0 (молекула)']]},
p43:{title:'§43 Окисл./восст.',rows:[['Окисление','отдача e⁻ (с.о. ↑)'],['Восстановление','приём e⁻ (с.о. ↓)'],['Восстановитель','отдаёт e⁻'],['Окислитель','принимает e⁻']]},
p44:{title:'§44 ОВР',rows:[['ОВР','меняются с.о.'],['Метод','электронный баланс'],['Баланс','отдано e⁻ = принято e⁻']]},
p45:{title:'§45 Вокруг нас',rows:[['Горение','+ O₂'],['Коррозия','ржавление Fe'],['Батарейка','ток из ОВР'],['Дыхание','окисление глюкозы']]},
final1:{title:'Финал главы 5',rows:[['§§4245','ОВР'],['Награда','ачивка + XP']]}
};
window.TIPS = [
{sec:'p42',html:'Степень окисления — условный заряд атома. H обычно +1, O обычно −2, сумма с.о. в молекуле = 0.'},
{sec:'p43',html:'Окисление — отдача электронов (с.о. растёт). Восстановление — приём электронов (с.о. падает).'},
{sec:'p44',html:'В ОВР число отданных электронов = числу принятых (метод электронного баланса).'},
{sec:'p45',html:'Горение, коррозия, дыхание, работа батарейки — всё это ОВР.'},
{sec:'final1',html:'С.о., окислитель/восстановитель, электронный баланс — повтори перед боссом.'}
];
window.POOLS = {
p42:[
{q:'Степень окисления — это…',opts:['Масса атома','Условный заряд атома в соединении','Число нейтронов','Валентность ядра'],a:1,ex:'Условный заряд, который был бы у атома, если все связи ионные.'},
{q:'Степень окисления кислорода в большинстве соединений:',opts:['+2','2','0','+6'],a:1,ex:'O обычно 2.'},
{q:'Степень окисления серы в H₂SO₄:',hint:'H +1, O 2, Σ=0',unit:'',a:6,ex:'2·(+1)+S+4·(2)=0 → S=+6.'},
{q:'Степень окисления любого простого вещества (O₂, Fe) равна…',hint:'',unit:'',a:0,ex:'У простых веществ с.о. = 0.'}
],
p43:[
{q:'Окисление — это процесс…',opts:['Приёма электронов','Отдачи электронов','Распада ядра','Растворения'],a:1,ex:'Окисление — отдача e⁻ (с.о. растёт).'},
{q:'Восстановитель в реакции…',opts:['Принимает e⁻','Отдаёт e⁻','Не меняется','Распадается'],a:1,ex:'Восстановитель отдаёт электроны (сам окисляется).'},
{q:'Окислитель — это частица, которая…',opts:['Отдаёт e⁻','Принимает e⁻','Растворяется','Испаряется'],a:1,ex:'Окислитель принимает электроны (сам восстанавливается).'}
],
p44:[
{q:'В основе ОВР лежит…',opts:['Обмен ионами','Переход электронов','Обмен молекулами','Изменение цвета'],a:1,ex:'Переход электронов между частицами.'},
{q:'Метод электронного баланса требует, чтобы…',opts:['Масса росла','Число отданных e⁻ = числу принятых','Объём не менялся','Цвет совпадал'],a:1,ex:'Отдано e⁻ = принято e⁻.'},
{q:'В реакции 2Mg + O₂ → 2MgO магний…',opts:['Окислитель','Восстановитель','Не участвует','Катализатор'],a:1,ex:'Mg отдаёт электроны → восстановитель.'}
],
p45:[
{q:'Что из перечисленного НЕ является ОВР?',opts:['Горение угля','Ржавление железа','Растворение соли в воде','Работа батарейки'],a:2,ex:'Растворение соли — без изменения с.о.'},
{q:'При ржавлении железа Fe…',opts:['Принимает e⁻','Отдаёт e⁻','Не меняется','Испаряется'],a:1,ex:'Fe окисляется (отдаёт e⁻), с.о. растёт.'},
{q:'Источник тока в батарейке — это…',opts:['Реакция обмена','ОВР','Растворение','Плавление'],a:1,ex:'Ток возникает за счёт ОВР.'}
],
final1:[
{q:'С.о. азота в HNO₃:',hint:'H +1, O 2',unit:'',a:5,ex:'+1+N+3·(2)=0 → N=+5.'},
{q:'Окисление — это…',opts:['Приём e⁻','Отдача e⁻','Распад','Растворение'],a:1,ex:'Отдача электронов.'},
{q:'В 2Na + Cl₂ → 2NaCl хлор является…',opts:['Восстановителем','Окислителем','Катализатором','Растворителем'],a:1,ex:'Cl₂ принимает e⁻ → окислитель.'},
{q:'С.о. простого вещества равна…',hint:'',unit:'',a:0,ex:'0.'},
{q:'С.о. марганца в KMnO₄:',hint:'K +1, O 2',unit:'',a:7,ex:'+1+Mn+4·(2)=0 → Mn=+7.'},
{q:'Сколько электронов отдаёт Mg при окислении до Mg⁺²?',hint:'',unit:'',a:2,ex:'2 электрона.'}
]
};
function rememberBox(items){ return '<div class="remember-box"><div class="remember-box-title"><svg class="ic" viewBox="0 0 24 24" style="width:15px;height:15px"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg> Запомни!</div><ul>'+items.map(function(t){return '<li>'+t+'</li>';}).join('')+'</ul></div>'; }
function qList(items){ return '<div class="section-title">Вопросы и задания</div><ol class="q-list">'+items.map(function(t){return '<li>'+t+'</li>';}).join('')+'</ol>'; }
function flag(title, help, inner){ return '<div class="flag-card"><div class="flag-title">'+title+'</div><div class="flag-help">'+help+'</div>'+inner+'</div>'; }
function wgt(title, inner){ return '<div class="wgt"><div class="wgt-h"><svg class="ic" viewBox="0 0 24 24"><path d="M4 7h16M4 12h16M4 17h10"/></svg> '+title+'</div>'+inner+'</div>'; }
function hero(ph,label,title,formula,desc,tags){ return '<div class="para-hero ph-'+ph+'"><div class="ph-label">'+label+'</div><h2>'+title+'</h2>'+(formula?'<div class="ph-formula">'+formula+'</div>':'')+'<div class="ph-desc">'+desc+'</div>'+(tags?'<div class="ph-tags">'+tags.map(function(t){return '<span class="ph-tag">'+t+'</span>';}).join('')+'</div>':'')+'</div>'; }
window.BUILDERS = { p42:bp42, p43:bp43, p44:bp44, p45:bp45, final1:bfinal };
function bp42(){ document.getElementById('p42-body').innerHTML =
hero(6,'§ 42 · Глава 5','Степень окисления','с.о.','Условный заряд атома, который помогает «считать» электроны в соединениях.',['с.о.','H +1','O 2'])
+makeCard('theory','Что такое степень окисления','§42','<div class="def-box"><b>Степень окисления</b> — условный заряд атома в соединении, вычисленный из предположения, что все связи ионные.</div><p>Правила: у простых веществ с.о. = 0; водород обычно <b>+1</b>, кислород обычно <b>2</b>; сумма степеней окисления в молекуле равна <b>0</b>. По этим правилам находят с.о. остальных элементов.</p>')
+flag('Калькулятор степени окисления','Введи формулу — определятся степени окисления всех элементов.','<div id="c-ox"></div>')
+rememberBox(['У простого вещества с.о. = 0.','H → +1, O → 2 (как правило).','Сумма с.о. в нейтральной молекуле = 0.'])
+qList(['Найди с.о. серы в SO₃.','Чему равна с.о. железа в Fe₂O₃?'])
+secNav(null,'p43')+readButton('p42'); wireReadBtn('p42'); }
function bp43(){ document.getElementById('p43-body').innerHTML =
hero(5,'§ 43 · Глава 5','Процессы окисления и восстановления','отдал / принял e⁻','Два процесса, которые всегда идут вместе: один атом отдаёт электроны, другой их принимает.',['окисление','восстановление'])
+makeCard('theory','Окисление и восстановление','§43','<p><b>Окисление</b> — отдача электронов, степень окисления <b>повышается</b>.<br><b>Восстановление</b> — приём электронов, степень окисления <b>понижается</b>.</p><div class="def-box"><b>Восстановитель</b> отдаёт электроны (сам окисляется). <b>Окислитель</b> принимает электроны (сам восстанавливается).</div>')
+'<div class="wgt"><div class="wgt-h"><svg class="ic" viewBox="0 0 24 24"><path d="M3 12h18"/></svg> Кто есть кто</div><div class="lat-grid"><div class="lat-card"><h4>Восстановитель</h4><ul><li>отдаёт e⁻</li><li>с.о. растёт</li><li>сам окисляется</li><li>пример: Mg⁰ → Mg⁺²</li></ul></div><div class="lat-card"><h4>Окислитель</h4><ul><li>принимает e⁻</li><li>с.о. падает</li><li>сам восстанавливается</li><li>пример: O₂⁰ → O⁻²</li></ul></div></div></div>'
+rememberBox(['Окисление — отдача e⁻ (с.о. ↑); восстановление — приём e⁻ (с.о. ↓).','Восстановитель окисляется, окислитель восстанавливается.'])
+qList(['Что происходит со степенью окисления при окислении?','Кто отдаёт электроны — окислитель или восстановитель?'])
+secNav('p42','p44')+readButton('p43'); wireReadBtn('p43'); }
function bp44(){ document.getElementById('p44-body').innerHTML =
hero(8,'§ 44 · Глава 5','Окислительно-восстановительные реакции','электронный баланс','Реакции с переходом электронов уравнивают особым методом — электронным балансом.',['ОВР','баланс e⁻'])
+makeCard('theory','Метод электронного баланса','§44','<p><b>ОВР</b> — реакции, в которых меняются степени окисления (происходит переход электронов). Их уравнивают <b>методом электронного баланса</b>:</p><ol><li>Определить с.о. и найти, кто отдаёт, а кто принимает электроны.</li><li>Записать полуреакции: сколько e⁻ отдано и принято.</li><li>Подобрать множители так, чтобы <b>отдано e⁻ = принято e⁻</b>.</li><li>Перенести множители в уравнение как коэффициенты.</li></ol>')
+flag('Пошаговый электронный баланс','Выбери реакцию и разбери метод по шагам.','<div class="fld"><label>Реакция</label><select id="c-redox-pick"></select></div><div class="out" id="c-redox-out"></div><div class="fld"><button class="btn" id="c-redox-step">Следующий шаг ▸</button><button class="btn" id="c-redox-all">Показать всё</button></div>')
+rememberBox(['ОВР = изменение степеней окисления.','Главное правило: отдано e⁻ = принято e⁻.'])
+qList(['Кто восстановитель в 2Mg + O₂ → 2MgO?','Сколько электронов принимает O₂ в этой реакции?'])
+secNav('p43','p45')+readButton('p44'); wireReadBtn('p44'); }
function bp45(){ document.getElementById('p45-body').innerHTML =
hero(9,'§ 45 · Глава 5','ОВР вокруг нас','горение · коррозия · ток','ОВР — не абстракция: они греют, двигают, питают и, увы, разрушают.',['горение','коррозия','батарейка'])
+makeCard('theory','ОВР в жизни','§45','<p>Окислительно-восстановительные реакции окружают нас повсюду:</p>'
+'<div class="lat-grid">'
+'<div class="lat-card"><h4>Горение</h4><ul><li>топливо + O₂</li><li>выделяется тепло</li><li>C + O₂ → CO₂</li></ul></div>'
+'<div class="lat-card"><h4>Коррозия</h4><ul><li>ржавление железа</li><li>Fe → Fe₂O₃·nH₂O</li><li>разрушает металл</li></ul></div>'
+'<div class="lat-card"><h4>Дыхание</h4><ul><li>окисление глюкозы</li><li>даёт энергию клеткам</li></ul></div>'
+'<div class="lat-card"><h4>Батарейка</h4><ul><li>ток из ОВР</li><li>энергия реакции → электричество</li></ul></div>'
+'</div>')
+rememberBox(['Горение, дыхание, коррозия, батарейки — это ОВР.','Растворение соли — НЕ ОВР (с.о. не меняется).'])
+qList(['Приведи три примера ОВР из жизни.','Почему растворение сахара — не ОВР?'])
+secNav('p44','final1')+readButton('p45'); wireReadBtn('p45'); }
function bfinal(){ document.getElementById('final1-body').innerHTML =
hero('final','Финал главы 5','Босс: ОВР','с.о. · окислитель/восстановитель · баланс','Шесть интегрированных задач по всей главе. Победи босса — ачивка «ОВР освоены».')
+makeCard('rule','Шпаргалка главы',null,'<div class="formula-grid"><div class="fcard"><h3>С.о.</h3><div class="main-f">H +1, O 2, Σ=0</div></div><div class="fcard"><h3>Окисление</h3><div class="main-f">e⁻, с.о. ↑</div></div><div class="fcard"><h3>Восстановление</h3><div class="main-f">+e⁻, с.о. ↓</div></div><div class="fcard highlight"><h3>Баланс</h3><div class="main-f">отдано = принято</div></div></div>')
+'<p style="margin:10px 0;color:var(--muted);font-size:.9rem">Реши все задачи — за каждую +5 XP, за победу — ачивка и бонус.</p>'
+secNav('p45',null); }
</script>
</body>