前言
最近碰到这样一个项目,业务逻辑全部都搬到前端,后端只提供API。
但是是在已有的项目上面做这样做,也就是在已有的项目上添加模块,这个模块采用前后端分工的方式来做。
因为各种原因,所以只有 jquery 可以用一下,万恶的ie。
jquery代码示例
先上代码,如果要运行,需要额外导入mock.js。
js
$(function() {
var list = {
init: function() {
// 初始化
this.$list = $("#list");
this.render();
},
render: function() {
// 渲染
this.getData();
this.bind();
},
renderData: function(data) {
// 渲染数据
var temp = {
listTemp: ''
}
$.each(data, function(i, iObj) {
temp.listTemp +=
'<tr data-id="' + iObj.id + '">'+
'<td>' + iObj.name + '</td>'+
'<td>' + iObj.price + '</td>'+
'<td>' +
'<span class="color-simple" style="background-color:' + iObj.color + '"></span>'+
'<span>' + iObj.color + '</span>'+
'</td>'+
'<td>' + iObj.name + '</td>'+
'</tr>';
});
this.$list.html(temp.listTemp);
},
bind: function() {
// 绑定事件
var self = $(this);
this.$list.on("click", "tr", function() {
alert($(this).data("id"));
});
},
getData: function() {
// 获取数据
var self = this;
Mock.mock('http://data.cn', {
'list|1-20': [
{
'id|+1': 1,
'name': '@name',
'price|1-1000': 1000,
'color': '@color',
'remark': '@remark'
}
]
});
$.ajax({
type: "get",
url: "http://data.cn",
success: function(data) {
self.renderData($.parseJSON(data).list);
}
});
}
}
list.init();
});
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" type="text/css" href="css/page.css"/>
</head>
<body>
<div>
<table class="table" border="1" cellpadding="0">
<thead>
<tr>
<th>名称</th>
<th>价格</th>
<th>颜色</th>
<th>备注</th>
</tr>
</thead>
<tbody id="list">
</tbody>
</table>
<script src="js/jquery.js" type="text/javascript" charset="utf-8"></script>
<script src="js/mock-min.js" type="text/javascript" charset="utf-8"></script>
<script src="js/list.js" type="text/javascript" charset="utf-8"></script>
</div>
</body>
</html>
css
body {
margin: 0;
font-family: "微软雅黑";
}
.table {
width: 80%;
margin: 20px auto;
border-collapse: collapse;
border-spacing: 0;
}
.table td,
.table th {
text-indent: 2%;
text-align: left;
}
.table thead tr {
height: 40px;
}
.table .body {
height: 400px;
overflow: auto;
display: block;
}
.table tbody tr {
height: 40px;
cursor: pointer;
}
.table tbody tr:nth-child(2n + 1) {
background-color: #eafff4;
}
.table tbody tr:nth-child(2n) {
background-color: #fff;
}
.table tbody tr:hover {
background-color: #b0e5ff;
}
.table tbody tr span {
vertical-align: middle;
}
.table tbody tr .color-simple {
width: 20px;
height: 20px;
margin-right: 10px;
border-radius: 2px;
display: inline-block;
}
解析
这是一个简单的例子,首先 js 内部执行顺序是这样的:
init(初始化)
render(渲染页面)
bind(绑定事件)getData(加载数据)
renderData(渲染数据)
init:
初始化,加载一个模块的开始。
主要用来缓存一些成员变量,如果是 jquery对象的 话就在之前加个 “$”,这样做是为了跟普通元素区别开来。
render:
渲染页面,顾名思义,就是渲染页面的函数。
在这个函数内部调用了 getData() 和 bind() 两个方法,getData()是为了去取数据,但为什么要在这里调用 bind() 方法呢,难道不应该在渲染完数据之后再绑定事件呢,说到 bind() 的时候再说为什么。
如果有另外的子模块需要渲染的话,也可以放在这里加载。 (比如在 list 模块下面有个 editPrice子模块,是一个单独的模块,就可以并列着写,然后在这里调用。)
$(function() {
// 我是父模块
var list = {
init: function() {
// 初始化
this.$list = $("#list");
this.render();
},
render: function() {
// 渲染
this.getData();
// 我调用了子模块
editPrice.init();
this.bind();
},
renderData: function() {},
bind: function() {},
getData: function() {}
}
// 我是子模块
var editPrice = {
init: function() {},
render: function() {},
renderData: function() {},
bind: function() {},
getData: function() {}
}
list.init();
});
bind:
绑定事件,所有的绑定事件全部都在这里处理。
这里定义了一个 “self” 变量,这是因为再绑定事件的 on 的函数内部由于作用域不同,所以调用不了其它 list 对象的成员变量和方法,所以事先缓存了起来,有的人会叫 _this、me、that 这些名字,我的习惯是叫 self。
关于上一点其实还可以再函数尾部加上 bind() 方法绑定作用域的,这样就不需要额外申明一个变量了,没有用是因为我不大习惯。。。
这里讲一下为什么 bind() 方法要放在 render() 里面,之所以不 renderData() 之后做是因为数据可能会重复调用,比如分页,就可能会重复调用 renderData() 这个方法,所以才利用了事件委托的办法。
getData:
获取数据,就是在这里用 ajax 和后端进行通信。
用 Mock.js 去模拟一个后端Api,如果你还不知道这个东西,点这里。
这里的 self 跟 bind() 里的 self 同理,为了调用成员方法 renderData()。
renderData:
渲染数据,用最原始的方法对代码拼接HTML。
拼接数据的时候,前后用单引号的话,就可以不用担心会跟里面 class 或者其它属性的双引号起冲突了。
拼接好数据之后再一口气 html 进事先在 init() 方法缓存好的 jquery对象 里。
另外: 如果我的模块要在其它的 js 的里调用怎么办,我的做法是 把数据绑定到 window 对象上。
$(function() {
var list = {}
list.init();
window.list = list;
});
最后
这样子的写法我觉得还是比较方便维护的。
如果有什么想跟我讨论的话,请私信。