| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- /**
- * License: MIT
- * Url: https://github.com/linjingming/sim-tree
- */
- ;(function (window, factroy) {
- if (!window || !window.document) {
- throw new Error('simTree need window')
- }
- factroy(window);
- })(typeof window !== 'undefined' ? window : this, function (window) {
- "use strict";
- var name = 'simTree';
- var version = '0.0.2';
- var document = window.document;
- var defaultConfig = {
- linkParent: false,
- response: {
- name: 'name',
- id: 'id',
- pid: 'pid',
- checked: 'checked',
- open: 'open',
- expand: 'expand',
- disabled: 'disabled'
- }
- };
- var err = function (msg) {
- throw new Error(msg);
- };
- var simTpl = function (tpl, data) {
- return tpl.replace(/\{\{(.+?)\}\}/g, function ($1, $2) {
- return data[$2] ? data[$2] : '';
- });
- };
- var Class = function (options) {
- if (typeof $ === 'undefined') {
- err(name + 'need jquery');
- }
- if (!$.isPlainObject(options)) return;
- if (!options.el) {
- err('你没有传el');
- }
- if (!(this instanceof Class)) {
- return new Class(options);
- }
- this.options = $.extend(true, {}, defaultConfig, options);
- this.init();
- };
- //初始化时候 用 checkId 存储选中的Id, 用openId 存储要展开的节点Id,
- var $prevA, checkId = [], openId = [];
- Class.prototype = {
- version: version,
- constructor: Class,
- /**
- * 绑定自定义事件
- *
- * @param type {string} 自定义事件名称
- * @param cb {function} 回调函数
- * @param isCover {boolean} 是否覆盖之前的回调
- * @return this {object} 实列对象
- */
- on: function (type, cb, isCover) {
- var isTriggered, args;
- this.handles[type] = this.handles[type] || [];
- isTriggered = this.handles[type].isTriggered;
- args = this.handles[type].args;
- if ($.isFunction(cb)) {
- if (isCover === true) {
- this.handles[type] = [cb];
- } else {
- this.handles[type].push(cb);
- }
- if (isTriggered) {
- cb.call(this, args);
- }
- }
- return this;
- },
- // 解除绑定的自定义事件
- off: function (type) {
- this.handles[type] = [];
- return this;
- },
- // 触发自定义事件
- trigger: function (type, args) {
- var i, len;
- this.handles[type] = this.handles[type] || [];
- i = 0;
- len = this.handles[type].length;
- // isTriggered 表示已经触发过
- this.handles[type].isTriggered = true;
- // args 参数
- this.handles[type].args = args;
- for (; i < len; i++) {
- this.handles[type][i].call(this, args);
- }
- },
- init: function () {
- var options = this.options;
- var data = options.data;
- this.handles = {};
- this.$el = $(options.el);
- this.data = data;
- this.event();
- this.render();
- },
- /**
- *
- */
- dataCallback: function () {
- var args = arguments;
- if (args.length === 1) {
- this.render(args[0]);
- } else {
- this.doRender(args[0], args[1]);
- }
- },
- /**
- * 把data解析成树型数据
- */
- parse: function (data) {
- var options = this.options;
- var response = options.response;
- var res = [];
- var map = {};
- var i = 0;
- var len = data.length;
- var id = response.id;
- var pid = response.pid;
- // 如果子节点异步加载 直接返回
- if (options.childNodeAsy) {
- return data;
- }
- for (; i < len; i++) {
- var item = data[i];
- var tempId = item[id];
- // 如果节点有children这个字段则判断数据本就是树型结构 直接返回原始数据
- if (item.children) {
- return data;
- }
- if (tempId) {
- map[tempId] = item
- }
- }
- for (i = 0; i < len; i++) {
- var item = data[i];
- var tempPid = item[pid];
- var parent = map[tempPid];
- if (tempPid && parent) {
- (parent.children || (parent.children = [])).push(item);
- } else {
- res.push(item);
- }
- }
- return res;
- },
- render: function (data) {
- var data = data || this.data;
- if ($.isFunction(data)) {
- data({}, this.dataCallback.bind(this))
- }
- if ($.isArray(data)) {
- data = this.parse(data);
- this.doRender(this.$el, data);
- }
- },
- doRender: function ($el, data, level) {
- var self = this;
- var options = this.options;
- var response = options.response;
- var len = data.length;
- var i = 0;
- var item;
- var id = response.id;
- var text = response.name;
- var level = level || 1;
- var tpl = '<i data-type="{{asy}}" class="sim-tree-spread {{spreadIcon}}"></i><a href="javascript:;"><i class="sim-tree-checkbox"></i>{{text}}</a>';
- var isRootEle = ($el === this.$el);
- var $outEl = $(document.createElement('ul'));
- var oLi, $li, hasChild, disabled, expand;
- var asy = options.childNodeAsy ? 'asy' : '';
- if (false && !options.check) { // 单选
- tpl = tpl.replace('<i class="sim-tree-checkbox"></i>', '');
- }
- for (; i < len; i++) {
- item = data[i];
- oLi = document.createElement('li');
- hasChild = !!item.children;
- disabled = item[response.disabled];
- expand = item[response.expand] || false;
- oLi.innerHTML = simTpl(tpl, {
- asy: asy,
- text: item[text],
- spreadIcon: hasChild ? (expand ? 'sim-icon-d' : 'sim-icon-r') : 'sim-hidden'
- });
- oLi.setAttribute('data-level', level);
- oLi.setAttribute('data-id', item[id]);
- disabled && oLi.setAttribute('class', 'disabled');
- $li = $(oLi);
- $li.data('data', item);
- if (expand) {
- $outEl.addClass("show");
- }
- $outEl.append($li);
- if (hasChild) {
- this.doRender($li, item.children, level + 1);
- }
- item[response.checked] && checkId.push(item[id]);
- item[response.open] && openId.push(item[id]);
- }
- len && $el.append($outEl);
- if (isRootEle) {
- $outEl.addClass('sim-tree');
- this.trigger('done', data);
- $.each(openId, function (index, id) {
- self.expandNode(id);
- });
- this.setSelected(checkId);
- } else {
- // 异步加载移除loading
- if (options.childNodeAsy) {
- this.hideLoading($el.find('.sim-tree-spread'));
- $outEl.addClass('show');
- }
- }
- },
- /**
- *
- */
- event: function () {
- var self = this;
- this.$el.off('click').on('click', function (e) {
- var $tar = $(e.target);
- if ($tar.hasClass('sim-tree-spread')) {
- self.spread.call(self, $tar);
- }
- if ($tar.hasClass('sim-tree-checkbox')) {
- $tar = $tar.parent();
- }
- if ($tar[0].tagName.toLowerCase() === 'a') {
- self.clickNode.call(self, $tar);
- }
- return false;
- });
- this.$el.on('selectstart', function () {
- return false;
- });
- if (this.options.done) {
- this.on('done', this.options.done);
- }
- if (this.options.onClick) {
- this.on('click', this.options.onClick);
- }
- if (this.options.onChange) {
- this.on('change', this.options.onChange);
- }
- if (this.options.onSearch) {
- this.on('search', this.options.onSearch);
- }
- },
- // 展开或收起
- spread: function ($el) {
- if ($el.hasClass('sim-icon-r')) {
- this.doSpread($el, true);
- } else {
- this.doSpread($el, false);
- }
- },
- // 添加loading
- showLoading: function ($el) {
- $el.addClass('sim-loading');
- },
- // 移除loading
- hideLoading: function ($el) {
- $el.removeClass('sim-loading');
- },
- /**
- * 展开或者收起
- * @param $el {jquery object} jquery对象
- * @param status {boolean} true 展开 false收起
- */
- doSpread: function ($el, status) {
- var $pli = $el.parent();
- var $ul = $pli.children('ul');
- var item = $pli.data('data');
- if (!item.children) return;
- if (status) {
- $el.removeClass('sim-icon-r').addClass('sim-icon-d');
- // 异步加载子节点
- if ($el.data('type') === 'asy' && $.isFunction(this.data)) {
- this.showLoading($el);
- this.data($pli.data('data'), this.dataCallback.bind(this, $pli));
- $el.data('type', '');
- }
- $ul.addClass('show');
- } else {
- $el.removeClass('sim-icon-d').addClass('sim-icon-r');
- $ul.removeClass('show');
- }
- },
- // 点击节点
- clickNode: function ($tar) {
- var self = this;
- var $pli = $tar.parent();
- var $li = this.$el.find('li');
- var len = $li.length;
- var i = 0;
- var list = [];
- var data, $childUl, $childCheck;
- var isChange = false;
- if ($pli.hasClass('disabled')) return;
- if (this.options.check) {
- isChange = true;
- this.doCheck($tar.find('.sim-tree-checkbox'));
- if (this.options.linkParent) {
- $childUl = $pli.children('ul');
- $childCheck = $childUl.find('.sim-tree-checkbox');
- $.each($childCheck, function () {
- self.doCheck($(this), $pli.data('checked'), true);
- });
- }
- for (; i < len; i++) {
- data = $li.eq(i).data();
- if (data['checked'] === true) {
- list.push(data.data);
- }
- }
- } else {
- //单选模式下仅保留当前选择
- $(".sim-tree-checkbox", this.$el).removeClass("checked");
- $(".sim-tree-checkbox", $tar).addClass("checked");
- if ($prevA) {
- $prevA.css('font-weight', 'normal');
- }
- $tar.css('font-weight', 'bold');
- $prevA = $tar;
- data = $pli.data('data');
- list = [data];
- if (this.sels) {
- isChange = !(this.sels[0] === data);
- } else {
- isChange = true;
- }
- }
- this.sels = list;
- this.trigger('click', list);
- isChange && this.trigger('change', list);
- },
- // 多选设置选中状态
- doCheck: function ($check, status, flag) {
- var self = this;
- var $li = $check.closest('li');
- var $childUl, $childUlCheck;
- var data = $li.data();
- if (typeof status === 'undefined') {
- status = !data.checked;
- }
- if (status === true) {
- $check.removeClass('sim-tree-semi').addClass('checked');
- } else if (status === false) {
- $check.removeClass('checked sim-tree-semi');
- } else if (status === 'semi') {
- $check.removeClass('checked').addClass('sim-tree-semi');
- }
- $li.data('checked', status);
- if (this.options.linkParent === true) {
- !flag && this.setParentCheck($li);
- }
- },
- setParentCheck: function ($li) {
- var $pul = $li.parent('ul');
- var $pli = $pul.parent('li');
- var $lis = $pul.children('li');
- var $plicheck = $pli.find('>a .sim-tree-checkbox');
- var checked = [];
- var maxLen = $lis.length;
- var isChecked, checkedLen;
- if (!$pli.length) return;
- if ($li.find('>a .sim-tree-checkbox').hasClass('sim-tree-semi')) {
- this.doCheck($plicheck, 'semi');
- return;
- }
- // 获取同级的选中状态
- $.each($lis, function () {
- isChecked = $(this).data('checked');
- isChecked === true && checked.push($(this));
- });
- checkedLen = checked.length;
- // 如果选中长度跟li长度一样 则父级选中
- if (maxLen === checkedLen) {
- this.doCheck($plicheck, true);
- }
- // 如果选中长度为0 则父级没选中
- if (!checkedLen) {
- this.doCheck($plicheck, false);
- }
- // 如果没有全选中 则父级设置成半选状态
- if (checkedLen >= 1 && checkedLen < maxLen) {
- this.doCheck($plicheck, 'semi');
- }
- },
- // 树搜索
- search: function (val) {
- if (!this.$el) return;
- var val = $.trim(val);
- var $li = this.$el.find('li');
- var i = 0;
- var len = $li.length;
- var text, $mLi, data;
- var res = [];
- var reg = new RegExp(val, 'i');
- $li.hide().children('.sim-tree-spread').addClass('sim-hidden');
- for (; i < len; i++) {
- $mLi = $li.eq(i);
- text = $mLi.children('a').text();
- data = $mLi.data('data');
- if (!val) {
- $mLi.show();
- if (data.children) {
- $mLi.children('.sim-tree-spread').removeClass('sim-hidden');
- }
- } else if (text.search(reg) !== -1) {
- if (parseInt($mLi.data('level')) !== 1) { // 不是顶级的需要展开父节点
- this.expandNode(data[this.options.response.pid]);
- }
- $mLi.parents('li').add($mLi).show();
- res.push($mLi);
- }
- }
- this.trigger('search', val);
- },
- // 展开某节点
- expandNode: function (id) {
- var $li = id.addClass ? id : this.$el.find('[data-id=' + id + ']');
- var data = $li.data('data');
- var pid = data[this.options.response.pid];
- var $spread = $li.children('.sim-tree-spread');
- var level = parseInt($li.data('level'));
- if (data.children && $spread.length) {
- $spread.removeClass('sim-hidden');
- this.doSpread($spread, true);
- }
- if (level !== 1) {
- this.expandNode(pid);
- }
- },
- // 设置选中
- setSelected: function (id) {
- var self = this;
- var aId = id;
- var aData = [];
- var res = [];
- if (typeof (aId) === 'string' || typeof (aId) === 'number') {
- aId = [aId];
- }
- if (!$.isArray(aId)) {
- return;
- }
- if (!this.options.check) { // 单选
- aId = [aId[0]];
- }
- $.each(aId, function (index, id) {
- var $li = self.$el.find('[data-id=' + id + ']');
- var $a = $li.children('a');
- var $check = $a.children('.sim-tree-checkbox');
- var data = $li.data('data');
- if (!$li.length) {
- return true;
- }
- if (!$check.length) { // 单选
- $a.css('font-weight', 'bold');
- } else { // 多选
- self.doCheck($check, true);
- }
- if (parseInt($li.data('level')) !== 1) { // 不是顶级的需要展开父节点
- self.expandNode(data[self.options.response.pid]);
- }
- aData.push(data);
- res.push($li[0]);
- });
- self.sels = aData;
- self.trigger('click', aData);
- },
- // 获取选中值
- getSelected: function () {
- return this.sels;
- },
- // 设置禁止选中
- disableNode: function (id) {
- var self = this;
- var aId = id;
- if (typeof (aId) === 'string' || typeof (aId) === 'number') {
- aId = [aId];
- }
- if (!$.isArray(aId)) {
- return;
- }
- $.each(aId, function (index, id) {
- var $li = self.$el.find('[data-id=' + id + ']');
- $li.addClass('disabled');
- });
- },
- // 树销毁
- destroy: function () {
- this.$el.html('');
- for (var key in this) {
- delete this[key]
- }
- delete this;
- },
- // 树刷新
- refresh: function (data) {
- this.$el.html('');
- this.render(data);
- }
- }
- window[name] = Class;
- $.fn[name] = function (opt) {
- opt = $.extend(true, {el: this}, opt);
- return Class(opt);
- };
- return Class;
- });
|