[组件] TopN 排行榜
废话不说,直接看代码,最后会给出一个示例:
/** * TopN 排行榜组件 * * @param {Array} data 排行数据 * @param {Number} N 即TopN的N * @param {Object} config 配置对象,格式为: * { * headers: [], // 每一项的header信息,如"北京"的header为"城市", * // 每一项都是HTML字符串 * // 也可以是Function,返回一段HTML代码 * showHeader: false, // 是否显示headers * * keys: [], // 每一项数据的key * values: [], // 如需定义结构,元素为Function,返回一段HTML * // 一般传null即可 * mainKey: 'xx', // 比较项 * sorted: false, // 数据是否已排序 * } * * headers(如果有), keys, values的长度保持一致 * * 如有色块,约定className为valueBar,如果色块旁边需附有值说明,约定className * 为valueLiteral,如下: * <div class="valueBar"></div><div class="valueLiteral">100</div> */ function TopN(data, N, config) { this.data = data; this.N = N; this.config = config || {}; // 对应的DOM节点 this.node = null; if (!this.config.sorded) { this.data.sort(this.sort()); } } TopN.prototype = { constructor: TopN, /** * @param {HTMLElement} parentNode 插入TopN组件的父元素 */ initDOM: function() { return function(parentNode) { if (!parentNode || parentNode.nodeType !== 1) return; var config = this.config, html = ['<table class="ui_TopN">'], i, len = config.keys.length; // 加col html.push('<colgroup>'); for (i = 1; i <= len; i++) { html.push('<col class="column' + i + '" />'); } html.push('</colgroup>'); // 拼装header部分 if (config.showHeader) { html.push('<thead><tr>'); var headers = config.headers; for (i = 0, len = headers.length; i < len; i++) { html.push('<th>'); html.push(headers[i] || ' '); html.push('</th>'); } html.push('</tr></thead>'); } // 拼装排行部分 html.push('<tbody>'); // 遍历前N 项数据 var keys = config.keys, key, values = config.values, value, items = this.data, item, j, size = values.length; for (i = 0, len = this.N; i < len; i++) { item = items[i]; html.push('<tr>'); // 遍历每项数据的keys for (j = 0; j < size; j++) { key = keys[j]; value = values[j]; if (key) { key = item[key]; } else { // key为空表示序号项 key = i + 1; } if (typeof value === 'function') { value = value(key); } else { value = key; } html.push('<td>'); html.push(value); html.push('</td>'); } html.push('</tr>'); } html.push('</tbody></table>'); var doc = parentNode.ownerDocument, div = doc.createElement('div'); div.innerHTML = html.join(''); this.node = div.firstChild; parentNode.appendChild(this.node); if ($('valueBar', this.node)[0]) { this.autoWidth(); } } }(), autoWidth: function() { var maxValue = this.data[0][this.config.mainKey], maxWidth; var valueBars = $('valueBar', this.node), bar, valueLiterals = $('valueLiteral', this.node), literal; // 进到这里,valueBars肯定不为空,所以就看valueLiterals是否为空 maxWidth = valueBars[0].parentNode.offsetWidth - (valueLiterals[0] ? valueLiterals[0].offsetWidth : 0); var data = this.data, mainKey = this.config.mainKey, percentage, width; for (var i = 0, len = valueBars.length; i < len; i++) { bar = valueBars[i]; percentage = data[i][mainKey] / maxValue; width = maxWidth * percentage; width = Math.max(4, width); bar.style.width = width + 'px'; if (!bar.innerHTML) { bar.innerHTML = ' '; } } }, /** * 排序方法,作为Array.prototype.sort()的参数 * @return {Function} */ sort: function() { var key = this.config.mainKey; return function(item1, item2) { if (item1 && typeof item1[key] !== 'undefined' && item2 && typeof item2[key] !== 'undefined') { var value1 = '' + item1[key]; var value2 = '' + item2[key]; return -1 * value1.localeCompare(value2); } } } } function $(className, node){ node = node || document; return node.getElementsByClassName(className); }
接着给例子,请先把TopN组件存为topN.js:
<!DOCTTYPE html> <html> <head> <script src="topN.js"></script> <script> var data = [ {name:'北京', input:5000}, {name:'上海', input:4000}, {name:'深圳', input:6000}, {name:'广州', input:3000}, {name:'天津', input:7000}, ] var top3 = new TopN(data, 3, { headers: [null, '城市', '值', '还是城市'], showHeader: true, keys: [null, 'name', 'input', 'name'], values: [null, null, function(s){ return '<div class="valueBar"></div><span class="valueLiteral">'+s+'</span>'; }, function(value){ return '<b>'+value+'</b>' }], mainKey: 'input' }) window.onload = function(){ top3.initDOM(document.body); } </script> <style> ol { border:2px solid blue; } .column3 { width:300px; } .valueBar { background:blue; } </style> </head> <body> </body> </html>