Files
2026-08-04 18:07:40 +08:00

1 line
18 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Dart & Flutter 学习测验 (30题)</title> <style> * { margin:0; padding:0; box-sizing:border-box; font-family:'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif; } body { min-height:100vh; background: linear-gradient(135deg,#02569B 0%, #0277BD 50%, #13B9FD 100%); display:flex; align-items:center; justify-content:center; padding:20px; } .app { width:100%; max-width:760px; } .header { background:#fff; border-radius:16px 16px 0 0; padding:22px 28px 16px; box-shadow:0 10px 40px rgba(0,0,0,.25); } .header h1 { font-size:22px; color:#02569B; display:flex; align-items:center; gap:10px; } .header h1 span.logo { width:34px;height:34px;border-radius:50%; background:linear-gradient(135deg,#13B9FD,#02569B); color:#fff;display:inline-flex;align-items:center;justify-content:center; font-size:18px;font-weight:800; } .meta { display:flex; justify-content:space-between; align-items:center; margin-top:14px; font-size:13px; color:#666; } .bar { height:8px; background:#e3f2fd; border-radius:99px; margin-top:8px; overflow:hidden; } .bar-fill { height:100%; width:0%; background:linear-gradient(90deg,#13B9FD,#02569B); transition:width .4s ease; } .card { background:#fff; padding:28px; border-radius:0 0 16px 16px; box-shadow:0 10px 40px rgba(0,0,0,.25); min-height:420px; } .q-head { display:flex; justify-content:space-between; align-items:center; margin-bottom:16px; } .q-num { font-size:15px; color:#0288D1; font-weight:700; } .badge { font-size:11px; padding:3px 10px; border-radius:99px; font-weight:700; letter-spacing:.5px; } .lv1{ background:#e3f2fd; color:#0277BD; } .lv2{ background:#e8f5e9; color:#2e7d32; } .lv3{ background:#fff3e0; color:#e65100; } .lv4{ background:#fce4ec; color:#c2185b; } .lv5{ background:#f3e5f5; color:#7b1fa2; } .lv6{ background:#ffebee; color:#b71c1c; } .q-title { font-size:17px; line-height:1.7; color:#263238; margin-bottom:20px; font-weight:600; } .q-title code { background:#f5f5f5; padding:1px 6px; border-radius:5px; color:#0277BD; font-family:'Consolas',monospace; } .opts { display:flex; flex-direction:column; gap:12px; } .opt { border:2px solid #e0e0e0; border-radius:12px; padding:14px 18px; cursor:pointer; font-size:15px; color:#37474f; transition:all .15s; background:#fff; text-align:left; } .opt:hover:not(:disabled) { border-color:#13B9FD; background:#e1f5fe; } .opt.selected { border-color:#0277BD; background:#e1f5fe; } .opt.correct { border-color:#2e7d32; background:#e8f5e9; font-weight:700; } .opt.wrong { border-color:#c62828; background:#ffebee; } .opt:disabled { cursor:default; opacity:.92; } .opt .key { font-weight:800; margin-right:8px; color:#0277BD; } .explain { margin-top:20px; padding:16px 18px; border-radius:12px; font-size:14px; line-height:1.8; display:none; border-left:5px solid; } .explain.ok { background:#e8f5e9; border-color:#2e7d32; color:#1b5e20; display:block; } .explain.no { background:#ffebee; border-color:#c62828; color:#b71c1c; display:block; } .explain b { font-size:13px; } .btns { display:flex; justify-content:flex-end; gap:12px; margin-top:22px; } .btn { border:none; border-radius:10px; padding:12px 28px; font-size:15px; font-weight:700; cursor:pointer; transition:transform .1s, opacity .2s; } .btn:active { transform:scale(.96); } .btn-primary { background:linear-gradient(135deg,#13B9FD,#02569B); color:#fff; } .btn-ghost { background:#eceff1; color:#455a64; } .btn:disabled { opacity:.4; cursor:not-allowed; } /* 结果页 */ .result { display:none; text-align:center; padding-top:10px; } .score-circle { width:150px; height:150px; border-radius:50%; margin:10px auto 20px; display:flex; flex-direction:column; align-items:center; justify-content:center; background:conic-gradient(#13B9FD calc(var(--p)*1%), #e3f2fd 0); } .score-circle .inner { width:120px; height:120px; border-radius:50%; background:#fff; display:flex; flex-direction:column; align-items:center; justify-content:center; } .score-circle .num { font-size:38px; font-weight:800; color:#02569B; } .score-circle .lbl { font-size:13px; color:#90a4ae; } .grade { font-size:26px; font-weight:800; margin-bottom:6px; } .grade-sub { color:#78909c; font-size:14px; margin-bottom:18px; } .review { text-align:left; max-height:260px; overflow-y:auto; border-top:1px solid #eceff1; padding-top:14px; } .review .item { font-size:13px; padding:8px 6px; border-bottom:1px dashed #eceff1; color:#455a64; line-height:1.6; } .review .ok { color:#2e7d32; font-weight:700; } .review .no { color:#c62828; font-weight:700; } </style> </head> <body> <div class="app"> <div class="header"> <h1><span class="logo">D</span>Dart & Flutter 学习测验</h1> <div class="meta"> <span id="progressText">第 1 / 30 题</span> <span id="scoreText" style="color:#13B9FD;font-weight:700;">得分:0</span> </div> <div class="bar"><div class="bar-fill" id="bar"></div></div> </div> <div class="card"> <!-- 题目卡片 --> <div id="quizBox"> <div class="q-head"> <span class="q-num" id="qNum"></span> <span class="badge" id="qBadge"></span> </div> <div class="q-title" id="qTitle"></div> <div class="opts" id="opts"></div> <div class="explain" id="explain"></div> <div class="btns"> <button class="btn btn-ghost" id="prevBtn" onclick="prev()">上一题</button> <button class="btn btn-primary" id="nextBtn" onclick="next()">下一题 →</button> </div> </div> <div class="result" id="resultBox"> <div class="score-circle" id="circle"> <div class="inner"><div class="num" id="finalScore"></div><div class="lbl">/ 30 分</div></div> </div> <div class="grade" id="grade"></div> <div class="grade-sub" id="gradeSub"></div> <div class="review" id="review"></div> <div class="btns" style="justify-content:center;margin-top:20px;"> <button class="btn btn-primary" onclick="restart()">🔄 重新测验</button> </div> </div> </div> </div><script> const questions = [ // ===== 1 ===== { lv:1, q:'Dart ""', opts:['var','let','const','dynamic'], ans:0, exp:'Dart <b>var</b> <b>let</b> JS <b>const</b> ' }, { lv:1, q:'Dart 64 ', opts:['integer','int','number','long'], ans:1, exp:'Dart <b>int</b> 64<b>double</b> <b>num</b>' }, { lv:1, q:' Dart ', opts:['# ','/* */','// ','<!-- -->'], ans:2, exp:'Dart <b>//</b> <b>/* */</b><b>#</b> Python#! Dart shebang ' }, { lv:1, q:'Dart ', opts:['runApp()','main()','init()','start()'], ans:1, exp:' <b>main()</b>Flutter <code>void main() => runApp(MyApp());</code>' }, { lv:1, q:'', opts:['console.log()','System.out.println()','echo','print()'], ans:3, exp:'Dart <b>print()</b> <code>print("Hello Dart");</code>' }, { lv:1, q:'<code>int x = 10;</code> <code>x=10</code>', opts:['print("x=" + x);','print("x=$x");','print(\'x=${x}\');',''], ans:3, exp:'Dart <b>+</b> <b>$x</b> <b>${x}</b> <code>x=10</code>' }, // ===== 2 ===== { lv:2, q:' <b></b> Dart ', opts:['for (var i=0; i<5; i++)','while (ok)','foreach (x in list)','do { } while (ok)'], ans:2, exp:'Dart <b></b> <code>foreach(x in list)</code> <code>for (var x in list)</code> <code>list.forEach(...)</code>' }, { lv:2, q:' <code>for (var i=0; i<5; i++) print(i);</code> ', opts:['1 2 3 4 5','0 1 2 3 4','0 1 2 3 4 5','5 4 3 2 1'], ans:1, exp:'i 0 <code>i&lt;5</code> <b>0 1 2 3 4</b>' }, { lv:2, q:'Dart switch case ', opts:['end','return / break / throw','continue',''], ans:1, exp:'Dart case <b>breakreturn throw</b> C 穿' }, { lv:2, q:'', opts:['int add(int a,int b){ return a+b; }','add(int a,int b) => a+b;','void add(int a,int b){ return a+b; }','A B '], ans:3, exp:'A B <b></b>C void return ' }, { lv:2, q:'<b></b>', opts:['void f({String name}) {}','void f([String name]) {}','void f(String? name) {}','void f(String name="") {}'], ans:0, exp:'<b>{}</b> <code>f(name: x)</code><b>[]</b> <b>?</b> ' }, { lv:2, q:' <code>void f({int a = 1}) {}</code>', opts:['f()','f(1)','f(a: 1)','A C '], ans:3, exp:'A <b></b> <code>f(a: 1)</code>C <code>f(1)</code> ' }, // ===== 3 ===== { lv:3, q:'Dart "/"', opts:['Array','ArrayList','List','Vector'], ans:2, exp:'Dart <b>List</b> <code>[1,2,3]</code>' }, { lv:3, q:' 123 ', opts:['{1, 2, 3}','[1, 2, 3]','(1, 2, 3)','List(1,2,3)'], ans:1, exp:'<b>[]</b> List<b>{}</b> Set/Map<b>()</b> ' }, { lv:3, q:'<code>var list = [10, 20, 30]; print(list[1]);</code> ', opts:['10','20','30',''], ans:1, exp:'Dart <b>0</b> list[1] <b>20</b>' }, { lv:3, q:' List <b></b>', opts:['forEach()','map()','where()','add()'], ans:1, exp:'<b>map()</b> Iterable<b>forEach()</b> void<b>where()</b> ' }, { lv:3, q:'<code>var a=[1,2,3]; var b=[0, ...a];</code> <code>b.length</code> ', opts:['3','4','7',''], ans:1, exp:'<b>...a</b> a 1,2,3 0b = [0,1,2,3] <b>4</b>' }, { lv:3, q:'<b></b>', opts:['List','Map','Set','Queue'], ans:2, exp:'<b>Set</b> Map ' }, // ===== 4 ===== { lv:4, q:' <code>class Dog { String name; }</code> ', opts:['Dog d = Dog();','var d = new Dog;','Dog d = new Dog();',''], ans:3, exp:'Dart 2 <b>new </b> <code>Dog()</code> ' }, { lv:4, q:'使', opts:['with','implements','extends','inherits'], ans:2, exp:' <b>extends</b><b>implements</b> <b>with</b> Mixin' }, { lv:4, q:'<b></b>', opts:['abstract','interface','base','pure'], ans:0, exp:'<b>abstract</b> new' }, { lv:4, q:'/<code>this</code> ', opts:['','','',''], ans:0, exp:'<b>this</b> <code>this.name = name</code>' }, { lv:4, q:' String List', opts:['List<String> names = [];','List names = <String>[];','var names = <String>[];',''], ans:3, exp:'Dart <code>&lt;String&gt;[]</code> ' }, { lv:4, q:' Animal <code>void speak()</code> Dog ', opts:[' speak() ','',' speak',''], ans:0, exp:' <code>@override</code> Dog ' }, // ===== 5 ===== { lv:5, q:'Dart <b> null</b> ', opts:['String','String?','String!','nullable String'], ans:1, exp:' <b>?</b> <code>String? s = null;</code> ? String ' }, { lv:5, q:' <code>??</code> ', opts:[' null ',' null ','',''], ans:0, exp:'<code>a ?? b</code>a null a b <code>??=</code> ' }, { lv:5, q:'使 <code>async/await</code> ', opts:['Stream<T>','Future<T>','void','T'], ans:1, exp:'async <b>Future&lt;T&gt;</b>await Future ' }, { lv:5, q:'<br><code>Future.delayed(Duration(seconds:1), () => print("A"));<br>print("B");</code>', opts:['A B','B A','',' A'], ans:1, exp:'Future.delayed <code>print("B")</code>1 A' }, // ===== 6 Flutter ===== { lv:6, q:'Flutter <b></b>', opts:['Future','Stream','List','Map'], ans:1, exp:'<b>Stream</b> Future ' }, { lv:6, q:'Flutter <b></b>', opts:['Activity','View','Widget','Component'], ans:2, exp:'Flutter <b>Widget</b>UI Widget TextContainerColumn' }, { lv:6, q:'<b></b>使', opts:['StatelessWidget','StatefulWidget','Container','Scaffold'], ans:1, exp:' <b>StatefulWidget</b> State setState StatelessWidget' }, ]; let cur = 0; // let score = 0; let userAnswers = new Array(questions.length).fill(null); // let answered = new Array(questions.length).fill(false); const lvName = ['',' ',' ',' ',' ',' ','🚀 Flutter ']; const lvClass = ['','lv1','lv2','lv3','lv4','lv5','lv6']; function render() { const q = questions[cur]; document.getElementById('qNum').textContent = ` ${cur+1} / ${questions.length} `; document.getElementById('qBadge').textContent = lvName[q.lv]; document.getElementById('qBadge').className = 'badge ' + lvClass[q.lv]; document.getElementById('qTitle').innerHTML = q.q; const optsBox = document.getElementById('opts'); optsBox.innerHTML = ''; const keys = ['A','B','C','D']; q.opts.forEach((o, i) => { const btn = document.createElement('button'); btn.className = 'opt'; btn.innerHTML = `<span class="key">${keys[i]}.</span>${o}`; btn.onclick = () => choose(i, btn); // / if (answered[cur]) { btn.disabled = true; if (i === q.ans) btn.classList.add('correct'); if (i === userAnswers[cur] && i !== q.ans) btn.classList.add('wrong'); } optsBox.appendChild(btn); }); const expBox = document.getElementById('explain'); if (answered[cur]) { const isOK = userAnswers[cur] === q.ans; expBox.className = 'explain ' + (isOK ? 'ok' : 'no'); expBox.innerHTML = (isOK ? ' ' : ' <b>' + keys[q.ans] + '</b><br>') + '📖 ' + q.exp; } else { expBox.className = 'explain'; expBox.innerHTML = ''; } document.getElementById('prevBtn').disabled = cur === 0; document.getElementById('nextBtn').textContent = cur === questions.length - 1 ? ' 🎯' : ' '; document.getElementById('progressText').textContent = ` ${cur+1} / ${questions.length} `; document.getElementById('bar').style.width = ((cur+1)/questions.length*100) + '%'; document.getElementById('scoreText').textContent = `${score}`; } function choose(i, btn) { if (answered[cur]) return; answered[cur] = true; userAnswers[cur] = i; const q = questions[cur]; if (i === q.ans) score++; render(); } function next() { if (cur < questions.length - 1) { cur++; render(); } else showResult(); } function prev() { if (cur > 0) { cur--; render(); } } function showResult() { document.getElementById('quizBox').style.display = 'none'; const rb = document.getElementById('resultBox'); rb.style.display = 'block'; const pct = score / questions.length * 100; document.getElementById('circle').style.setProperty('--p', pct.toFixed(1)); document.getElementById('finalScore').textContent = score; let grade, sub; if (pct >= 90) { grade = '🏆 '; sub = 'Dart Flutter '; } else if (pct >= 75) { grade = '🌟 '; sub = ''; } else if (pct >= 60) { grade = '👍 '; sub = ''; } else if (pct >= 40) { grade = '📖 '; sub = ''; } else { grade = '💪 '; sub = ' Dart + '; } document.getElementById('grade').textContent = grade; document.getElementById('gradeSub').textContent = sub; // const keys = ['A','B','C','D']; const review = document.getElementById('review'); let html = '<div style="font-weight:700;color:#02569B;margin-bottom:6px;">📋 </div>'; questions.forEach((q, i) => { const isOK = userAnswers[i] === q.ans; html += `<div class="item"> <b>${i+1}.</b> ${q.q.replace(/<br>/g,' ').slice(0,46)}... ${isOK ? '<span class="ok"> </span>' : '<span class="no"> ' + (userAnswers[i]==null?'':keys[userAnswers[i]]) + '' + keys[q.ans] + '</span>'} </div>`; }); review.innerHTML = html; } function restart() { cur = 0; score = 0; userAnswers = new Array(questions.length).fill(null); answered = new Array(questions.length).fill(false); document.getElementById('resultBox').style.display = 'none'; document.getElementById('quizBox').style.display = 'block'; render(); } render(); </script></body> </html>