去年年末做了一个项目,因为第一次做前端管理职位,第一次做整个项目的前端架构很多东西都不熟悉,作为一次大胆的尝试。

  js方面的只有一个坑,那就是前端与后端的网络层封装,这一块是在后端的协助下开发的。网络层封装的过程中学到一点就是参数写成对象的形式是最佳实践,类似的还有消息提示框组件同理。

  项目开发过程中遇到一个比较麻烦的问题,由于项目周期比较短,为了促进开发进度,我提议让UI和前端同时进行,其实现在想一下,这是一个错误的决定,因为这导致后期项目修改bug的时候有相当一段时间内都是在修改UI层面的东西,需求一直修改也导致项目后期不停地修改ui。最主要是项目周期太短,团队协作没有经验,导致后期花费太多时间在一些细节上,而这些细节应该在项目初期解决,不是在项目完成之后里面改来改去。

  所以这次项目结束之后就和UI探讨项目开发的规范设计。后期讨论的结果是最好以组件的形式来设计ui  

  a:模态对话框的ui设计稿

  b:选项卡的ui设计稿

c:表格的ui设计稿

d:常用组件的ui设计稿

e:文字层面设计到正文字体,正文大小,正文文字颜色;一级标题字体大小,字体颜色;二级标题字体大小,字体颜色;

f:表单ui设计,表单中还设计到左侧的描述文字的字体大小,文字颜色,与右侧input的距离,以及input的边框颜色,边框圆角是多少。

h:font-family: "Microsoft YaHei","微软雅黑",Tahoma,Arial,Helvetica,STHeiti;其中,后面两张字体是苹果默认的字体,最佳实践应该是:font-family: "Microsoft YaHei","微软雅黑";因为不同的字体会产生不同的行间距和布局。

  

属性 属性值
字体 整站字体、正文、标题、字体颜色、字体大小、高亮字体(正常时的颜色,hover时的颜色)
modal title、body、footer、timer(定时器)
tab 活动的时候的样式、正常的时候的样式
table 表格的高度、对齐方式、hover时候的行颜色、无内容时的UI
无内容 无内容时的UI
分页组件 上一页、下一页、翻页
根据业务提取的组件 业务逻辑一定要清晰

编写js组件时,需要编写输入和输出都比较灵活的函数,比如模态对话框有可能需要定时器,有可能只需要一个按钮,有可能需要多个按钮,这些情况都需要考虑到。

以下是需要注意的几点

1、网络层封装,网络层应该封装在一个单例里面,单例名称定位HttpUtils;

e.g

 /**
* @Author Mona
* @Date 2016-12-08
* @description 网络层封装
*/ /**
* 封装基本请求方式
*/
window.BaseRequest = (function () {
//发送请求的所有方式
var request = {}; /**
* 基本请求
*/
function baseRequestFunc(type,param,url,async,contentType,dataType,processData,opt_suc,paramType,opt_error) {
var cur_url = contextPath+url;
var now_url = '';
//当把参数作为路由的一部分时此时的参数为字符串;
(paramType&&paramType=='url')?(now_url=cur_url+'/'+param+'.json'):(now_url=cur_url+'.json');
//这个里面是最基本的ajax
$.ajax({
type:type,
data:param,
url:now_url,
async:async,//默认为true
contentType:contentType,//默认为application/x-www-form-urlencoded
dataType:dataType,//默认为预期服务器返回的数据类型
processData:processData,//默认为true
success:function(data,textStatus,jqXHR){
if($.isFunction(opt_suc)){
opt_suc(data,textStatus,jqXHR);
}
},
error:function(jqXHR,textStatus,errorThrown){
            //其实,这里应该处理的更加灵活,比如说可以配置为可以选择使用默认的后端错误提示,或者是使用自己写的错误提示方式
renderErrorMsg(jqXHR,textStatus,errorThrown);
if($.isFunction(opt_error)){
opt_error();
}
}
}) } /**
* get异步请求方式
*/
request.get = function (param,url,callback,paramType) {
baseRequestFunc('get',param,url,true,'application/x-www-form-urlencoded','json',true,callback,paramType);
} /**
* get同步请求方式
* param {param} object
*/
request.sync_get = function (param,url,callback,paramType) {
baseRequestFunc('get',param,url,false,'application/x-www-form-urlencoded','json',true,callback,paramType);
} /**
* post异步请求方式
* param {param} object
*/
request.post = function (param,url,callback,paramType) {
baseRequestFunc('post',param,url,true,'application/json','json',true,callback,paramType);
} /**
* post的requestBean请求方式 这种请求方式适用于字段较多,且需要formdata方式上传文件
* param {param} object {param.files} array {param.fileNames} array {param.inputData} object
*/
request.post_multipart_form_data = function (param,url,callback,paramType,formData,opt_error) {
var form_data = new FormData();
if(param.files && param.files.length>0){
$.each(param.files,function(k,info_name){
//if(document.getElementById(info_name).files[0] !== undefined){
form_data.append('files',document.getElementById(info_name).files[0])
//}
})
} if(param.fileNames && param.fileNames.length>0){
$.each(param.fileNames,function(i,item){
form_data.append('fileNames',item);
})
}
if(formData && formData=='formdata'){
$.each(param.inputData,function(i,item){
form_data.append(i,item);
})
}else{
form_data.append('requestBean', new Blob([JSON.stringify(param.inputData)], {
type: "application/json"
}));
}
baseRequestFunc('post',form_data,url,true,false,'json',false,callback,paramType,opt_error);
} /**
* post的formdata请求方式
* param {param} object
*/
request.post_form_data = function(param,url,callback,paramType,opt_error){
var form_data = new FormData();
$.each(param,function(i,item){
form_data.append(i,item);
})
baseRequestFunc('post',form_data,url,true,false,'json',false,callback,opt_error);
} /**
* post的JSON.stringify(param)请求方式
* param {param} object
*/
request.post_string_data = function(param,url,callback,paramType,opt_error){
var cur_data = JSON.stringify(param);
baseRequestFunc('post',cur_data,url,true,'application/json','json',false,callback,paramType,opt_error);
}
return request;
})();
 var HttpUtils = (function () {

 //融资申请流程所有请求接口对象
var application = {}; /**
* 获取融资申请回显信息
*/
application.get_finance_info_echo_data = function(param,callback){
var url = '/finance/finance_info';
BaseRequest.get(param,url,callback);
}());

2、数据列表渲染等基础的常用的组件封装;

e.g:

 /**
* @Author Mona
* @date 2016-11-04
* @description 审核结束提交组件
* @param selector {string} 组件最大的容器名称
* @param maxLength {int} 组件中文字输入的最大长度
*/ function controlBtn(type,selector,curValLen){
var _this = this;
_this.selector = selector;
_this.maxlength = 140;
_this.curValLen = curValLen;
_this.type = type; _this.select_dom = $(_this.selector).find('select[data-role="control-btn"]');
_this.textarea_dom = $(_this.selector).find('textarea[data-role="control-btn"]');
_this.btn_dom = $(_this.selector).find('[data-role="target-btn"]');
_this.b_dom = $(_this.selector).find('[data-role="font-length"]>b'); _this.selectVal = $.trim(_this.select_dom.val());
_this.textareaVal = $.trim(_this.textarea_dom.val()); _this.setOn = function(){
_this.btn_dom.removeAttr('disabled');
} _this.setOff = function(){
_this.btn_dom.attr('disabled','');
} if(_this.selectVal!==''){
(_this.selectVal=='agree'||_this.type=='1' || _this.textareaVal.length>0)?_this.setOn():_this.setOff()
} else{
_this.setOff()
}
_this.init(); curValLen?_this.b_dom.text(_this.maxlength-curValLen):_this.b_dom.text(_this.maxlength);
} controlBtn.prototype = {
init:function(){
var _this = this;
var curSelectVal = _this.selectVal || '';
var curTextareaVal = _this.textareaVal || ''; _this.b_dom.text(_this.maxlength-_this.curValLen); _this.select_dom.on('change',function(){
curSelectVal = $.trim($(this).val());
console.debug('意见内容==='+curTextareaVal)
if(curSelectVal!==''){
(curSelectVal=='agree'||_this.type=='1' || curTextareaVal.length>0)?_this.setOn():_this.setOff()
} else{
_this.setOff()
}
}) _this.textarea_dom.bind('input propertychange',function(){
curTextareaVal = $.trim($(this).val()); if(curSelectVal!==''){
(curSelectVal=='agree'||_this.type=='1' || curTextareaVal.length>0)?_this.setOn():_this.setOff()
} else{
_this.setOff()
}
if(curTextareaVal.length>0){
if(curTextareaVal.length>_this.maxlength){
_this.b_dom.text(0);
$(this).val($(this).val().substring(0,140));
}else{
_this.b_dom.text(_this.maxlength-$(this).val().length);
}
}else{
_this.b_dom.text('140');
} }) }
}
 /**
* @param {option} object
* option.type tip| operableModal
* option.title 提示的标题 string
* option.info 提示的内容 string/dom
* option.historyRef 从哪里来回哪里去 string
* option.timer 停留的时间 int
* option.cancelText 左侧取消按钮的文案
* option.successText 右侧成功按钮的文案
* option.cancelCallback 取消的回调函数
* option.successCallback 成功的回调函数
*/
function whaleModal(option){
if($('#whale-modal-form').length>0){
$('#whale-modal-form').detach();
} if(option && typeof option !=='object'){//如果存在
alert('请传入正确的参数!');
} var type = (option&&option.type) || 'tip';
var title = (option&&option.title) || '提示';
var info = (option&&option.info) || '办理成功!';
var removeStore = (option&&option.is_remove_store)||false; var historyRef = '';
if(option&&option.historyRef){
historyRef = contextPath+option.historyRef;
}else if(window.sessionStorage["historyRef"]){
historyRef = window.sessionStorage["historyRef"]
}else{
historyRef = contextPath+'/anagement_page';
} var timer = (option&&option.timer) || 2000;
var cancelText = (option&&option.cancelText) || '取消';
var successText = (option&&option.successText) || '成功';
var cancelCallback = option&&option.cancelCallback;
var successCallback = option&&option.successCallback;
var is_operable_modal = (type == 'operableModal');
var cancel_able = (option&&option.cancelAble) || false; var h = '';
h+='<div id="whale-modal-form" class="modal fade" tabindex="-1" style="display: none;" aria-hidden="true" data-role="whale-modal">';
// h+='<div class="modal-backdrop"></div>';
h+='<div class="modal-dialog">';
h+='<div class="modal-content">';
h+='<div class="modal-header">';
h+='<span class="close" data-dismiss="modal">×</span>';
h+='<h4 class="blue bigger">'+title+'</h4>';
h+='</div>';
h+='<div class="modal-body">'+info+'</div>';
if(is_operable_modal){
h+='<div class="modal-footer">';
cancel_able?(h+='<button class="btn btn-sm btn-default" data-dismiss="modal" data-role="cancel">'+cancelText+'</button>'):'';
h+='<button class="btn btn-sm btn-primary" data-role="success">'+successText+'</button>';
h+='</div>';
}
h+='</div>';
h+='</div>';
h+='</div>';
$('body').append(h);
var cur_modal = $('#whale-modal-form');
var cancel_btn_dom = cur_modal.find('[data-role="cancel"]');
var success_btn_dom = cur_modal.find('[data-role="success"]');
cur_modal.modal('show'); //以下是给取消确定按钮注册点击事件
if(is_operable_modal){//如果不是需要自己去操作的modal 那么是不需要注册按钮的交互事件的
cancel_btn_dom.on('click',function(){
if($.isFunction(cancelCallback)){
cancelCallback();
}
});
success_btn_dom.on('click',function(){
if($.isFunction(successCallback)){
successCallback();
}
}); $('[id="whale-modal-form"] [data-dismiss="modal"]').on('click',function(){
window.location.href = historyRef;
})
} //以下是设置自动跳转的逻辑
if(!is_operable_modal){//如果是需要自己去操作的modal那么就不用自动跳转
setTimeout(function(){
cur_modal.modal('hide');
removeStore?window.sessionStorage.clear():'';
window.location.href = historyRef;
},timer);
} }

3、【js命名】为了更好的维护后期代码,变量命名以下面的规则命名

代表dom对象的js变量命名为 xx_dom;

后端返回的参数为data;

前端发送给后端的参数为param;

构造函数的命名首字母大写后面驼峰形式;

拿到回显数据方法名为 get_echo_data

设置XX以'set'开头命名方法

得到XX以'get'开头命名方法

sessionStorage,localStorage中存储的数据都以驼峰形式设置key

4、【css命名】ui层面的东西和数据交互层面的东西分开,方便维护

在dom中不要经常使用id属性以免系统会产生重复,如果一定要使用id那么请加上前缀,比如container-head ,container-body , container-footer

css样式表中不使用id作为选择器书写样式,一律使用class

有数据交互功能的dom结构都是用data-role-XX的形式增加属性,方便在js中使用,且css中不使用data-role开头的属性书写样式。

5、【函数】

前端开发过程中函数经常用到,这个时候函数的命名以及函数的通用性非常重要

多人合作开发时函数命名尤其重要【涉及全局(通用)函数和各自使用的函数】普通函数的命名以驼峰形式书写

通用函数以g开头,比如gModal,gGetRoleInfo

构造函数首字母大写,后面使用驼峰形式书写

与网络层相关的方法命名以下划线的方式书写比如 HttpUtils.get_finance_echo_data

功能 函数名称
拿到后端返回的回显数据 get_finance_echo_data
拿到机构信息 get_institution_info_data
   

复用性比较高的函数使用对象的形式来传入参数,这样方便后期维护,如果参数不是以对象的形式出现,那么后期方法的改造会出现非常大的问题,比如说,网络层封装的函数又可能有其他的业务需求,那么再传参数,就有可能影响其他地方的调用,这个时候使用对象的形式传入参数,会给开发带来极大的便利。

工作笔记——js前端规范的更多相关文章

  1. 工作笔记——js与文件上传下载

    1 js判断上传文件的后缀名,文件大小 //判断照片大小 function getPhotoSize(obj){ photoExt=obj.value.substr(obj.value.lastInd ...

  2. 《工作笔记:移动web页面前端开发总结》

    工作笔记:移动web页面前端开发总结 移动web在当今的发展速度是一日千里,作为移动领域的门外汉,在这段时间的接触后,发现前端开发这一块做一个小小的总结. 1.四大浏览器内核 1.Trident (I ...

  3. JS模块规范 前端模块管理器

    一:JS模块规范(为了将js文件像java类一样被import和使用而定义为模块, 组织js文件,实现良好的文件层次结构.调用结构) A:CommonJS就是为JS的表现来制定规范,因为js没有模块的 ...

  4. JS前端编码规范

    转自<前端编码规范之JavaScript>,网址:http://www.cnblogs.com/hustskyking/p/javascript-spec.html 一个是保持代码的整洁美 ...

  5. 前端学习:学习笔记(JS部分)

    前端学习:学习笔记(JS部分) 前端学习:JS学习总结(图解)    JS的简介 JS基本语法 JS内置对象 JS的函数 JS的事件 JS的BOM JS的DOM JS的简介 新建步骤 <body ...

  6. 前端、HTML+CSS+JS编写规范(终极版)

    HTMLCSS文档规范 HTML和CSS文档必须采用UTF-8编码格式: HTML文档必须使用HTML5的标准文档格式: HTMLCSS编写规范 HTML和CSS的标签.属性.类名.ID都必须使用小写 ...

  7. 前端规范之JS代码规范(ESLint + Prettier)

    代码规范是软件开发领域经久不衰的话题,几乎所有工程师在开发过程中都会遇到或思考过这一问题.而随着前端应用的大型化和复杂化,越来越多的前端团队也开始重视代码规范.同样,前段时间,笔者所在的团队也开展了一 ...

  8. 2016年第2周读书笔记与工作笔记 scrollIntoView()与datalist元素

    这一周主要是看了html5网页开发实例与javascript 高级程序设计,供以后翻阅查找.  html5网页开发实例第1章与第二章的2.1部分: 第1章内容: html5在w3c的发展史. 浏览器的 ...

  9. HTML/CSS/JS编码规范

    最近整理了一份HTML/CSS/JS编码规范,供大家参考.目录:一.HTML编码规范二.CSS编码规范三.JS编码规范 一.HTML编码规范 1. img标签要写alt属性 根据W3C标准,img标签 ...

随机推荐

  1. 001servlet的基本知识

    servlet的知识: l  1. servlet概念及相关接口简介 l  2. servet 执行过程 l  3. servlet路径映射 l  4. 缺省servlet          --应用 ...

  2. 【BZOJ】1500: [NOI2005]维修数列(splay+变态题)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1500 模板不打熟你确定考场上调试得出来? 首先有非常多的坑点...我遇到的第一个就是,如何pushu ...

  3. LoadRunner中的异常处理

    在脚本的Run-time Settings中,可以设置在脚本运行过程中发生错误的处理方式.进入到Run-time Settings中,切换到Miscellaneous标签页,可以看到Error Han ...

  4. 判断asp.net中session过期方法的比较

    重写继承page的OnInit()虚方法,在需要的界面上,继承这个类. 1.新建继承page类的类JudgeSession,实现接口成员. 2.重写OnInit()方法,判断session情况. 3. ...

  5. mathtype免费版下载及序列号获取地址

    在编辑公式这个方面来说,MathType是使用最多的一个工具,因为它操作简单,不需要复杂的学习过程就可以很快地掌握操作技巧,并且功能也比Office自带的公式编辑器完善很多,可以对公式进行批量修改.编 ...

  6. Boost-date_time库学习

    最近开了boost库的学习,就先从日期-时间库开始吧,boost的date_time库是一个很强大的时间库,用起来还是挺方便的. 以下代码只是入门级的简单学习,更详细的资料参考boost源码.  C+ ...

  7. django 模型中的计算字段

    models.py class Person(models.Model): family_name= models.CharField(max_length=20, verbose_name='姓') ...

  8. ArcGIS 空间数据库备份

    Expdp system/ddd@orcl directory=sdebak dumpfile=20170124_1_ServerBak.dmp schemas=(sde, ddd)

  9. 2D绘图引擎比较

    这个问题很普遍.最近在研究这个问题,在网上搜了一些资料,再结合自己的经验,谈谈自己的一些想法. 一.双缓存能提高绘图效率吗? 网上有篇文章:绘图效率完整解决方案——三种手段提高GDI/GDI+绘图效率 ...

  10. 【BZOJ2095】[Poi2010]Bridges 动态加边网络流

    [BZOJ2095][Poi2010]Bridges Description YYD为了减肥,他来到了瘦海,这是一个巨大的海,海中有n个小岛,小岛之间有m座桥连接,两个小岛之间不会有两座桥,并且从一个 ...