熟悉Easyui的朋友可能都比较熟悉panel,因为panel是布局和其它一些组件的基础,在1.2.5版本中,panel的标题部分增加了对工具条的支持(1.2.4可能也支持,但是不支持写在HTML文档中的工具条)。
现象描述:
给panel附加工具条有两种方式:
Name | Type | Description | Default |
---|---|---|---|
tools | array,selector | Custom tools, possible values: 1) an array, each element contains iconCls and handler properties. 2) a selector that indicating the tools |
[] |
- 一种是定义数组数据,数组每个对象包含iconCls和handler属性,分别用于图标和事件;
- 另一种就是类似css选择器的字符串形式,Easyui会根据这个字符串到当前页面找字符串表达式选取到的DOM,将其作为panel的tools:
对于第一种方式,申明javascript数组对象,肯定是可以实现多个panel共用一个数组对象的;对于第二种方式就不尽如人意了,一个源tools只能被一个panel使用。个人觉得第二种方式源tools只能被一个panel使用是不合理的,有时候我们很有可能多个panel共用一个tools,而且写在HTML里面更直观,所以第二种方式的tools需要改进。
源码分析:
我们来分析一下生成panel标头部分的源码:
function _173(_174){ var opts = $.data(_174, "panel").options; var _175 = $.data(_174, "panel").panel; if (opts.tools && typeof opts.tools == "string") { _175.find(">div.panel-header>div.panel-tool .panel-tool-a").appendTo(opts.tools); } _165(_175.children("div.panel-header")); if (opts.title && !opts.noheader) { var _176 = $("<div class=\"panel-header\"><div class=\"panel-title\">" + opts.title + "</div></div>").prependTo(_175); if (opts.iconCls) { _176.find(".panel-title").addClass("panel-with-icon"); $("<div class=\"panel-icon\"></div>").addClass(opts.iconCls).appendTo(_176); } var tool = $("<div class=\"panel-tool\"></div>").appendTo(_176); if (opts.tools) { if (typeof opts.tools == "string") {//如果是字符串,也就是我说的第二种方式 $(opts.tools).children().each(function(i){ /** * 这个地方是不能重用的根本原因,因为jQuery的appendTo方法破坏性操作,即源DOM被移动到目标位置,而不是拷贝到目标位置。 * 所以作为源的tools只要被一个panel使用就等于被empty()了,当然也就无法被多个panel同时使用了, * 知道原因就知道改怎么改进了,应该使用clone的方式拷贝,直接使用jQuery的clone()方法拷贝即可. * 克隆拷贝之后还要注意到,地4-6行代码,如果当前panel中已经存在一些tool,则会把这些tool移动到源tools中,然后清空panel内部tool。 * 使用克隆拷贝后,4-6行的代码就不再需要了,4-6行代码是为了备份已有tool,而现在不需要备份了,再备份的话会造成重复的源tools */ $(this).addClass($(this).attr("iconCls")).addClass("panel-tool-a").appendTo(tool); }); } else { for (var i = 0; i < opts.tools.length; i++) { var t = $("<a href=\"javascript:void(0)\"></a>").addClass(opts.tools[i].iconCls).appendTo(tool); if (opts.tools[i].handler) { t.bind("click", eval(opts.tools[i].handler)); } } } } if (opts.collapsible) { $("<a class=\"panel-tool-collapse\" href=\"javascript:void(0)\"></a>").appendTo(tool).bind("click", function(){ if (opts.collapsed == true) { _18e(_174, true); } else { _183(_174, true); } return false; }); } if (opts.minimizable) { $("<a class=\"panel-tool-min\" href=\"javascript:void(0)\"></a>").appendTo(tool).bind("click", function(){ _194(_174); return false; }); } if (opts.maximizable) { $("<a class=\"panel-tool-max\" href=\"javascript:void(0)\"></a>").appendTo(tool).bind("click", function(){ if (opts.maximized == true) { _197(_174); } else { _182(_174); } return false; }); } if (opts.closable) { $("<a class=\"panel-tool-close\" href=\"javascript:void(0)\"></a>").appendTo(tool).bind("click", function(){ _177(_174); return false; }); } _175.children("div.panel-body").removeClass("panel-body-noheader"); } else { _175.children("div.panel-body").addClass("panel-body-noheader"); } };
代码修正:
要分析的内容均已经写在代码的注释里面了,所以最后的该法只要进行以下改动即可:
- 要将4-6行代码注释掉
- 将each循环内部appendTo之前先clone元素
clone的写法如下:
if (typeof opts.tools == "string") { $(opts.tools).children().each(function(i){ $(this).addClass($(this).attr("iconCls")).addClass("panel-tool-a").clone().appendTo(tool); }); }