diff --git a/backend/tests/chemistry8-page.test.js b/backend/tests/chemistry8-page.test.js index 437eed7..3ab7f5c 100644 --- a/backend/tests/chemistry8-page.test.js +++ b/backend/tests/chemistry8-page.test.js @@ -117,3 +117,15 @@ test('ch3: нуклид §30 и паспорт §35 монтируются', asy doc.defaultView.goTo('p35'); await wait(120); assert.ok(doc.querySelectorAll('#c-passport .pt-cell').length > 80, 'ПСХЭ паспорта §35'); }); + +/* ── Глава 4 ── */ +test('ch4: SPA без ошибок, 7 карточек, §36 активен, тип связи', async () => { + const { doc, errors } = await loadDom('chemistry_8_ch4.html', '/js/chem8_ch4_widgets.js'); + assert.deepEqual(errors, [], 'нет ошибок: ' + errors.join(' | ')); + assert.equal(doc.querySelectorAll('#psel-grid .psel-card').length, 7, '6 § + финал'); + assert.ok(doc.querySelector('.sec.active') && doc.querySelector('.sec.active').id === 'sec-p36', '§36 активен'); + doc.defaultView.goTo('p37'); await wait(120); + assert.ok(doc.querySelector('#c-bond1 .bt-svg'), 'виджет типа связи §37'); + doc.defaultView.goTo('p38'); await wait(120); + assert.ok(doc.querySelector('#c-bond2 .bt-out'), 'виджет полярности §38'); +}); diff --git a/backend/tests/chemistry8.test.js b/backend/tests/chemistry8.test.js index b105305..7d58d42 100644 --- a/backend/tests/chemistry8.test.js +++ b/backend/tests/chemistry8.test.js @@ -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'].includes(ch.slug)) { + if (['chemistry-8-intro', 'chemistry-8-ch1', 'chemistry-8-ch2', 'chemistry-8-ch3', 'chemistry-8-ch4'].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 + ' подключает движок'); @@ -175,6 +175,17 @@ test('Phase 4 — Глава 3 построена + atomShell/shellConfig кор assert.equal(C.zSym(17), 'Cl', 'Z=17 → Cl'); }); +test('Phase 5 — Глава 4 построена + bondType корректен', () => { + const html = fs.readFileSync(path.join(TB, 'chemistry_8_ch4.html'), 'utf8'); + for (let i = 36; i <= 41; i++) assert.ok(html.includes('id="sec-p' + i + '"'), '§' + i + ' секция'); + assert.ok(html.includes('id="c-bond1"'), 'тип связи §37'); + assert.ok(html.includes('Лабораторный опыт 4'), 'Лаб.4'); + assert.ok(html.includes('/js/chem8_ch4_widgets.js'), 'виджеты главы 4'); + assert.equal(C.bondClass('H', 'H').type, 'ковалентная неполярная'); + assert.equal(C.bondClass('H', 'Cl').type, 'ковалентная полярная'); + assert.equal(C.bondClass('Na', 'Cl').type, 'ионная'); +}); + 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'); diff --git a/frontend/css/chem8-textbook.css b/frontend/css/chem8-textbook.css index 847c092..382dd67 100644 --- a/frontend/css/chem8-textbook.css +++ b/frontend/css/chem8-textbook.css @@ -376,6 +376,20 @@ html.dark .passport h4{color:var(--pri-l)} .passport-grid div{padding:6px 9px;background:var(--card);border:1px solid var(--border);border-radius:8px} .passport-grid b{color:var(--pri-d)}html.dark .passport-grid b{color:var(--pri-l)} +/* тип связи (§37,38) */ +.bt-svg{width:100%;max-width:280px;height:auto;color:var(--text);display:block;margin:8px auto} +.bt-stage{display:flex;justify-content:center} +.bt-out.ok{background:var(--ok-bg);border-color:#86efac} +.bt-out.bad{background:var(--fail-bg);border-color:#fca5a5} + +/* решётки (§41) */ +.lat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;margin:10px 0} +.lat-card{border:1.5px solid var(--border);border-radius:12px;padding:13px 15px;background:var(--card-soft)} +.lat-card h4{font-family:'Outfit';font-weight:800;font-size:.92rem;margin-bottom:6px;color:var(--pri-d)} +html.dark .lat-card h4{color:var(--pri-l)} +.lat-card .lat-ex{font-family:var(--mono);font-size:.82rem;color:var(--muted);margin-bottom:4px} +.lat-card ul{margin:4px 0 0 16px;font-size:.82rem} + /* орбитали (§32) — статичные SVG */ .orb-row{display:flex;gap:18px;flex-wrap:wrap;justify-content:center;margin:10px 0} .orb-item{text-align:center} diff --git a/frontend/js/chem8_ch4_widgets.js b/frontend/js/chem8_ch4_widgets.js new file mode 100644 index 0000000..674fb31 --- /dev/null +++ b/frontend/js/chem8_ch4_widgets.js @@ -0,0 +1,14 @@ +/* chem8_ch4_widgets.js — виджеты Главы 4 «Химическая связь». + * Использует window.Chem8: bondType. + */ +(function (W) { + 'use strict'; + function C() { return W.Chem8 || {}; } + function $(id) { return document.getElementById(id); } + + function mount_p37() { var el = $('c-bond1'); if (el && !el._b && C().bondType) { el._b = 1; C().bondType(el, { a: 'H', b: 'H' }); } } + function mount_p38() { var el = $('c-bond2'); if (el && !el._b && C().bondType) { el._b = 1; C().bondType(el, { a: 'H', b: 'Cl' }); } } + + W.CHEM8_WIDGETS = {}; + W.FLAG_MOUNTS = { p37: mount_p37, p38: mount_p38 }; +})(window); diff --git a/frontend/js/chem8_svg.js b/frontend/js/chem8_svg.js index 60954a9..daba5d3 100644 --- a/frontend/js/chem8_svg.js +++ b/frontend/js/chem8_svg.js @@ -690,6 +690,63 @@ return { el: host, draw: draw }; } + /* ────────────────────────────────────────────────────────────────────────── + Химическая связь (Phase 5). + EN — электроотрицательность (Полинг, школьные значения). bondClass(da,db) + по разнице ЭО → тип связи. bondType(mount) — интерактивный виджет. + ────────────────────────────────────────────────────────────────────────── */ + var EN = { + H:2.1, Li:1.0, Be:1.5, B:2.0, C:2.5, N:3.0, O:3.5, F:4.0, + Na:0.9, Mg:1.2, Al:1.5, Si:1.8, P:2.1, S:2.5, Cl:3.0, + K:0.8, Ca:1.0, Br:2.8, I:2.5, Zn:1.6, Fe:1.8, Cu:1.9, Ag:1.9 + }; + function enOf(sym) { return EN[sym] != null ? EN[sym] : 2.0; } + function bondClass(a, b) { + var d = Math.abs(enOf(a) - enOf(b)); + if (a !== b && (a in EN) && (b in EN) && enOf(a) <= 1.6 && enOf(b) <= 1.6) { + // два металла → металлическая + if (METALS_EN[a] && METALS_EN[b]) return { type: 'металлическая', cls: 'warn', d: d }; + } + if (d >= 1.7) return { type: 'ионная', cls: 'bad', d: d }; + if (d < 0.4) return { type: 'ковалентная неполярная', cls: 'good', d: d }; + return { type: 'ковалентная полярная', cls: 'mid', d: d }; + } + var METALS_EN = { Li:1, Be:1, Na:1, Mg:1, Al:1, K:1, Ca:1, Zn:1, Fe:1, Cu:1, Ag:1 }; + + function bondType(mount, opts) { + var host = typeof mount === 'string' ? global.document.querySelector(mount) : mount; + if (!host) return null; + opts = opts || {}; + var syms = Object.keys(EN); + function optList(sel) { return syms.map(function (s) { return ''; }).join(''); } + host.innerHTML = '
' + + '
' + + '
'; + var sa = host.querySelector('.bt-a'), sb = host.querySelector('.bt-b'), stage = host.querySelector('.bt-stage'), out = host.querySelector('.bt-out'); + function upd() { + var a = sa.value, b = sb.value, r = bondClass(a, b), d = Math.round(r.d * 10) / 10; + // δ-заряды: более ЭО атом — δ− + var aMore = enOf(a) > enOf(b), polar = r.type.indexOf('полярная') >= 0; + var da = (r.type === 'ионная') ? (aMore ? '−' : '+') : (polar ? (aMore ? 'δ−' : 'δ+') : ''); + var db = (r.type === 'ионная') ? (aMore ? '+' : '−') : (polar ? (aMore ? 'δ+' : 'δ−') : ''); + var color = r.cls === 'good' ? 'var(--ok)' : r.cls === 'bad' ? 'var(--fail)' : 'var(--pri)'; + stage.innerHTML = '' + + '' + + '' + + '' + + '' + a + '' + + '' + b + '' + + (da ? '' + da + '' : '') + + (db ? '' + db + '' : '') + + ''; + out.className = 'out bt-out ' + (r.cls === 'good' ? 'ok' : r.cls === 'bad' ? 'bad' : ''); + out.innerHTML = 'ΔЭО = |' + enOf(a) + ' − ' + enOf(b) + '| = ' + d + ' → связь ' + r.type + '' + + (r.type === 'ионная' ? '
Электрон полностью переходит к более электроотрицательному атому.' : polar ? '
Общая пара смещена к более электроотрицательному атому (' + (aMore ? a : b) + ').' : r.type.indexOf('металл') >= 0 ? '
Общие электроны принадлежат всем атомам («электронный газ»).' : '
Общая пара поделена поровну.') + '
'; + } + sa.addEventListener('change', upd); sb.addEventListener('change', upd); upd(); + return { el: host, update: upd }; + } + /* ---- Каркасы-заглушки интерактивных виджетов (реализуются по фазам) ---- */ function notImplemented(name) { return function () { @@ -727,6 +784,10 @@ shellConfig: shellConfig, // распределение электронов по слоям nuclide: nuclide, // §30 — A=Z+N, нуклид zSym: zSym, // Z → символ элемента + // готово (Phase 5 — химическая связь) + bondType: bondType, // §37,38 — ЭО → тип связи + bondClass: bondClass, // классификация связи по ΔЭО + enOf: enOf, // электроотрицательность // заглушки (см. план, разд. B) — наполняются в Phase 5–6 oxStateCalc: notImplemented('oxStateCalc'), // §42 — калькулятор степени окисления redoxBalancer: notImplemented('redoxBalancer'), // §44 — e-баланс ОВР diff --git a/frontend/textbooks/chemistry_8_ch4.html b/frontend/textbooks/chemistry_8_ch4.html index dc242c9..193ff96 100644 --- a/frontend/textbooks/chemistry_8_ch4.html +++ b/frontend/textbooks/chemistry_8_ch4.html @@ -7,130 +7,214 @@ Химия 8 · Глава 4 · «Химическая связь» - + + + - + +
-
- - - К разделам - +
-
Глава 4 · § 36–41
-

Химическая связь

+

Химия 8 · Глава 4

+
Природа связи, ковалентная (полярная и неполярная), ионная и металлическая связь, кристаллические решётки
- + К разделам +
-
-
-
- -
-
-

Раздел в разработке

-

Интерактивное наглядное наполнение этого раздела (теория, модели, симуляторы, тренажёры и боссы) добавляется поэтапно. Ниже — план параграфов раздела согласно учебнику.

-
-
+
+
+
+

Почему атомы держатся вместе

+

Атомы соединяются, чтобы завершить внешний электронный слой и стать устойчивее. В зависимости от того, как именно они «делят» электроны, возникают разные типы химической связи — а от них зависят свойства веществ.

+
+ +
Прогресс главы
0%
+
+
+
-
- - Содержание раздела +
Параграфы главы
+ +
§ 36

Природа химической связи

+
§ 37

Ковалентная связь

+
§ 38

Полярная и неполярная связь. Электроотрицательность · Лаб. 4

+
§ 39

Ионная связь

+
§ 40

Металлическая связь. Межмолекулярное взаимодействие

+
§ 41

Кристаллическое состояние вещества

+

Финал главы

-
    -
  • § 36Природа химической связи
  • -
  • § 37Ковалентная связь
  • -
  • § 38Неполярная и полярная ковалентная связь. Электроотрицательность
  • -
  • Лабораторный опыт 4. Составление моделей молекул
  • -
  • § 39Ионная связь
  • -
  • § 40Металлическая связь. Межмолекулярное взаимодействие
  • -
  • § 41Кристаллическое состояние вещества
  • -
+
- + +
Достижение!