Posts in category javascript

历史 - 无意中访问到 jQuery 的 trac

看起来 jQuery 历史上使用过 trac 来进行开发管理,具体地址访问这儿: https://bugs.jquery.com/ , 我是通过 stackoverflow这个问题 不小心进入的.

看起来,这个 trac 两年前就不再使用了.



动态写入内容到 iFrame 并执行其中脚本

How to - Injecting HTML into an IFrame

其实实现思路比较简单,与动态打开一个窗口并使用 document.write(...) 写入内容的做法类似,IFrame 内部包含的 window 对象也可以使用同样的方法写入 HTML 内容,并且可以执行其中的脚本。

主要参考

  • stackoverflow "Creating an iframe with given HTML dynamically"

  • Dojo 的 Reference Guide 采用类似做法来运行示例代码
    • 经过分析可以看到 Dojo Reference Guide 是采用一个 src=javascript:[页面内容] 的方式来打开 iframe,例如:
      javascript:%20'<!DOCTYPE%20html>\n<html%20>\n<head>\n\n<link%20rel="stylesheet"%20href="../_static/js/dojo/../dijit/themes/claro/claro.css">\n\n<script>dojoConfig%20=%20{async:%20true}</script><script%20src=\'../_static/js/dojo/dojo.js\'></script><script>require([\n%20%20%20%20"dojo/ready",%20"dojo/_base/window",%20"dojo/store/Memory",\n%20%20%20%20"dijit/tree/ObjectStoreModel",%20"dijit/Tree"\n],%20function(ready,%20win,%20Memory,%20ObjectStoreModel,%20Tree){\n\n%20%20%20%20//%20Create%20test%20store,%20adding%20the%20getChildren()%20method%20required%20by%20ObjectStoreModel\n%20%20%20%20var%20myStore%20=%20new%20Memory({\n%20%20%20%20%20%20%20%20data:%20[\n%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'world\',%20name:\'The%20earth\',%20type:\'planet\',%20population:%20\'6%20billion\'},\n%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'AF\',%20name:\'Africa\',%20type:\'continent\',%20population:\'900%20million\',%20area:%20\'30,221,532%20sq%20km\',\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20timezone:%20\'-1%20UTC%20to%20+4%20UTC\',%20parent:%20\'world\'},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'EG\',%20name:\'Egypt\',%20type:\'country\',%20parent:%20\'AF\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'KE\',%20name:\'Kenya\',%20type:\'country\',%20parent:%20\'AF\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'Nairobi\',%20name:\'Nairobi\',%20type:\'city\',%20parent:%20\'KE\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'Mombasa\',%20name:\'Mombasa\',%20type:\'city\',%20parent:%20\'KE\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'SD\',%20name:\'Sudan\',%20type:\'country\',%20parent:%20\'AF\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'Khartoum\',%20name:\'Khartoum\',%20type:\'city\',%20parent:%20\'SD\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'AS\',%20name:\'Asia\',%20type:\'continent\',%20parent:%20\'world\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'CN\',%20name:\'China\',%20type:\'country\',%20parent:%20\'AS\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'IN\',%20name:\'India\',%20type:\'country\',%20parent:%20\'AS\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'RU\',%20name:\'Russia\',%20type:\'country\',%20parent:%20\'AS\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'MN\',%20name:\'Mongolia\',%20type:\'country\',%20parent:%20\'AS\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'OC\',%20name:\'Oceania\',%20type:\'continent\',%20population:\'21%20million\',%20parent:%20\'world\'},\n%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'EU\',%20name:\'Europe\',%20type:\'continent\',%20parent:%20\'world\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'DE\',%20name:\'Germany\',%20type:\'country\',%20parent:%20\'EU\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'FR\',%20name:\'France\',%20type:\'country\',%20parent:%20\'EU\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'ES\',%20name:\'Spain\',%20type:\'country\',%20parent:%20\'EU\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'IT\',%20name:\'Italy\',%20type:\'country\',%20parent:%20\'EU\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'NA\',%20name:\'North%20America\',%20type:\'continent\',%20parent:%20\'world\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'SA\',%20name:\'South%20America\',%20type:\'continent\',%20parent:%20\'world\'%20}\n%20%20%20%20%20%20%20%20],\n%20%20%20%20%20%20%20%20getChildren:%20function(object){\n%20%20%20%20%20%20%20%20%20%20%20%20return%20this.query({parent:%20object.id});\n%20%20%20%20%20%20%20%20}\n%20%20%20%20});\n\n%20%20%20%20//%20Create%20the%20model\n%20%20%20%20var%20myModel%20=%20new%20ObjectStoreModel({\n%20%20%20%20%20%20%20%20store:%20myStore,\n%20%20%20%20%20%20%20%20query:%20{id:%20\'world\'}\n%20%20%20%20});\n\n%20%20%20%20//%20Create%20the%20Tree.%20%20%20Note%20that%20all%20widget%20creation%20should%20be%20inside%20a%20dojo.ready().\n%20%20%20%20ready(function(){\n%20%20%20%20%20%20%20%20var%20tree%20=%20new%20Tree({\n%20%20%20%20%20%20%20%20%20%20%20%20model:%20myModel\n%20%20%20%20%20%20%20%20});\n%20%20%20%20%20%20%20%20tree.placeAt(win.body());\n%20%20%20%20%20%20%20%20tree.startup();\n%20%20%20%20});\n});</script>\n</head>\n<body%20class="claro">\n%20%20%20%20\n</body>\n</html>'
      

实现实例

参考 fill-iframe-with-string.html, 要点解释如下:

  1. 基本流程就是:
    • IFrame 内部 document.open();
    • IFrame 内部 document.write(...);
    • IFrame 内部 document.close();
  2. 示例中实现了向 IFrame 内部窗口传递参数的功能。注意在 IE 中,document.open() 会清除 IFrame 内部 window 对象上的属性,因此参数的设置需要在 document.open() 之后进行;
  3. 关于脚本的执行:
    • 按照一般的习惯,在页面头部会使用诸如 <script src="./jquery-ui-1.10.3/jquery-1.9.1.js"></script> 这样的写法引入外部 js,然后在 HTML 元素之后使用嵌入的 javascript 脚本执行与页面元素相关的操作;
    • 在 Firefox 和 Chrome 中,<script> 的执行是按照在页面中的先后顺序进行的, 因此处于文档后部的嵌入 javascript 脚本可以使用外部 js 中定义的变量(比如:jQuery 的 "$");
    • 但是在 IE 中情况正好相反,在执行嵌入的 javascript 脚本时,引入的外部 js 还没有执行,这样就造成嵌入 javascript 脚本出现 "找不到 $ 对象" 之类的错误;
    • 解决方法是在 IFrame 内部页面上定义 bodyonload 事件,在这个事件中执行页面中的嵌入 javascript 脚本。

实际效果见 在线演示

讨论:不同浏览器的差异

总的来说 IE9、Firefox 和 Chrome 的差别很小,倒是 IE8 与其他浏览器存在不小的差别,主要包括:

  • 安全模型:上面提到的示例 html 文件无法通过 IE8 直接在本地打开(如下图),但是其他浏览器可以正常打开,而发布到 Web 服务器上之后,IE8 也可以正常打开;

    另外如果 IFrame 中引用的是来自网络的 js 外部文件,IE8 可以正常运行(见这个例子:fill-iframe-with-string-online-test.html);
  • IFrame 相关对象, 以及页面高度检测:下面对不同浏览器中 iframe.documentWindowiframe.contentWindowiframe.Documentiframe.contentDocument.body.offsetHeightiframe.Document.body.scrollHeight进行了比较,可以看出来,IE8 与其他几个浏览器的差异比较明显:
    • IE8, WindowsXP:
    • IE9, Windows 7:
    • Firefox19, Windows 7:
    • Firefox20, Ubuntu:
    • Google Chrome 6, Windows 7:
    • Chromium25, Ubuntu:

END

使用 x3dom 框架及 WebGL 在浏览器上显示 3 维模型

如果需要在浏览器上显示 3D 画面的话, 现在一般会使用 WebGL, 典型的例如 three.js(http://mrdoob.github.com/three.js/), 但是 WebGL 对浏览器版本以及显卡的要求比较高, 很多客户端无法正常使用 ———— 当然现在新买的机器是毫无压力的.

后来在网上查找到了 X3DOM(http://www.x3dom.org/), 通过使用不同的后端(backend), X3DOM 可以兼容较低版本的浏览器(主要是指 IE 系列), 也可以在没有显卡支持的情况下运行, 常用的非 WebGL 后端是 Adobe Flash Player 11, IE 也可以通过使用 Google Chrome Frame 实现对 WebGL 的支持, 注意 Flash 11 以下的版本是不能正常运行的.

X3DOM 通过在标准的 HTML5 DOM 中加入 X3D 格式的 XML 元素, 实现将 X3D 格式的 3D 模型嵌入到 HTML 页面的功能; 在 http://www.x3dom.org/ 网站上有丰富的示例以及较详细的文档, 不过彻底搞懂估计需要一些 3D 建模的知识, 比如 fieldOfView 这样的专业术语.

另外 web3D Consortium 也有大量关于 X3D 的资料, 尤其是 X3D tooltips(http://www.web3d.org/x3d/content/X3dTooltips.html), 是一份全面的 X3D 节点元素速查手册(有中文版)(不知道为什么 www.web3d.org 被 GWF 了, 如果要下载也可以到 这里);

在初步了解 x3dom 的基础上, 以显示货物装箱为例, 对 x3dom 进行了简单的封装, 重点关注 货物在集装箱等容器中的堆放方式的显示, 可以实现以 "Box" 的方式加入不同尺寸的货物(长方体), 以不同的角度查看堆放情况, 以及对这些长方体的选择/加亮显示等等, 具体代码可以到 https://github.com/thinkbase/dev-thinkbase.net/tree/master/.research/x3dom-container-fill 下载, 注意测试用的 html 文件不能直接在本地打开, 必须部署到 HTTP 服务器上才能正常运行; 如果不想麻烦的话,在这里可以看到 在线演示.

实际显示的效果如下图所示(使用 Flash backend 的效果, 如果系统支持 WebGL 的话效果应该要好很多):