开发网站的时候,尤其是一些后台管理系统,会出现很多重复性工作,为追求方便快捷解决方法往往是简单粗暴的复制粘贴。复制粘贴会让代码散发出惹人讨厌的坏味道每个程序员都知道,但有时候除此之外别无解决方案,如项目中的html文件,除了头尾部份, 明明有很多冗余的代码存在于项目的html文件当中,但对于提取它们却总是束手无策。
这类代码即有html也有js
html代码如,两张列表页面, 除了表的列数和具体的内容以外, html结构的规格都是相同的,但是我们在新建页面时,这类重复的table、tr、td总是不可避免的需要将之填充在页面之中。此外, 不同列表页面中的搜索表单html结构也存在同样的问题。 甚至不同的添加和编辑数据的页面, 展示数据的页面, html都会存在不同程度的重复
js代码如,不同页面表单数据的收集, 利用ajax发送到服务端。 或者其它一些提取成公用函数显得小题大做以及难以提取成公用函数的js代码等
虽然这种重复是在可接受范围之内的,毕竟处理这一点重复所增加的额外工作量相对于整体工作来说是微不足道的。然而, 积少成多, 时间久了,这类非有效性工作所带来的影响也足以拖慢我们的工作效率。
如何一劳永逸解决这类不影响到根本却时不时蹦出来让你难受一下而你又对它无可奈何的问题?我前段时间寻找到了一种确定理论上可行并已经付诸实践的方案,而且在应用过程中带来了出人意料的成效。下面, 我对这种做法的原理进行描述
首先,问题的根本在于html语言不像编程语言那样具备灵活提取公共代码的能力,而冗余代码带来的问题会使用编码效率降低,因此,消除冗余代码就意味着解决了困扰我们的问题。html在这方面能力有限,然而,我们可以js代替之
假如要制作一张表单提交页面
我们可以把它分解成多个部份,然后组合在一起形成一张完整的页面
以红色标注的便是每一个小部份,我们可以用js控件来进行抽像,换言之, 用一个js对象表示这页面中的小部分, 一整张页面便有许多个js对象组成,js对象的代码大致长这样子(es6代码)
class input extends control.fbase {
renderHtml() {
let placeholder =this.dataSource.get("placeholder") || "";
let html = `<inputtype="text" placeholder="${placeholder}"/>`;
return html;
}
getValue() {
let result =this.getElement().value;
return result;
}
setValue(value) {
let ele = this.getElement();
ele.value = value;
}
}
这代表一个input控件,组成页面的其它控件也可如此实现
这样做的好处在于,抽象出来的控件不仅仅是html表单元素,可以是千变万化任意方式的组合
就是这一个js效果也可以写成一个控件,对于外部来说, 它只要实现特定接口就行了, 比如说获得值 ,获得控件的html等。 外部代码初始化这些控件,统一管理, 如获得各控件的html,拼接后生成页面;获得各控件的值,转换成json发送至服务器
生成页面的代码
let control1 = new Input();
let control2 = new Select();
let control3 = new CheckBoxList();
let control4 = new AttachControl();
let controlList = [control,control2,control3,control4];
let pageHtml =controlList.map(item=>item.renderHtml()).join("");
document.body.innerHTML = pageHtml;
获得结果发送至服务器的代码
let control1 = new Input();
let control2 = new Select();
let control3 = new CheckBoxList();
let control4 = new AttachControl();
let controlList = [control,control2,control3,control4];
let result =controlList.map(item=>item.getValue());
$.POST(url, result);
这便是我们讲解的方法的思路的最简单的实现。控件之间是可以组合的,只需要实现有限数量的控件,便可以组合出功能各不相同的页面,将代码复用能力最大化,项目中页面越多,开发起来越省力。组合方式的表达可以使用配置文件,配置文件需要一定的规范,这种规范可以随程序员喜好自已定制,这里给出一个以我的需求定制的配置文件代码
这种以xml表示的配置文件的含意并不难理解
<listen class=’gzwsw_send_item’></listen>
这段表示服务器端数据处理的类型(class),其它的就不做详细解释了。这个配置表示之前文章中的示例页面,代码量更少,几乎没有任何噪音。
这种设计的整个工作流程大致如下
如此,便可以开发员把注意力集中于处理需求中纯粹的业务逻辑,不受一些原本就无甚意义的干扰,增加工作效率, 提升作体验。
当然,这种方式也存在一定局限,不适合于任何场景。如果一个项目中有许多页面结构相同或者相似的页面,那么非常适合使用这种方式,如网站后台管理系统,各种界面朴素的业务管理系统。一些页面花哨,需要前后端程序员配合的项目则不适合以这种方式实现。因为这种方式虽然很好的解决了冗余代码的问题, 但却是以一部分的灵活性为代价的, 因此不适合在html结构需要高度定制的场景。
换个角度,我们也可以把这种实现看作是一个我们自己开发的框架,这个框架可以非常优雅高效的解决部分特定的问题。然而,除此之外的其它方向或领域,它并不擅长 , 最好的解决方案并不在这里, 需要寻找另外方法或者原生实现。
这篇文章只是提供一个实现的思路,并没有事无巨细的讲解整个解决方案,对于文章中思路的应用,还要看大家的理解程度的和兴趣,因为要完全的实现整个方案的方方面面有不小的工作量,我花了大概有两个星期,才让这个框架可以真正在项目中完美使用。
对于这个方案,灵感来自于asp.net的webform,虽然为了让这个框架更贴近于我所开发项目的需求,已经跟webform的运行模式没什么关系了,但框架的设计中还是存在的webform的影子, 因此,懂得webform的程序,应该更容易接受这种模式。