@
feat(chemistry-8): Phase 5 — Глава 4 «Химическая связь» (§36–41) Глава на движке (6 § + Лаб.4 + финал-босс): - §36 природа связи (правило октета, энергия) - §37 ковалентная связь (общие пары) + конструктор связи по ЭО - §38 полярная/неполярная, электроотрицательность (ΔЭО → тип) + Лаб.4 модели молекул - §39 ионная связь (анимация передачи e⁻ Na→Cl) + §40 металлическая (электронный газ) - §41 кристаллические решётки (4 типа → свойства); финал-босс - POOLS ~25 задач, шпаргалки и подсказки chem8_svg.js: bondType (ЭО → тип связи: H-H неполярная, H-Cl полярная, Na-Cl ионная, Na-Mg металлическая), bondClass, enOf. chem8_ch4_widgets.js: монтаж по §. Тесты: 33/33 (юнит + jsdom-виджеты + полностраничный SPA 5 глав). Ассеты 200. --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:
@@ -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);
|
||||
@@ -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 '<option value="' + s + '"' + (s === sel ? ' selected' : '') + '>' + s + ' (ЭО ' + enOf(s) + ')</option>'; }).join(''); }
|
||||
host.innerHTML = '<div class="fld"><label>Атом A</label><select class="bt-a">' + optList(opts.a || 'H') + '</select>'
|
||||
+ '<label>Атом B</label><select class="bt-b">' + optList(opts.b || 'Cl') + '</select></div>'
|
||||
+ '<div class="bt-stage"></div><div class="out bt-out"></div>';
|
||||
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 = '<svg viewBox="0 0 240 70" class="bt-svg">'
|
||||
+ '<line x1="95" y1="35" x2="145" y2="35" stroke="' + color + '" stroke-width="3"/>'
|
||||
+ '<circle cx="80" cy="35" r="26" fill="' + color + '" opacity=".15" stroke="' + color + '" stroke-width="2"/>'
|
||||
+ '<circle cx="160" cy="35" r="26" fill="' + color + '" opacity=".15" stroke="' + color + '" stroke-width="2"/>'
|
||||
+ '<text x="80" y="40" text-anchor="middle" font-size="16" font-weight="800" fill="currentColor">' + a + '</text>'
|
||||
+ '<text x="160" y="40" text-anchor="middle" font-size="16" font-weight="800" fill="currentColor">' + b + '</text>'
|
||||
+ (da ? '<text x="80" y="12" text-anchor="middle" font-size="12" font-weight="800" fill="' + color + '">' + da + '</text>' : '')
|
||||
+ (db ? '<text x="160" y="12" text-anchor="middle" font-size="12" font-weight="800" fill="' + color + '">' + db + '</text>' : '')
|
||||
+ '</svg>';
|
||||
out.className = 'out bt-out ' + (r.cls === 'good' ? 'ok' : r.cls === 'bad' ? 'bad' : '');
|
||||
out.innerHTML = '<span class="bd">ΔЭО = |' + enOf(a) + ' − ' + enOf(b) + '| = <b>' + d + '</b> → связь <b>' + r.type + '</b>'
|
||||
+ (r.type === 'ионная' ? '<br>Электрон полностью переходит к более электроотрицательному атому.' : polar ? '<br>Общая пара смещена к более электроотрицательному атому (' + (aMore ? a : b) + ').' : r.type.indexOf('металл') >= 0 ? '<br>Общие электроны принадлежат всем атомам («электронный газ»).' : '<br>Общая пара поделена поровну.') + '</span>';
|
||||
}
|
||||
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-баланс ОВР
|
||||
|
||||
Reference in New Issue
Block a user