丨辅助界面元素的架构设计_第1页
丨辅助界面元素的架构设计_第2页
丨辅助界面元素的架构设计_第3页
丨辅助界面元素的架构设计_第4页
丨辅助界面元素的架构设计_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

代码<selectid="lineWidth"<option<option<option<option<option<option还有颜色选择控件 .js#L115),如下代码<selectid="lineColor"<option<option<option<option<option<option9<selectid="fillColor"<option<option<option<option<option<option<option<option我们统一用通用的select实现了一个线型选择器、两个颜色选择器的实例。虽然这种怎么做我们不妨把上面基础版本的线型选择器、颜色选择器BaseLineWidthPicker、我们解释一下这个表格中的各项内id是控件的id,通过它可以获取到辅助界面元素的顶value面元素的值,其实也就是辅助界面元素的Model的数据。从MVC构角度来说,Model的数据一般是一棵DOM。但是对很多辅助界面元素来说,它的DOM树比较简单,只是一个数值。比如线型选择器是一个number,颜色选择器是一个Colorpalette是颜色选择器的调色板,用来指示颜色选择器可以选择哪些颜色blur()方法是主动让一个界面元素失去焦点onchange是在该界面元素的值(value)通过用户界面交互进行改变时发送的。需要注意的是,这个只在用户交互时发送。直接调用element.value=xxx这样的方式来修改界面元素的值是不会触发onchange的。首先,每个界面元素使用的时候,统一以<divtype="xxx">来表示。比如上面的一个线代码<divtype="BaseLineWidthPicker"id="lineWidth"23<divtype="BaseColorPicker"id="lineColor"onchange="onPropChanged('lineColor')"45<divtype="BaseColorPicker"id="fillColor"onchange="onPropChanged('fillColor')"那么它是怎么被替换成前面的界面我们引入一个全局的qcontrols:QControls实例,所有我们定义的控件都(register)自己。的代码如下代码classQControlsconstructor()this.data= register(type,control)this.data[type]= 8可以看出,的逻辑基本上没做什么,只是建立了类型(type)和控件的构建函(control)的关联。有了这个关联表,我们就可以在适当的时候,把所有的<div="xxx">的div替换为实际的控件。替换过代码classQControlsinit()letdivs=.geletn=for(leti=n-1;i>=0;i--)letdiv=lettype=if(type!=null)letcontrol=if(control) 16这段代码逻辑很简单,遍历文档中所有的div,如果带type性,就去查这个type完整的辅助界面元素框架代码如具体构建控件的代码是怎么样的?源代码请参考这两我们拿BaseColorPicker作为例子看下吧代码1functionBaseColorPicker(div)2letid=3letonchange=4letpalette=5letcolors=6letoptions=7for(letiincolors)8letcolor=9letn=if(color.charAt(n-1)==")")letoffset=options.push(`<optionvalue="`+color.substring(0,offset)+`">`+}elseoptions.push(`<optionvalue="`+color+`">`+color+}}div.outerHTML=`<selectid="`+id+`">`+options.join("")+letelem=.geif(onchange)elem.onchange=}}24qcontrols.register("BaseColorPicker",可以看到,构建函数的代码大体分为如下三第一步,从占位的div元素中读入所有的输入参数。这里是id,onchange,palette第二步,把占位的div元素替换为实际的界面。也就是div.outerHTML=xxx这段代码。第三步,如果用户对onchange感,把onchange响应函数安装到实际界面的onchange中jQuery接下来我们就开始考虑替换颜色选择器的实现了。新版本的颜色选择器,我们不妨ColorPicker。这个新版本的使用必须和BaseColorPicker一样,也就是从使用的角度来说,我们只需要把之前的BaseColorPicker换成ColorPicker。如下代码1<divtype="BaseLineWidthPicker"id="lineWidth"23<divtype="ColorPicker"id="lineColor"onchange="onPropChanged('lineColor')"45<divtype="ColorPicker"id="fillColor"onchange="onPropChanged('fillColor')"那么实现方面呢我们决定基于jQuery社区的spectrum颜色选择器我们的画图程序的主体并没有任何现成的框架代码。 是第一个被引入的对待jQuery,我们可以有两种态度。一种是认为jQuery计非常优良,我们很喜欢,决在这种态度下,我们允许jQuery格的代码蔓延得到处都是,典型表现就是满屏$当然这种选择的风险是不低的。有一天我们不想再基于jQuery发了,这意味着大量的模另一种态度是,认为jQuery并不是我们的主体框架,只是因为我们有些模块用了社区的果,比如spectrum颜色选择器,它是基于jQuery实现的。这意味着我们要用spectrum,就需要引入jQuery。这种团队下,我们会尽可能限制jQuery使用范围,尽量不要让它的代码蔓延,而只是限我们这一讲假设我们的态度是后者。我们有自己的基础开发框架(Jaart),所以不会大面积使用u。这样我们需要包装jQuery组件。代码如下(参阅代码1functionColorPicker(div)2id=3onchange=4palette=5colors=6value=78932

div.outerHTML=`<inputtype="button"id="`+id+`"value="`+value+`">`letelem=$("#"+id)l:true,showInput:true,showButtons:true,preferredFormat:"hex6"if{}Object.defineProperty(.geementById(id),{get(){returnvalueset(x)if{}value=xthis.busy=trueelem.spectrum("set",value)this.busy=false}34qcontrols.register("ColorPicker",这里大部分代码比较常规,只有Object.defineProperty这一段看起来比较古怪一些。这 ementById(id)这个界面元素的value属性的读写(get/set)函数为什么需要改写因为我们希望感知到使用者对value的改写。正常我们可能认为接管onchange就可以了,但是实际上element.value=xxx这样的属性改写是不会触发onchange的。所以我们只能从改写value属性的set函数来做。set数value改写后,会调用elem.spectrum(“set”value)改变颜色控件的当前值但这里又有个细节问题:elem.spectrum(“set”,value)内部又会调用element.value=value来修改 ementById(id)这个界面元素的value属性,这样就出现了死循环。怎么办?我们通过引入一个busy标志来解决:如果当前已经处于value属性的set函数,就直接返回。到目前为止,我们实现了三个符合我们定义的控件规范的辅助界面元素观察这些辅助界面元素的代码,你会发现它们都没有MVC构。是因为辅助界面元素不适合用MVC架构来编写么?当然不更本质的原因是因为它们规模太小了。这些界面元素的特点是DOM都是一个value,并不是一棵树,这样Model层就没什么代码了。同样的逻辑,View层、Control层代码量都过于短小,就没必要有那么清楚的模块划分。View负责界面呈现,Control负责响应,只是在心里有谱就好但并不是所有辅助界面元素都这么简单举一个简单的例子。让我们给自己设定一个新目标:把我们前面实战的画图序,改答案当然是肯定但是这意味着我们有一些假设需要修正。这些假设通常都和唯一性有比如,全局有唯一的View对象实例qview:QPaintView。如果我们是辅助界面元素,意味着我们可能在同一个界面出现多个实例。在多实例的情况下,View显然就应该有多再比如,我们画图程序的辅助界面元素(参见accel/.js)都是单例,具体表现为这些界面元素的id都是固定的。使得每个QPaint实例都有自己的辅助界面元素。另案是继续保持单例,这意味着多个QPaint实例会有一个当前实例的概念。辅助界我们选择继续保持单例。这意味着qview:QPaintView这个全局变量可以继续存在,但是和之前的含义有了很大不同。之前qview代表的是单例,现在qview代表的是当前实例。有了当前实例当然就有切换。这样就需要增加焦点相关的响应在画图程序中Controller是View例相关的。比如:PathCreator、ShapeSelector等。在View存在多例的情况下,这些Controller之前的registerController动作就需要重新考虑。为了支持多例,我们引入了onViewAdded、onCurrentViewChanged。当一个新的View实例被创建时,会发送onViewAdded。Controller可以响应该去完成registerController动作。如下:代码onViewAdded(function(view)view.registerController("PathCreator",function()3 5

returnnewQPathCreator(view,原先,当前图形样式是放在View中的,通过qview.style可以到。这会导致多个View的当前图形样式不一样,但是我们辅助界面元素又是单例的,这就非常让人混淆。最后我们决定把qview.style挪到全局,改名叫defaultStyle(参阅 .js#L42)做完这些改造,我们的画图程序就有了成为一个标准控件的基础。具体代码如下(代码function intView(drawingID)letview=newreturn56functioninitPaintView(drawingID)letview= 10functionPaintView(div)letid=letwidth=letheight=div.outerHTML=`<canvasid="`+id+`"width="`+width+`"height="`+height+1820qcontrols.register("PaintView",有了这个PaintView控件,我们就可以到处它了。我们做了一个PaintView控件DEMO程序,它效果看起来是这样的(代码参阅从这个截图看,细心的你可能会留意到,还有一个问题是没有被修改的,那就是URL地址。我QPaintViewload档后会修改URL,这作为应用程序并没有问题。但是如果是一个控件,整个界面有好多个PaintView,URL中应该显示哪个文档的ID?显然谁都不合适。如果非要显示,可能要在PaintView例附近

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论