lu2
Version:
Simple and flexible UI component library based on native HTML and JavaScript
420 lines (369 loc) • 11.1 kB
JavaScript
/**
* @Table.js
* @author xunxuzhang
* @version
* Created: 15-06-28
*/
define(function(require, exports, module) {
//require('plugin/jquery');
// 复选框
if (!window.addEventListener) {
require.async('common/ui/Checkbox');
}
var DropList = require('common/ui/DropList');
var Pagination = require('common/ui/Pagination');
var Tips = require('common/ui/Tips');
// 加载动效
require('common/ui/Loading');
/**
* 项目表格组件
* @使用示例
* new Table($('#table'), {});
*/
var LOADING = 'loading';
var CHECKED = 'checked', DISABLED = 'disabled', SELECTED = 'selected',
selector = '[type=checkbox]';
// 一些元素类名
var CL = {
// 列表结构相关
container: 'table-x',
size: 'table-size',
empty: 'table-null-x',
// 错误
error: 'table-error-x',
// 加载
loading: 'ui-loading',
// 下面是分页相关的:
// 总数据量
total: 'table-num-length',
// 每页系那是数目
every: 'table-num-every',
// 分页左侧容器
data: 'table-page-data',
// 分页列表(右侧)容器
page: 'table-page'
};
// 表格
var Table = function(el, options) {
if (!el || !el.length) return this;
var defaultPageOptions = {
// 总数据量
length: 0,
// 每页显示数目
every: 15,
// 当前的页数
current: 1
};
// 默认参数
var defaults = {
// 请求列表数据的Ajax参数,同jQuery $.ajax() 参数
// 默认dataType为'json'
ajaxOptions: { },
// 分页数目下拉内容
pageList: [15, 30, 50],
// 一般情况下,pageoptions参数都是使用默认值
pageOptions: defaultPageOptions,
// 对请求的JSON数据进行处理,并返回
parse: function(data) {
if (typeof data == 'string') {
return data;
}
return '';
},
events: {
// 事件,例如
// 'a.icon-del:click': function() { /* ... */ }
},
// 列表内容显示的回调
onShow: $.noop,
// 点击分页的回调
// 如果存在,会替换本组件内置的分页Ajax处理
onPage: null,
// 点击复选框的回调
onCheck: $.noop
};
var params = $.extend({}, defaults, options || {});
var self = this;
// 表格列表需要的一些元素
var container, table, size, empty, loading = $(), total, every, data, page;
if (el.hasClass(CL.container)) {
container = el;
} else {
container = el.parents('.' + CL.container);
}
table = container.find('table');
size = container.find('.' + CL.size);
empty = container.find('.' + CL.empty);
if (params.ajaxOptions.url) {
// 这句话2作用,1是可能没有初始的loading HTML, 2是为之后的动画做准备
size.loading({ create: true }).unloading();
loading = container.find('.' + CL.loading);
}
total = container.find('.' + CL.total);
every = container.find('.' + CL.every);
data = container.find('.' + CL.data);
page = container.find('.' + CL.page);
// 元素之类
this.el = {
container: container,
size: size,
table: table,
empty: empty,
loading: loading,
total: total,
every: every,
data: data,
page: page
};
// 回调之类
this.callback = {
parse: params.parse,
page: params.onPage,
show: params.onShow
};
// 数据之类
this.num = $.extend({}, defaultPageOptions, params.pageOptions);
// 一些事件
// 单复选框选中效果
table.delegate(selector, 'click', function() {
var tdCheckbox = table.find('td ' + selector), isAllChecked = false, isAllUnchecked = false;
// 全选
if ($(this).parents('th').length) {
isAllChecked = $(this).prop(CHECKED);
isAllUnchecked = !isAllChecked;
tdCheckbox.prop(CHECKED, isAllChecked);
} else {
var lengthChecked = tdCheckbox.filter(':checked').length;
// 是否取消全选
isAllChecked = (tdCheckbox.length == lengthChecked);
// 是否全部非选
isAllUnchecked = (lengthChecked == 0);
}
// 改变全选复选框的状态
table.find('th ' + selector).prop(CHECKED, isAllChecked);
// IE7-IE8必须根据真实选中态初始化属性值
if ($.fn.propMatch) {
table.find(selector).propMatch();
}
// 根据复选框状态决定表格行样式
tdCheckbox.each(function() {
$(this).parents('tr')[$(this).prop(CHECKED)? 'addClass': 'removeClass'](SELECTED);
});
// 回调
params.onCheck.call(this, isAllChecked, isAllUnchecked, table);
});
// 点击列表,只有不是a元素或者是复选框本事,选中当前复选框
table.on('click', function(event) {
var target = event.target, checkbox = null;
if (target && /^a|input|label|th$/i.test(target.tagName) == false) {
checkbox = $(target).parents('tr').find(selector);
if (checkbox.length && checkbox.prop(DISABLED) == false) {
checkbox.trigger('click');
}
}
});
// 其他些事件
$.each(params.events, function(key, value) {
var arr_selector_type = key.split(':');
if (arr_selector_type.length == 2 && $.isFunction(value)) {
table.delegate(arr_selector_type[0], arr_selector_type[1], value);
}
});
// 切换每页数目的dropList
// 求得当前选中的分页数
// 优先本地存储
var storeId = table.attr('id'), currentEvery = params.pageOptions.every;
if (storeId && window.localStorage && localStorage[storeId]) {
currentEvery = localStorage[storeId];
self.num.every = currentEvery;
}
// 赋值
every.html(currentEvery);
this.pageList = new DropList(every.parent(), $.map(params.pageList, function(number) {
return { value: '<span class="'+ CL.every +'">' + number + '</span>' };
}), {
width: 60,
onSelect: function() {
var everyNew = $(this).text();
if (window.localStorage && storeId) {
localStorage[storeId] = everyNew;
}
// 如果分页有变
if (self.num.every != everyNew) {
// 改变分页数目
self.num.every = everyNew;
// 当前页重置为1
self.num.current = 1;
// 重新刷新
self.ajax();
}
}
});
// ajax数据
this.ajaxOptions = params.ajaxOptions;
// 获得数据
this.ajax();
};
Table.prototype.ajax = function(options) {
options = options || {}
var self = this;
// 防止连续请求
if (self.ajaxing == true) return this;
// 一些存储在实例对象上的数据
var el = this.el, callback = this.callback, num = this.num;
// 列表容器元素
var tbody = el.table.find('tbody');
// ajax请求参数
var ajaxParams = $.extend({ dataType: 'json' }, this.ajaxOptions, options);
// ajax地址是必需项
if (!ajaxParams.url) return this;
// ajax的data数据和几个回调走的是合并策略
var data = options.data || {}, dataOptions = {};
if ($.isFunction(this.ajaxOptions.data)) {
dataOptions = this.ajaxOptions.data() || {};
}
ajaxParams.data = $.extend({}, {
current: num.current,
every: num.every
}, dataOptions, data);
num.current = ajaxParams.data.current;
num.every = ajaxParams.data.every;
// 回调额合并
var success = ajaxParams.success, error = ajaxParams.error, complete = ajaxParams.complete;
ajaxParams.success = function(data) {
var html = callback.parse(data);
tbody.html(html || '');
if (!html) {
el.empty.show();
}
// 修改总数值并显示
var total = data.total;
if (!total && total !== 0) {
total = data.data && data.data.total;
}
if (total || total == 0) {
el.total.html(total);
self.num.length = total;
} else {
// 如果ajax返回的没有列表总数值,使用之前的值
total = num.length;
}
el.data.show();
// 显示分页
if (self.pagination) {
self.pagination.num = self.num;
self.pagination.show();
} else {
self.pagination = new Pagination(el.page, {
length: total,
current: num.current,
every: num.every,
mode: num.mode || 'long',
onClick: function(page, current) {
// 更新分页
self.num.current = current;
// 自定义分页事件
if ($.isFunction(self.callback.page)) {
self.callback.page.call(this, page, current);
} else {
// 显示小loading
$(this).addClass(LOADING);
// ajax再次
self.ajax();
}
}
});
}
// tips效果
el.table.find('.ui-tips').tips();
if ($.isFunction(success)) {
success(data);
}
}
ajaxParams.error = function(xhr, status) {
var elError = el.size.find('.' + CL.error);
if (elError.size()) {
elError.show();
} else {
elError = $('<div class="'+ CL.error +'">网络异常,数据没有获取成功,您可以稍后重试!</div>');
el.size.append(elError);
}
if ($.isFunction(error)) {
error(xhr, status);
}
}
ajaxParams.complete = function() {
// 去除中间的大loading
el.loading.hide();
// 去掉分页的小loading
if (this.pagination) {
this.pagination.el.container.find('.' + LOADING).removeClass(LOADING);
}
if ($.isFunction(complete)) {
complete();
}
// 呈现与动画
self.show();
// 请求结束标志量
self.ajaxing = false;
}
// 滚动到表格上边缘
var scrollTop = $(window).scrollTop();
if (el.table.offset().top < scrollTop) {
scrollTop = el.container.offset().top;
$('html, body').animate({
scrollTop: scrollTop
}, 'fast', function() {
if (this == document.body) {
self.ajaxing = true;
$.ajax(ajaxParams);
}
});
} else {
self.ajaxing = true
$.ajax(ajaxParams);
}
// 显示loading
el.loading.css('top', '0');
if (el.loading.css('display') == 'none') {
el.loading.height(el.size.height() - el.table.find('thead').height());
}
// 微调圈圈的位置
var distance = el.loading.height() - $(window).height();
if (distance > 0) {
el.loading.css('top', -0.5 * distance);
}
// loading显示
el.loading.show();
// 其他元素隐藏
el.empty.hide();
el.size.find('.' + CL.error).hide();
el.table.find('tbody').empty();
this.scrollTop = scrollTop;
//setTimeout(function() {
//$.ajax(ajaxParams);
//}, 500);
return this;
}
Table.prototype.show = function() {
this.el.size.unloading(this.el.size.data('animation'));
// 显示loading
this.el.loading.css('top', '0');
// Chrome, IE10+高度变小时候,会先置顶,在变化,导致晃动,影响体验,通过记录scrollTop修正,FireFox没有此问题
$(window).scrollTop(this.scrollTop);
//没有全选
var chkAll = this.el.table.find('th input' + selector);
if (chkAll.length) {
chkAll.prop(CHECKED, false);
if ($.fn.propMatch) {
chkAll.propMatch();
}
}
// 列表显示的回调
if ($.isFunction(this.callback.show)) {
this.callback.show.call(this);
}
return this;
}
return Table;
});