不写前端,用纯 Python 做个自动判分测验:ss.state 双向数据绑定入门
不写前端用纯 Python 做个自动判分测验ss.state 双向数据绑定入门上篇我们用 5 个例子上手了 SimpleStart 的基础积木按钮、表单、表格、图表。这篇做一个更完整的小应用3 道选择题的判分测验——作答自动判分答对变绿、答错变红顶部实时计分一键全部重置。全程不碰 HTML/CSS/JavaScript核心只用一个特性ss.state双向数据绑定。思路界面是数据的投影命令式写界面的习惯是数据变了找到显示它的组件手动更新。这篇我们反过来——先把数据和状态定义清楚界面只是状态的一面镜子。写完你会发现判分函数里没有一行更新界面的代码。第一步把数据写出来QUESTIONS[{q:**1. Python 中定义函数用哪个关键字**,options:[func,def,lambda],answer:def},{q:**2. 下面哪个类型是不可变的**,options:[list,dict,tuple],answer:tuple},{q:**3. len(abc) 的返回值是**,options:[2,3,4],answer:3},]题目、选项、答案全部业务数据就这一个列表。想换成英语题、化学题只改这里界面代码零改动。第二步建一份状态quizss.State(q1,q2,q3,c1,c2,c3,summary选好答案这里自动出分)q1~q3存三道题的答案c1~c3存判分颜色summary是得分条文本——整张页面由这 7 个状态位加一句提示语决定。ss.State是响应式状态容器把属性传给组件参数绑定就完成了之后属性怎么变组件自动跟着变。第三步判分逻辑不碰任何组件defgrade():donescore0fori,qinenumerate(QUESTIONS,start1):pickedgetattr(quiz,fq{i}).valueifnotpicked:continuedone1okpickedq[answer]scoreok quiz.update(**{fc{i}:successifokelseerror})# State - 组件颜色quiz.summaryf已答{done}/3 · 答对{score}题(全部正确 ifscore3else)defon_answer(event):quiz.update(**{fq{event.data[idx]}:event.value})# 组件 - State把选择写回grade()三个要点读状态要显式.value。quiz.q1读出来的是绑定对象供组件响应式使用参与判断必须取.value。这是初学者最容易踩的坑记个口诀传给组件用属性本身写逻辑用.value一个回调服务三道题。eventData{idx: i}在下面第四步传给 radio会合并进事件对象回调里用event.data[idx]取回题号——不用写三个几乎一样的函数grade()只读写 State没有任何组件引用——改的是数据变的是界面。第四步绑定界面ss.write(## Python 小测验)ss.text(quiz.summary,typeinfo)fori,qinenumerate(QUESTIONS,start1):withss.card(stylemax-width:560px):ss.write(q[q])ss.radio(q[options],valuegetattr(quiz,fq{i}),colorgetattr(quiz,fc{i}),onchangeon_answer,eventData{idx:i},inlineTrue)ss.space(mt-4)ss.button(重新作答,iconmdi-refresh,typesuccess,onclickon_reset)得分条ss.text(quiz.summary, typeinfo)——注意传的是 State 属性本身不是字符串值。组件从此订阅这个属性它变我就变。单选组valuequiz.qN绑答案colorquiz.cN绑颜色——组件外观也是数据的投影。选中一个选项onchange把值写回 Stategrade()更新颜色状态位radio 自己变绿或变红全程没人碰过这个组件。写过前端的读者这效果类似v-model——组件修改自动写回变量变量修改自动刷新组件。没用过前端直接跳过这段——这正是你不需要学它的原因。我们不需要主动去更新组件对吗对。运行全程summary先后呈现三个字符串时机summary 的值谁写的页面加载选好答案这里自动出分State 初始值每次作答已答 2/3 · 答对 2 题grade()点击重置已重置再来一轮on_reset()三次换脸没有一行拿组件引用去更新的代码——绑定一次订阅终身。常见的写法是数据变了还要记得mytext.prop.text ...手动同步漏了一处界面和数据就对不上State 把这一步整个消灭了。注意边界只有绑定过 State 的参数才享受这个待遇。ss.text(固定文本)这种传普通字符串的还是要手动更新。重置双向的另一半defon_reset(event):quiz.update(q1,q2,q3,c1,c2,c3,summary已重置再来一轮)# 一次 update三个单选组清空、颜色全部复位作答是组件 → State选择写回数据重置是State → 组件一次update三个单选组同时清空、颜色全部复位、得分条换文案。没有循环没有逐个设置组件——这就是双向的完整含义。小结回头看这个不到 50 行的应用数据、状态、逻辑、界面完全分开。界面代码只有 10 行换题库、改判分规则、调样式各改各的层互不牵连——耦合降到最低应用才好管理组件自动刷新精力还给逻辑本身。不需要维护一张哪个数据显示在哪个组件、改完要手动同步的清单写的代码只有业务界面是状态的同源投影。选中值、颜色、得分文案都来自同一份 State数据对了界面一定对——不存在改了数据、某个组件忘了跟上这类经典 bug应用天然可生长。从 3 题到 30 题只是往列表里加几个 dict逻辑和界面一行不改。跑起来pipinstallsimplestart ss quiz.py# 四段代码拼起来存成 quiz.py或直接用仓库里的 tutorials/tutorial_01.py下一步这个例子还有可以生长的地方用quiz.watch(summary)监听状态变化答错自动弹出解析把题库换成 YAML 文件做成真正的刷题工具。这些留到后续篇章。在线文档中文http://www.simplestart.cc/zhDocumentation (English)http://www.simplestart.ccGitHub本文完整代码tutorials/tutorial_01.pyhttps://github.com/readever/simplestartpip install simplestart把你手头的练习题变成一个能自动判分的页面试试。做出了有意思的应用欢迎来 GitHub Issues 交流。本系列文章01 SimpleStart 入门不写一行前端用纯 Python 构建 Web 应用02 不写前端用纯 Python 做个自动判分测验ss.state 双向数据绑定入门本文