`

IE6下使用JS获取路径中包含汉字的URL的一个问题(转载)

    博客分类:
  • js
阅读更多

 

IE6下使用JS获取路径中包含汉字的URL的一个问题

  我们经常需要用 JavaScript 获取网页上某个链接的地址(href 属性),很简单,只需要 a.getAttribute("href") 就行了。一切都很顺利,除了万恶的 IE6。

  有时候,我们的链接中含有汉字,为了保证链接不会因为编码问题失效,我们先要将汉字转换为 URL 编码的形式。比如,UTF-8 编码的“汉字”将被转为“%E6%B1%89%E5%AD%97”,GBK 编码的“汉字”则是“%BA%BA%D7%D6”。这样,一个形如“http://test.com/news/cartoonlist/d14-td12月义乌最有商机的小商品-p1.html”的链接(其中的汉字为 GBK 编码)将被转为“http://test.com/news/cartoonlist/d14-td12%D4%C2%D2%E5%CE%DA%D7%EE%D3%D0%C9%CC%BB%FA%B5%C4%D0%A1%C9%CC%C6%B7-p1.html”。转换之后,在各大浏览器上访问都很正常,用 js 获取链接的 href 值也很正常,除了在 IE6 下。

  我们来看一下下面的代码:

1 <!-- 请在 IE6 下测试本段代码 -->
3
4 <script type="text/javascript">
5 function test(a) {
6     alert(a.getAttribute("href"));
7 }
8 </script>

  点击链接,在除 IE6 的各大浏览器下表现都和预期的一致,如下图:

  正常表现

  但在 IE6 下,取得的 href 属性中汉字编码的部分变成了乱码:

  IE6 下的怪异表现

  在 IE6 下,如果要对通过 js 获取 href 属性,只要 href 值的 URL 路径中含有汉字等字符(无论这些字符是用 GBK 编码的还是 UTF-8 编码的)的 URL 编码,都将遇到这样的问题。网上搜索了一番,得知大概是由于 IE6 对编码支持的不完善造成的。另外,这个问题只在 URL 编码出现在 URL 路径而不是参数(即 ? 后面的内容)或书签(即 # 后面的内容)中才会发生。比如,下面的代码中,也有 URL 汉字编码,但这些汉字编码都在参数中,所以不会有这个问题。

1 <!-- 请在 IE6 下测试本段代码 -->
3
4 <script type="text/javascript">
5 function test(a) {
6     alert(a.getAttribute("href"));
7 }
8 </script>

  鉴于 IE6 在国内还有巨大的份额,我们必须要设法解决或避免这个问题。避免这个问题的方法很简单,只要规定 URL 路径中不要出现这样的汉字编码即可(URL 参数中可以出现)。但如果 URL 路径中已经大量应用汉字编码了,有办法处理吗?网上搜索了一圈无果,看来只能自己处理了。

  经过测试,注意到只有用 js 获取 href 属性的值时会有这个问题,取别的属性(即使是一个自定义属性的值)都正常。比如:

1 <!-- 请在 IE6 下测试本段代码 -->
3
4 <script type="text/javascript">
5 function test(a) {
6     alert(a.getAttribute("href") + "\n" + a.getAttribute("my-attr"));
7 }
8 </script>

  可以看到,js 获取的 href 属性中有乱码,但自定义属性的值是正常的。

  这就有了第一个解决办法:服务器端生成 HTML 时,给每个超链接再加一个自定义属性,值和 href 的值一样。客户端 js 要处理 href 时,读取这个自定义属性就行了。

  但这个方法显然很不靠谱,因为工程太浩大了,而且这个自定义属性对于除 IE6 以外的浏览器来说都是毫无用途的。

  继续探索,突然想到,这个链接元素的 outerHTML 属性中的 URL 是否正常呢?试了一下,发现 outerHTML 属性是正常的,没有乱码。于是,就有了下面的更好的解决办法:

  解决方案一:

01 <!-- 请在 IE6 下测试本段代码 -->
03
04 <script type="text/javascript">
05 function test(a) {
06     alert(a.getAttribute("href")); // IE 6 下有乱码
07
08     var href;
09     if (a.outerHTML &&
10             (href = a.outerHTML.match(/<a [^>]*?href=['"]?(.*?)['"\s]/i)) &&
11             (href = href[1]) != a.getAttribute("href")
12         ) a.setAttribute("href", href);
13
14     alert(a.getAttribute("href")); // IE 6 下正常
15 }
16 </script>

  原理很简单,读取链接 a 的 outerHTML,用正则从中找到 href 的值,这个值就是我们期望的没有乱码的值。注意,上面的代码中我们又把提取到的 href 的值写回了 href 属性,这么做的原因是用 js 写 href 属性后,再次用 js 读取时就是刚才写入的值(即刚才提取的没有乱码的值)。

  这种方法很简单直观,不过有一个缺点是要读取 outerHTML 的值。另外,@yuyu1911 也总结了另外一种解决办法,我将他的代码稍作整理后,把上面的 test 函数写成如下形式:

  解决方案二:

01 function test(a) {
02     //alert(a.getAttribute("href")); // IE 6 下有乱码
03
04     var href = a.getAttribute("href");
05
06     if (isIE6()) {
07         // IE 6 下,汉字自动转义后变乱码了,采用 escape 方法对其进行编码能恢复其编码,
08         // 但同时也将 ?:&=# 等字符也进行了编码,所以对这些字符还得进行解码
09         var i = href.search(/[\?#]/);
10         if (i == -1) i = href.length;
11         href = escape(href.substr(0, i)).replace( // 将 ?:&=# 字符进行解码
12                 /(%3F|%3A|%26|%3D|%23)/g,
13                 function($0, $1) {
14                     return unescape($1);
15                 }
16             ) + href.substr(i);
17     }
18     alert(href);
19 }
20
21 // 判断是否为 IE6
22 function isIE6() {
23     // ...
24     return true;
25 }

  这个方法的特点是不需要额外地读取 outerHTML 属性的值,同时需要处理的正则也简单一些,我简单测试了一下,它在 IE6 下性能比上面要读取 outerHTML 的方法稍高一些。这个方法的不足是需要判断浏览器是否为 IE6,因为在其它浏览器下,上面的处理过程会将正常的 URL 编码再编码一次。另外,上面的 isIE6 函数我故意留空了,因为判断浏览器版本的方法通常在大家常用的框架或库中已经有了,这儿我就不再重复实现了。

  这样,在各大主流浏览器中,我们都能顺利地用 js 取得链接的 href 值了,即使 URL 路径中有经过 URL 编码的汉字。

  --------------------------------------------------

  上面的内容写好后,经 @wljray 提醒,注意到在 IE 下,node.getAttribute 有一点不同,它可以有两个参数,具体见这儿。具体到这个问题,通过 getAttribute 取链接的 href 属性时,可以传两个参数,如下:

1 a.getAttribute("href", iFlags);

  其中 iFlags 的值可以为 0、1、2、4。测试如下:

01 <!-- 请在 IE6 下测试本段代码 -->
02 <a href="/news/d14-td12%D4%C2%D2%E5%CE%DA%D7%EE%D3%D0%C9%CC-p1.html"onmousedown="test(this)" target="_self">链接1</a>
03
04 <script type="text/javascript">
05 function test(a) {
06     var v = [0, 1, 2, 4], i, s = "", iFlags;
07     for (i = 0; i < v.length; i ++) {
08         iFlags v[i];
09         s += "iFlags " + iFlags + "\nhref  = '"
10             + a.getAttribute("href", iFlags) + "'\n\n";
11     }
12     alert(s);
13 }
14 </script>

  注意上面的代码中,我们的 href 写的是相对路径。测试结果如下,一图胜千言:

  IE getAttribute 第二个参数测试

  可以看到,iFlags 为 0 或 1 时,就是默认情况,有乱码,返回的是绝对路径;iFlags 为 2 时,没有乱码,返回相对路径;iFlags 为 4 时,没有乱码,返回绝对路径。

  另外,getAttribute 的第二个参数在其它浏览器中都会被安全地忽略掉,所以,综合起来,本文开头提出来的问题的最佳解决方案如下。

  最终解决方案:

1 function test(a) {
2     return a.getAttribute("href", 2); // 搞定
3 }

  这样,getAttribute 在各大浏览器(包括 IE6)中就都有一致的表现了。绕了一大圈,尝试了各种方法,没想到最后最佳的解决方案居然是浏览器本来就支持的。但 IE 这个属性太不常用了,我今天还是第一次知道,再次感谢告诉我这个属性的 @wljray。:-)

分享到:
评论

相关推荐

    大名鼎鼎SWFUpload- Flash+JS 上传

     在SWFUpload的使用过程中,无论在客户端还是服务器端都要和File Object打交道,在一个File Object中包含了以下内容:  {  id : string, // SWFUpload file id, used for starting or cancelling and upload  ...

    asp.net知识库

    帮助解决网页和JS文件中的中文编码问题的小工具 慎用const关键字 装箱,拆箱以及反射 动态调用对象的属性和方法——性能和灵活性兼备的方法 消除由try/catch语句带来的warning 微软的应试题完整版(附答案) 一个...

    KODExplorer 芒果云-资源管理器

    [如何使用] 下载程序,解压上传到你的服务器路径下,data目录设置777权限。访问体验超便捷的服务吧! (data目录没有写权限会导致配置修改不能保存、不能新建用户等) [关于上传问题] 程序没有做任何限制,如果需要...

    商用版本文本编辑器DotNetTextBoxV6.0.8Source 源码

    2)修正在带有中文目录的网站路径下使用控件会出现找不到路径的BUG! 3)修正控件上传目录初始设置不支持中文目录的BUG! 4)修正当三级或以上级别目录调用控件时图片相对路径转换不正确的BUG! 5)增加提取编辑器内容中...

    DotNetTextBox V6.0.10 商业版 下载 (已知最新)

    2)修正在带有中文目录的网站路径下使用控件会出现找不到路径的BUG! 3)修正控件上传目录初始设置不支持中文目录的BUG! 4)修正当三级或以上级别目录调用控件时图片相对路径转换不正确的BUG! 5)增加提取编辑器内容中...

    Discuz! X1.5.1 简体GBK R20111221.zip

    Discuz X1.5是康盛创想Comsenz推出的一个以社区为基础的专业建站平台,让论坛BBS、个人空间SNS、门户Portal、群组Group、应用开放平台Open Platform充分融合于一体,帮助网站实现一站式服务。  Discuz! X1.5.1 ...

    IBM WebSphere Portal门户开发笔记01

    1)在定制主题和外表中使用拖放 85 2)拖放标记摘要 85 3)拖放 API 86 八、功能应用或问题 87 1、WCM多子站区指向指定子站区配置 87 2、更改PORTAL默认的登录选项 89 3、如何在主题与皮肤中获取PORTAL登录用户信息 ...

    精易模块[源码] V5.15

    9、改善“网页_访问”中最后一个参数(代理地址)为“”符号时无法访问网页,感谢易友【z00544】反馈。 精易模块 V3.82 what’s new:(20140816) 1、修复“时间_取现行时间戳”有时不能正常返回13位时间戳,当...

    vc++ 应用源码包_6

    演示了OpenG的使用方法,内含几个实例,一个实例就3个文件。 p2p vb实例。 p2p+technology文档。 P2P视频技术源码(含开发文档) PcShare 内含远程控制、进程管理、文件操作、视频控制、注册表操作、客户端...

    vc++ 应用源码包_1

    演示了OpenG的使用方法,内含几个实例,一个实例就3个文件。 p2p vb实例。 p2p+technology文档。 P2P视频技术源码(含开发文档) PcShare 内含远程控制、进程管理、文件操作、视频控制、注册表操作、客户端...

    vc++ 应用源码包_2

    演示了OpenG的使用方法,内含几个实例,一个实例就3个文件。 p2p vb实例。 p2p+technology文档。 P2P视频技术源码(含开发文档) PcShare 内含远程控制、进程管理、文件操作、视频控制、注册表操作、客户端...

    vc++ 应用源码包_5

    演示了OpenG的使用方法,内含几个实例,一个实例就3个文件。 p2p vb实例。 p2p+technology文档。 P2P视频技术源码(含开发文档) PcShare 内含远程控制、进程管理、文件操作、视频控制、注册表操作、客户端...

    vc++ 应用源码包_3

    演示了OpenG的使用方法,内含几个实例,一个实例就3个文件。 p2p vb实例。 p2p+technology文档。 P2P视频技术源码(含开发文档) PcShare 内含远程控制、进程管理、文件操作、视频控制、注册表操作、客户端...

    网管教程 从入门到精通软件篇.txt

    IV:Open Inventor中使用的文件格式 IVD:超过20/20微观数据维数或变量等级文件 IVP:超过20/20的用户子集配置文件 IVT:超过20/20表或集合数据文件 IVX:超过20/20微数据目录文件 IW:Idlewild屏幕保护程序 ...

    精易官方免费模块v3.60版

    2.删除“程序_禁止重复运行_浏览器”,一个不知道何时添加的未公开子程序(可能代码也有问题) 1.完善“程序_加入右键菜单”,增加可空参数 &lt;显示名称&gt;感谢 阿蒙 的提醒 2.完善“线程_取自线程句柄”,采用百度百科的...

    vc++ 开发实例源码包

    演示了OpenG的使用方法,内含几个实例,一个实例就3个文件。 p2p vb实例。 p2p+technology 文档。 P2P视频技术源码(含开发文档) 目前的协议有如下一些特点: 1) 客户向服务器发送请求, 每个请求的长度不定. 请求...

    精易编程助手3.3+精易模块v6.3.1

    2、新增“文本_取出文本中汉字”,取出指定文本中的汉字; 3、新增“网页_JS格式化EX”原有的JS格式化命令的升级版; 4、新增“网页_Cookie合并更新ex”基于原有命令升级;感谢【@小小n 】反馈并提供源码 5、新增...

Global site tag (gtag.js) - Google Analytics