← 软件工程与计算 II(2020) 2020-软件工程与计算II-web-05-GUI入门 2020-07-06 约 19 分钟阅读 阅读 — 次
05-GUI入门
1. GUI入门
1.1. GUI Key elements
任何GUI(Graphical User Interface)都有三个关键元素:组件、布局和事件。
1.1.1. Component
组件是整个GUI的基础。常⻅组件有Label、TextField、Button等。
1.1.2. Layout
有了组件之后,下⾯要考虑的就是组件的布局。组件之间是Composite模式,可以转化为⼀个树状结构。
1.1.3. Event
最后,每个组件都要有事件响应的处理。⽐如,按按钮,获得焦点,被选择等。
Act that Results in an Event
Listener Type
User clicks a button, presses Return while typing in a text field, or chooses a menu item
ActionListener
User closes a frame (main window)
WindowListener
User presses a mouse button while the cursor is over a component
MouseListener
User moves the mouse over a component
MouseMotionListener
Component becomes visible
ComponentListener
Comoponent gets the keyboard focus
FocusListener
Table or list selection changes
ListSelectionListener
2. MVC Style
View和Model之间是Observer模式。
View要先向感兴趣的Model进⾏注册、Model改变之后通知View
View来Model取数据。View和Controller之间是事件机制。
⼀次View的交互,对应⼀个响应Controller。Controller负责修改Model和选择View的显示。
2.1. MVC in Swing
2.1.1. Model
ButtonModel接⼝的属性
ActionCommand
Mnemonic
Armed
Enabled
Pressed
Rollover
Selected
同样的模型DefaultButtonModel可以⽤于不同视图
2.1.2. View
JButton
继承JComponent
包含DefaultButtonModel、⼀些视图数据(标签和图标)、⼀个负责按钮视图的BasicButtonUI对象
2.1.3. Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class ButtonUIListener implements MouseListener , MouseMotionListener, ChangeListener{ public void mouseMoved (MouseEvent mouseevent) public void mouseDragged (MouseEvent mouseevent) public void mouseClicked (MouseEvent mouseevent) public void mouseEntered (MouseEvent mouseevent) public void mouseExited (MouseEvent mouseevent) public void mousePressed (MouseEvent mouseevent) public void mouseReleased (MouseEvent mouseevent) public void stateChanged (ChangeEvent changeevent) }public void mousePressed (MouseEvent mouseevent) { Button button = (Button)mouseevent.getSource(); ButtonModel buttonmodel = button.getModel(); buttonmodel.setPressed(true ); buttonmodel.setArmed(true ); }public void stateChanged (ChangeEvent changeevent) { Button button = (Button)changeevent.getSource(); button.repaint(); }
2.2. MVC in Web GUI
HTML表达了基础组件,⽣成DOM树,CSS表达样式生成CSS树。从⽽可以通过layout⽣成出渲染树。
Javascipt代表触发事件机制之后的处理。Javascipt脚本去操作Dom、更改CSS样式时,浏览器⼜要重新构建DOM、CSSOM树,重新render,重新layout、paint;(这是很费时间的操作)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <!DOCTYPE html > <html > <head > <meta charset ="utf-8" > </head > MVC vs MVP vs MVVM<body > <h1 > JavaScript 验证输⼊</h1 > <p > 请输⼊ 1 到 10 之间的数字:</p > <input id ="numb" > <button type ="button" onclick ="myFunction()" > 提交</button > <p id ="demo" > </p > <script > function myFunction ( ) { var x, text; x = document .getElementById ("numb" ).value ; than one or greater than 10 if (isNaN (x) || x < 1 || x > 10 ) { text = "输⼊错误" ; } else { text = "输⼊正确" ; } document .getElementById ("demo" ).innerHTML = text; } </script > </body > </html >
2.2.1. MVC vs MVP vs MVVM
MVC的等待过程会出现卡顿
所以我们选择MVP:Presenter来完成
例子:手机横竖屏切换,很多次的切换有很多的Controller拉爆内存
MVP:测试Presenter是很困难
MVVM:View Model和View双向绑定,是一个数据集
2.2.2. MVVM in Vue
counter数据和View中的点击次数进⾏双向绑定。事件响应每次按按钮,counter数据+1。View中的点击次数也随之改变。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <!DOCTYPE html><html > <head > <meta charset ="utf-8" > <title > Vue 测试实例 - 菜⻦教程(runoob.com)</title > <script src ="https://cdn.staticfile.org/vue/2.2.2/vue.min.js" > </script > </head > <body > <div id ="app" > <button v-on:click ="counter += 1" > 增加 1</button > <p > 这个按钮被点击了 {{ counter }} 次。</p > </div > <script > new Vue ({ el : '#app' , data : { counter : 0 } }) </script > </body > </html >
ViewModel有时候会异步请求Model的数据。当服务器回答后,再根据response数据设置ViewModel,从而达到View的改变。
下面是循环调用的,info是双向绑定,有MVVM处理好之后的过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <div id ="app" > <h1 > ⽹站列表</h1 > <div v-for ="site in info" > {{ site.name }} </div > </div > <script type = "text/javascript" > new Vue ({ el : '#app' , data () { return { info : null } }, mounted () { axios .get ('https://www.runoob.com/try/ajax/json_demo.json' ) .then (response => (this .info = response.data .sites )) .catch (function (error ) { console .log (error); }); } }) </script >
MVVM可以和函数式编程范式下的流式编程相结合,⽣成复杂的数据处理。
3. Virtual Dom 虚拟Dom树
3.1. From Template to Dom in Vue
Virtual DOM 其实就是⼀棵以 JavaScript 对象( VNode 节点)作为基础的树,⽤对象属性来描述节点,实际上它只是⼀层对真实 DOM 的抽象。最终可以通过⼀系列操作使这棵树映射到真实环境上。
简单来说,可以把Virtual DOM 理解为⼀个简单的JS对象,并且最少包含标签名(tag)、属性(attrs)和⼦元素对象(children)三个属性。不同的框架对这三个属性的命名会有点差别。
对于虚拟DOM,咱们来看⼀个简单的实例,就是下图所示的这个,详细的阐述了 模板 → 渲染函数 → 虚拟DOM树 → 真实DOM 的⼀个过程。
先生成一个假的Dom Tree,作为一个中间状态,不触发repaint,此时Dom在内存中
虚拟DOM树增大了调试的负担
3.2. 为什么要虚拟Dom?
虚拟DOM的最终目的 是将虚拟节点渲染到视图上。但是如果直接使⽤虚拟节点覆盖旧节点的话,会有很多不必要的DOM操作。例如,⼀个ul标签下很多个li标签,其中只有⼀个li有变化,这种情况下如果使⽤新的ul去替代旧的ul,因为这些不必要的DOM操作⽽造成了性能上的浪费。
为了避免不必要的DOM操作,虚拟DOM在虚拟节点映射到视图的过程中,将虚拟节点与上⼀次渲染视图所使⽤的旧虚拟节点(oldVnode)做对⽐ ,找出真正需要更新的节点来进⾏DOM操作,从⽽避免操作其他⽆需改动的DOM。
其实虚拟DOM在Vue.js主要做了两件事:
提供与真实DOM节点所对应的虚拟节点vnode
将虚拟节点vnode和旧虚拟节点oldVnode进⾏对⽐,然后更新视图
3.3. diff 差异
Vue的diff算法是基于snabbdom改造过来的,仅在同级的vnode间做diff,递归地进⾏同级vnode的
diff,最终实现整个DOM树的更新。因为跨层级的操作是⾮常少的,忽略不计,这样时间复杂度就从
O(n3)变成O(n)。
diff 算法包括⼏个步骤:
⽤ JavaScript 对象结构表示 DOM 树的结构;然后⽤这个树构建⼀个真正的 DOM 树,插到⽂档当中
当状态变更的时候,重新构造⼀棵新的对象树。然后⽤新的树和旧的树进⾏⽐较,记录两棵树差异
把所记录的差异应⽤到所构建的真正的DOM树上,视图就更新了
3.4. patch
核⼼函数实现流程:
patch(container,vnode) :初次渲染的时候,将Virtual Dom渲染成真正的DOM然后插⼊到容器⾥⾯。
patch(vnode,newVnode):再次渲染的时候,将新的vnode和旧的vnode相对⽐,然后之间差异应⽤到所构建的真正的DOM树上。
4. 参考
https://www.cs.utexas.edu/users/dsb/SwingTutorial/1_Basics/lecture.html
https://www.runoob.com/vue2/vuejs-ajax-axios.html
https://www.runoob.com/try/try.php?filename=tryjs_validation_number
https://segmentfault.com/a/1190000014070240
评论