应聘者页面——文本输入框及单选多视图重构

近期校招季。实习单位提供校招软件服务,线上用户比較多,并没有太多新功能上线,乐帝主要负责做一些重构的工作。想想今年毕业新来的同事,已经可以独立承担业务开发。乐帝近期对MVC架构有了更深的了解,编程能力也有一定的入门提高。从同事新胜那儿。学到非常多前端开发的规范,在这里再次感谢新胜耐心教导、无私帮助。

    乐帝与新胜最大的区别在于。新胜处理问题解决这个问题,都有深厚的理论功底,即知其所以然,而不单单是一个程序猿,他有自己的思考,懂得怎样优化代码与性能。乐帝向新胜学习他,构建的理论体系及解决这个问题的方法。高速缩小与新胜这个模范的差距。

    这篇文章所讨论视图,在单位。招聘项目里,应聘者功能下。那为什么须要重构呢?

    在这次重构工作中。我想有双方面原因:

  • 模板中处理逻辑过于复杂,不符合结构与处理逻辑分离,代码可读性不高。

<select data-name="<%=Name%>" data-obj="<%=controlData.Object%>" class="souce_name search_view width130">
		<option value="">不限</option>
	<%if(typeof searchItems !="undefined"){%>
		<%if(searchItems.Value!=null){%>
		<%_.each(dataSource, function(item){%>
		<%if(searchItems.Value.length>0){%>
			<%_.each(searchItems.Value, function(item1){%>

				<%if(item1!=item.Value){%>
				<option value="<%=item.Value%>"><%=item.Text%></option>
				<%}else{%>
				<option value="<%=item.Value%>" selected="selected"><%=item.Text%></option>
				<%}%>
			<%})%>
		<%}else{%>
		<option value="<%=item.Value%>"><%=item.Text%></option>
		<%}%>
		<%})%>
		<%}else{%>
			<%_.each(dataSource, function(item){%>
			<option value="<%=item.Value%>" title="<%=item.Text%>"><%=item.Text%></option>
			<%})%>
			<%}%>
	<%}else{%>
		<%_.each(dataSource, function(item){%>
		<option value="<%=item.Value%>"><%=item.Text%></option>
		<%})%>
	<%}%>
</select>

    如上所看到的,模板中用了多层if-else嵌套,夹杂各种<% %>以切割HTML和JS代码,结构与逻辑耦合度很高。可读性比較低。不利于改动。

  • 多个同类视图,在逻辑和结构上,仅仅有微小差异。但源码各写一套逻辑和视图,扩展性不高,造成大量代码冗余,不利于后期维护。

   乐帝做的第一步是将模板中逻辑提取出来,并将views.SearchItemView1、views.SearchItemView20、views.SearchItemView23,这三个视图模板採用Beyond
Compare软件进行文字比对,发现三个模板差异,这里的差异包含两部分内容:结构差异与逻辑差异。当中结构上标签名都同样,仅仅是每一个视图部分标签属性值不同,这些属性值可在View中处理。

   乐帝最初的解决方式,是通过调试每一个视图传入model值。发现视图构建差异在model值中Ctype属性上。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWluZ3lpbGVkaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

  于是针对以上三个视图。针对Ctype推断,构建不同视图不同的属性值。

textInputAttr:function(){
				var isDefault = this.model.get("IsDefault");
				var searchItems = this.model.get("searchItems");
				var defaultVal  = this.model.get("DefaultVal");
				var cType =this.model.get("Ctype");
				if(cType==1){
					this.$el.find("input[type='text']").addClass("search_box_prev");
					this.$el.find("input[type='text']").attr("data-rule-maxlength",300);
				}else{
					this.$el.find("input[type='text']").addClass("souce_name");
					this.$el.find("input[type='text']").attr("data-rule-maxlength",100);
					if(cType==23){
						this.$el.find("input[type='text']").addClass("default_word");
					}
				}//针对不同ctype设置input不同属性及值
				if(cType==1){
					if(typeof isDefault !="undefined"&&isDefault==1)
					{
						this.$el.find("input[type='text']").attr("defaultValue",defaultVal);
					};// 设置defaultValue属性
				}

				if(typeof searchItems !="undefined")
				{
					if(searchItems.Value!=null)
					{
						this.$el.find("input[type='text']").attr("value",searchItems.Value[0]);
					}
				}
				else{
					if(cType==1){
						if(typeof isDefault !="undefined"&&isDefault==1){
						this.$el.find("input[type='text']").attr("value",defaultVal);
						}
					}

				}//设置value属性值
			},
			checkInputAttr:function(){
				var searchItems = this.model.get("searchItems");
				var cType =this.model.get("Ctype");
				if(cType==1){
					this.$el.find("input[type='checkbox']").addClass("search_box_any");
				}else{
					this.$el.find("input[type='checkbox']").addClass("souce_name");
				}
					if((typeof searchItems !="undefined")&&(searchItems.Value!=null)&&(searchItems.Value.length>0)){
							_.each(searchItems.Value,function(item,value){
								var valLength = (cType==1)?

(searchItems.Value.length):(searchItems.Value.length-1);//推断採用何种表达式
								if(valLength==value){
									if(item){
										this.$el.find("input[type='checkbox']").attr("value",item);
										if(searchItems.Value[value]=="true")
											this.$el.find("input[type='checkbox']").attr("checked","checked");
									}else{
										this.$el.find("input[type='checkbox']").attr("value","");
									}
								}
							});
					}else{
						this.$el.find("input[type='checkbox']").attr("value","");
					}

			}//checkbox设置

这段代码存在的隐患是,依据Ctype做推断生成各视图,与model很相关,即与已有数据结构高度耦合。不利于扩展。假如在此逻辑上。我须要新加一个与上述三类视图同类的视图,那么还需在代码基础上。再次改进代码,增加对新视图Ctype推断,这显然不是我们想要的。

重构真正的需求是:构造一个通用类,将每一个视图共通的地方写入此类中。在不同子视图中继承此通用类,如有差异可覆写通用类方法,实现个性化定制。

   有了如上思路,接下来做的工作,就是依据之前採用文本比对得出的差异部分,进行分块处理。即构造原子函数,确定都有哪些原子块。而且一并写到通用类中。差异的部分在原子类中以空方法形式存在。在子函数中覆写通用类空函数,实现个性化订制。

var SingleInputView = Talent.ItemView.extend({
			onBeforeRender:function(){
				this.standLabel();//标准化标签
			},
			onRender:function(){
				this.textMaxlen(this.maxlength);
				this.setCheckboxVal(this.minus);
				this.SetTextInput();
				this.SetCheckboxInput();

			},
			standLabel:function(){
				var label = this.model.get("Label");
				if((label.length != 7)&&(label.length>6))
				{
					this.model.set({"Label":label.substring(0,6)+"…"});
				}
			},
			textAddClass:function(){
			},
			textMaxlen:function(length){
				this.$el.find("input[type='text']").attr("data-rule-maxlength",length);
			},
			setTextDefaultVal:function(){

			},
			setTextVal:function(){
				var isDefault = this.model.get("IsDefault");
				var searchItems = this.model.get("searchItems");
				var defaultVal  = this.model.get("DefaultVal");
				if(typeof searchItems !="undefined")
				{
					if(searchItems.Value!=null)
					{
						this.$el.find("input[type='text']").val(searchItems.Value[0]);
					}
				}
			},
			checkboxAddClass:function(){

			},
			setCheckboxVal:function(minus){
				var searchItems = this.model.get("searchItems");
				if((typeof searchItems !="undefined")&&(searchItems.Value!=null)&&(searchItems.Value.length>0)){
							_.each(searchItems.Value,function(item,value){
								var valLength =searchItems.Value.length-minus;//推断採用何种表达式
								if(valLength==value){
									if(item){
										this.$el.find("input[type='checkbox']").val(item);
										if(searchItems.Value[value]=="true")
											this.$el.find("input[type='checkbox']").attr("checked","checked");
									}else{
										this.$el.find("input[type='checkbox']").val("");
									}
								}
							});
					}else{
						this.$el.find("input[type='checkbox']").val("");
					}
			},
		});

    有些逻辑代码,仅仅是随着视图不同,变量不同。这里在父类中,构造带变量的方法。并在子类中设置属性值。传入父类方法中,如:

setCheckboxVal:function(minus){
				var searchItems = this.model.get("searchItems");
				if((typeof searchItems !="undefined")&&(searchItems.Value!=null)&&(searchItems.Value.length>0)){
					_.each(searchItems.Value,function(item,value){
						var valLength =searchItems.Value.length-minus;//推断採用何种表达式
						if(valLength==value){
							if(item){
								this.$el.find("input[type='checkbox']").val(item);
								if(searchItems.Value[value]=="true")
									this.$el.find("input[type='checkbox']").attr("checked","checked");
								}else{
									this.$el.find("input[type='checkbox']").val("");
								}
							}
					});

 在父类中构造了渲染后onRender回调函数,自己主动调用通用类及子视图方法:

onRender:function(){
				this.textMaxlen(this.maxlength);
				this.setCheckboxVal(this.minus);
				this.SetTextInput();
				this.SetCheckboxInput();

			}

这里用到两个this.SetTextInput()和this.SetCheckboxInput()两个方法,各自是在子类中实现,用以依照定制化需求,载入运行不同子类函数:

SetTextInput:function(){
				this.textAddClass();
				this.setTextDefaultVal();
				this.setTextVal();
			}

通用类,还用到一个onBeforeRender回调方法。用以在数据还没有渲染到模板时,对数据进行处理。

onBeforeRender:function(){
				this.standLabel();//标准化标签
			}

这样处理的优势在于,逻辑更清晰,而且充分利用此回调函数时序上的优势。

    通过对以上重构分析,我们能够得出重构的大体方向:

  • 对差异代码模块化,写入通用类的空方法中。
  • 仅仅有变量差异的代码,写入通用类中带參数方法中。
  • 最后调用方法,写在通用类中,并在子类中,构造定制化载入方法如SetTextInput方法的职能
时间: 2025-01-03 14:51:45

应聘者页面——文本输入框及单选多视图重构的相关文章

IPhone手机页面中点击文本输入框,弹出键盘,网页会放大,如何解决

在head标签中加入以上meta声明.具体属性可以谷歌/百度. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> 我查了下viewport,有几个属性:width - viewport的宽度 height - viewport的高度initial-scale - 初始的缩放比例minim

怎么让手机浏览器和微信焦点在文本输入框时不自动放大页面

方法一:禁止页面缩放 在head标签中加入以下代码 <meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0, user-scalable=no"> content的解释 width=device-width //宽度等于设备屏幕宽度 initial-scale=1.0 //初始缩放比例 minimum-

iOS自定义键盘和系统键盘切换且文本输入框一直获得焦点

UITextView用来进行文本输入.方法becomeFirstResponder和resignFirstResponder可以用来进行弹出系统键盘和收下系统键盘. 弹出系统键盘,文本输入框获得焦点.收下系统键盘,文本输入框失去焦点.那么,问题来了. 某个条件下,如点击界面上的某个按钮,展示自定义键盘.再次点击,切换到系统键盘.先收下系统键盘,再展示自定义键盘.比如移动自定义键盘View的Frame.Y.但这时因为收下系统键盘,本文输入框失去焦点.虽然展示了自定义键盘.但用户体验很不好.光标没有

java界面编程(2) ------ 按钮,文本输入框和文本区域

本文是自己学习所做笔记,欢迎转载,但请注明出处:http://blog.csdn.net/jesson20121020 上节创建了视窗,这是其他组件的容器,这节就来创建按钮. 创建按钮,只需要在希望出现的地方调用JButton的构造器即可. JButton是一个组件,它有自己的小窗口,能作为整个更新过程的一部分而自动被重绘.也就是说,你不必显示绘制一个按钮或者别的类型的控件,只要将其放在窗体上,它们可以自动绘制自己.采用上节的例子,在其基础上修改如下: public class SwingTes

类似微信的文本输入框

本文内容比较简单,给大家介绍一下微信的文本输入框是如何实现的,其实那只是个普通的文本框设了一个特殊的背景而已.具体微信怎么实现的,大家可以反编译下,这里介绍下如何实现这个背景. 可以先看下文章末尾的效果图,里面的文本框是不是和微信的比较像啊,下面说下实现思想: 首先,这种效果用.9图我不知道是否可以做出来.如果不用.9图的话,那就只能用drawable来写,这种drawable有点复杂,可以采用LayerList来实现,我的思想如下: 分三层实现,这里假设activity的背景是白色,第一层也(

手机中点击一个链接或文本输入框出现一个半透明的背景的问题

刚开始接触移动端的开发,发现input元素在iPhone中获得焦点时会出现一个半透明的背景,如图: 要去掉这个半透明背景需要设置以下样式 -webkit-tap-highlight-color:rgba(0,0,0,0); tap-highlight-color:rgba(0,0,0,0); 补充下网上的资料说明: 当你点击一个链接或输入框元素时,就会出现一个半透明的灰色背景. tap点击,highlight背景高亮,color颜色,颜色用数值调节 手机中点击一个链接或文本输入框出现一个半透明的

Text input(文本输入框)

Text input(文本输入框)是用来获得用户输入的绝佳方式. 你可以用如下方法创建: <input type="text"> 注意,input元素是自关闭的.

UIAlertView设置文本输入框格式

- (void)viewDidLoad { [super viewDidLoad]; UIAlertView * alertV = [[UIAlertView alloc] initWithTitle:@"textfield" message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:@"yes",@"no", nil]; [alertV setAlertViewStyle

Xcode--代码创建按钮,文本输入框

//创建按钮 UIButton *btn = [[UIButton alloc] init]; btn.frame = CGRectMake(0, 0, 100, 100); // 设置按钮在普通状态下的属性 // 设置背景图片 UIImage *normal = [UIImage imageNamed:@"btn_01.png"]; [btn setBackgroundImage:normal forState:UIControlStateNormal]; [btn setTitle