概要分析
粗略地分析panel的源码我们知道,panel的href方式获取数据使用的是jQuery的ajax方法,ajax获取返回纯文本,该文本作为变量传给success回调,也就是说,在success内部交由panel组件进一步处理,我们来看看代码片段:
- $.ajax({
- url: _18e.options.href,
- cache: false,
- success: function(data){
- _190.html(_18e.options.extractor.call(_18d, data));
- if ($.parser) {
- $.parser.parse(_190);
- }
- _18e.options.onLoad.apply(_18d, arguments);
- _18e.isLoaded = true;
- }
- });
通过上面代码可以看出:获取远程数据data作为参数送给success回调,在success内部,我们看到panel使用自身的extractor函数对data文本进一步过滤,这个过滤过程不重要,我们可以忽略。过滤后的数据直接使用jQuery的html()追加到当前DOM,然后easyui使用paser对追加的html片段进行渲染。
分析到这个地方,我想关键点我们就都已经找到了,明确以下两点最重要:
data内部包含的javascript片段的执行顺序取决于jQuery的html函数的处理机制
data内部包含的javascript片段一定先于easyui的parser执行
html函数机制:
第一步.将DOM中的script标签剥离出来,从而形成两部分内容,一部分是不包含script标签的文本,假设为A;另一部分是若干个script片段,假设为B。
第二步.清空当前标签,用A追加到当前标签。
第三步.追加B到当前页面,而且对于B,有两种情况:
- script标签使用src方式连接到其它js文件的情况:jQuery使用ajax函数获取src里面的javascript代码,并且ajax设置为同步,从而能保证按照引入顺序执行;
- 直接写在script标签里面的javascript代码:jQuery使用window.execScript或者window[ "eval" ]执行javascript代码.
结论归纳:
分析到这里基本就清晰了,所以,最后href目标页面中的javascript脚本的注意事项有以下几点:
script标签必须放在body内
script标签一定要放在body标签内部,放在body标签外面的所有script标签都会被忽略,或者直接省略掉html,head,body这几个标签页可以。
script的位置无关性
script标签包含的脚本不管是放在DOM最前面,还是中间,还是后面,从执行效果上讲,都好比按顺序地放在了DOM的最后面。因为是先追加不带script标签的DOM,后处理分离出来的script。这也是放在某个DIV前面的脚本可以通过这个DIV的ID属性访问到该DIV的原因,这一点跟正常页面的加载顺序是有区别的。
失去作用的document.ready
比如目标页面的内容如下:
- <script type="text/javascript">
- $(function(){
- alert("这里先执行");
- });
- alert("这里后执行");
- </script>
要是在普通页面内,document.ready里面的脚本肯定是在后面执行的,当其作为panel的href目标页面的时候ready是没有任何效果的,因为这时候页面早就加载完成的,ajax当然不在ready检测的范围内。
不要操作不存在的组件实例
目标页面里面的javascript代码不应该存在直接利用easyui组件实例对象的操作,比如$("#panelId").panel('setTitle','shit'),除非你在次之前调用了$("#panelId").panel({...});来生成panel组件的对象实例。
后知后觉的easyui parser
如果data里面包含easyui支持的组件class,那么在$.parser.parse(_190)代码执行完后将会完成对组件的解析,所以最安全的方式是在onLoad回调中操作easyui组件的实力对象。
不要重复构造easyui组件
还需要注意的是,不要重复构造easyui组件了,如果在data内部通过脚本构造了某easyui组件,然后$.parser.parse检索到该组件样式,又构造一次,这纯粹是浪费,而且可能造成两次加载。
还有哪些组件类似?
layout,according等扩展自panel的上层组件使用href的时候,脚本执行顺序的规则是跟panel组件一致的。
晕死… 我就用Chrome看了半天源文件,发现herf回来的页面只有body里面的东西,里面的按钮调用的JS全都是显示未定义。估计就是过滤掉了,看了你的文章后,果然如此…
管理员 世纪之光 : 2012年12月20日16:57:42 地下1层
奔泪吆,终于来了一个有头像的到我这里留言了……
哈哈,好悲催啊。我还在研究中… 尝试了好几种方式,直接ajax把内容取回来然后放到dialog的content中去,好像还是有点问题,script就是无论如何都要被干掉一样… 疯了…
管理员 世纪之光 : 2012年12月20日17:14:42 地下3层
把ajax的目标请求页面的所有javascript都放在body内部就可以了呀,easyui的规则一直是这样的。
这个我知道的… 可是不想这样啊… 这要一来格局变动太大了…
管理员 世纪之光 : 2012年12月20日17:44:35 地下5层
那你可以试着研究一下panel组件的extractor属性,它起到过滤掉的作用。
那个属性之前我试过了,给了个参数data,但是没有执行,不知道为什么。
//
href:xxxx,
extractor:function(data){
//xxxx
}
试了没反应…
管理员 世纪之光 : 2012年12月20日19:24:46 -48楼
@下午茶 没反应是什么意思啊,执行不进去?我试了是可以的啊 直接
extractor:function(data){
alert(1);//可以打印出来
}
如果要包含整个html的话,你的正则估计就复杂了,一个页面中不能包含两个head和title元素吧?
是没反应,我用浏览器Debug了,从头到尾根本没有进来,没有执行过这个方法。
你用的是哪个版本的jQuery和EasyUI? 我用的是jq1.7.2,easyui1.3。
$(‘#show-task-dialog’).show().dialog({
href : url,//这个是生成好的一个地址变量
title:title,
maximized : true,
closable : true,
modal : true,
cache:false,
draggable:false,
loadingMessage : ‘数据加载中…’,
extractor:function(data){
//此处照抄过来测试的
console.log(‘data’,data);
var pattern = /]*>((.|[\n\r])*)/im;
var matches = pattern.exec(data);
console.log(‘matches’,matches);
if (matches){
return matches[1]; // only extract body content
} else {
return data;
}
}
});
代码用的没问题吧? 方便的话帖帖你的。
管理员 世纪之光 : 2012年12月21日15:56:18 地下2层
我之前定义panel组件的extractor是有效的。而定义dialog的extractor,我试了下,确实无效,看了下dialog的代码,初始化组建的时候并没有使用自身定义的extractor覆盖panel组件定义的extractor。所以你想改的话,就这样改 $.fn.panel.defaults.extractor = function(data){alert(data);}。
哈哈,多谢多谢。之前没有看到你的回复,我用了iframe方式实现了功能。不过你说的也不错,我得培养看源码的习惯了~ 😀
今天看到这篇文章,但是对于“$(function(){})无法正常使用”,有一点疑问,因为目前试验的过程发现都有效啊……包括说明中的实例
$(function(){
alert(“这里先执行”);
});
alert(“这里后执行”);
管理员 世纪之光 : 2013年12月16日18:49:16 地下1层
“失去作用”并非是“无法使用”的意思。
$(function(){
alert(“1”);
});
alert(“2”);
以上代码,在普通页面内的正常情况,应该是先弹出”2″再弹出”1″,但是如果是panel的href的话,则是先弹出”1″后弹出”2″。我想表述的是这个意思。
了解……多谢了哈。看了这篇文章受益匪浅
多谢 终于知道为啥加载不上了
非常清晰的解释,几乎明白了easyui加载href的原理,能否讲解下css文件是如何加载的