由莫名其妙的错误开始---浅谈jquery的dom节点创建
2013-03-21 20:43
405 查看
本来没准备今天发博客的,在一个前端群中,一位老大哥风自由提出了一个简单却很奇特的问题:
有一个字符串是这样的:var s = '<html lang="en" class="js no-touch discourse-no-touch">'+ '<head><meta name="csrf-token" content="Oul7WqVh4FBVse2yGeY8ZkqoN5/9/2ImxohJvUYEJYc="/></head><body></body></html>';
怎么通过jquery得到其中content的值?
本来觉得这个问题蛮简单的,既可以通过正则获取,也可以通过jquery的$将这个字符串变成一个jq对象来获取。但是也正是后来这个方法,却带来了问题。
以我的理解,定位content的方法应该为$(s).find("meta").attr("content"),但是这么去获取结果确并不正确。
于是做了简单的尝试:
得到的并不是所详细的结果,而是meta标签。
这就有点奇怪了,风大猜测是因为外面有<html></html>,可能jquery不能把<html>标签变为dom。而在字符串外层套一层div则确实能够正确的获取结果。
但是,这个结果真的正确么?
又做了一个简单的尝试:
结果并不是我们所想象的那样,而是仍旧去除了html标签,只不过因为套用了一层div,使$(s).find("meta").attr("content")去正确找寻了节点,并不是保护了html标签。
这个问题的原因,相信只有jq的源码能够给我答案了。写了几行简单的测试代码,去通过断点解读一下jq的处理机制:
事实证明,除了第一种方式不能正确的获得结果以外,后两种都能正确的获取结果。通过研读jq的源码中对jq对象创建的代码,终于弄清楚了这个原因。
jq对传入的字符串会进行一次正则:
解释一下这个正则吧:
^<(\w+)\s*\/?
以<开头,至少跟着一个字符和任意个空白字符,之后出现0或1次/
>
这个就不说了,前面这些加起来就是<div >这样或者<meta />这样的
(?:<\/\1>|)$
可以匹配<、一个/或者空白并以之为结尾
这些就是</div>或者跟着<br />这种自闭合标签后面的空
这样如果没有任何属性和子节点的字符串(比如'<html></html>'或者'<div></div>'这样)会通过正则的匹配,当通过正则的匹配后则会通过传入的上下文直接创建一个节点:
而未通过节点的字符串,则通过创建一个div节点,将字符串置入div的innerHTML:
而浏览器是不允许div内直接包含<html>的,因此会将html标签过滤。
当过滤了html之后,刚才的字符串变成了:
jq会从两端向中间去寻找节点的头尾,在这里闭合标签则被寻找为meta标签。
这就是这次所得到的所有结论,总结一下:
如果你的标签是没有子节点和属性的标签,jq会通过正则判定后在你传入的上下文环境直接创建这个节点。
如果你的标签带有子节点或者属性,jq的正则不过,然后会创建一个div,把你的字符串作为div的innerHTML传入,再对div内部的dom节点遍历属性和节点,去获取class啊id啊之类的,然后再创建这个真正的节点。
但是浏览器不允许任何非frame类元素内部有html标签,会将之过滤。
在过滤了html标签后,head标签和body标签就成了两个标签,而jq是从外向内寻找包裹的标签对的,所以这两个标签没有被识别,而meta标签因为是自闭合标签,而且也是从外往内被包裹的最外层闭合标签,因此就成了获取这个标签。
大概就是这样了。
感谢阅读~同时感谢风大~
有一个字符串是这样的:var s = '<html lang="en" class="js no-touch discourse-no-touch">'+ '<head><meta name="csrf-token" content="Oul7WqVh4FBVse2yGeY8ZkqoN5/9/2ImxohJvUYEJYc="/></head><body></body></html>';
怎么通过jquery得到其中content的值?
本来觉得这个问题蛮简单的,既可以通过正则获取,也可以通过jquery的$将这个字符串变成一个jq对象来获取。但是也正是后来这个方法,却带来了问题。
以我的理解,定位content的方法应该为$(s).find("meta").attr("content"),但是这么去获取结果确并不正确。
于是做了简单的尝试:
var s = '<html lang="en" class="js no-touch discourse-no-touch">'+ '<head><meta name="csrf-token" content="Oul7WqVh4FBVse2yGeY8ZkqoN5/9/2ImxohJvUYEJYc="/></head><body></body></html>'; $(s);//[<meta name="csrf-token" content="Oul7WqVh4FBVse2yGeY8ZkqoN5/9/2ImxohJvUYEJYc=">]
得到的并不是所详细的结果,而是meta标签。
这就有点奇怪了,风大猜测是因为外面有<html></html>,可能jquery不能把<html>标签变为dom。而在字符串外层套一层div则确实能够正确的获取结果。
但是,这个结果真的正确么?
又做了一个简单的尝试:
var s = '<div><html lang="en" class="js no-touch discourse-no-touch">'+ '<head><meta name="csrf-token" content="Oul7WqVh4FBVse2yGeY8ZkqoN5/9/2ImxohJvUYEJYc="/></head><body></body></html></div>'; $(s);//[<div><meta name="csrf-token" content="Oul7WqVh4FBVse2yGeY8ZkqoN5/9/2ImxohJvUYEJYc="></div>]
结果并不是我们所想象的那样,而是仍旧去除了html标签,只不过因为套用了一层div,使$(s).find("meta").attr("content")去正确找寻了节点,并不是保护了html标签。
这个问题的原因,相信只有jq的源码能够给我答案了。写了几行简单的测试代码,去通过断点解读一下jq的处理机制:
(function() { debugger; $('<html class="123"></html>'); $('<div></div>'); $('<html></html>'); })();
事实证明,除了第一种方式不能正确的获得结果以外,后两种都能正确的获取结果。通过研读jq的源码中对jq对象创建的代码,终于弄清楚了这个原因。
jq对传入的字符串会进行一次正则:
var parsed = rsingleTag.exec( data );//rsingleTag=/^<(\w+)\s*\/?>(?:<\/\1>|)$/
解释一下这个正则吧:
^<(\w+)\s*\/?
以<开头,至少跟着一个字符和任意个空白字符,之后出现0或1次/
>
这个就不说了,前面这些加起来就是<div >这样或者<meta />这样的
(?:<\/\1>|)$
可以匹配<、一个/或者空白并以之为结尾
这些就是</div>或者跟着<br />这种自闭合标签后面的空
这样如果没有任何属性和子节点的字符串(比如'<html></html>'或者'<div></div>'这样)会通过正则的匹配,当通过正则的匹配后则会通过传入的上下文直接创建一个节点:
if ( parsed ) { return [ context.createElement( parsed[1] ) ]; }//context为上下文
而未通过节点的字符串,则通过创建一个div节点,将字符串置入div的innerHTML:
tmp = tmp || safe.appendChild( context.createElement("div") );//创建divdom节点 tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];//将字符串置入div对象的innerHTML
而浏览器是不允许div内直接包含<html>的,因此会将html标签过滤。
当过滤了html之后,刚才的字符串变成了:
<head><meta name="csrf-token" content="Oul7WqVh4FBVse2yGeY8ZkqoN5/9/2ImxohJvUYEJYc="/></head><body></body>
jq会从两端向中间去寻找节点的头尾,在这里闭合标签则被寻找为meta标签。
这就是这次所得到的所有结论,总结一下:
如果你的标签是没有子节点和属性的标签,jq会通过正则判定后在你传入的上下文环境直接创建这个节点。
如果你的标签带有子节点或者属性,jq的正则不过,然后会创建一个div,把你的字符串作为div的innerHTML传入,再对div内部的dom节点遍历属性和节点,去获取class啊id啊之类的,然后再创建这个真正的节点。
但是浏览器不允许任何非frame类元素内部有html标签,会将之过滤。
在过滤了html标签后,head标签和body标签就成了两个标签,而jq是从外向内寻找包裹的标签对的,所以这两个标签没有被识别,而meta标签因为是自闭合标签,而且也是从外往内被包裹的最外层闭合标签,因此就成了获取这个标签。
大概就是这样了。
感谢阅读~同时感谢风大~
相关文章推荐
- jquery动态创建dom节点
- jQueryDom操作之创建节点
- JqueryDOM操作-创建节点
- Jquery中的DOM操作 (一.查找和创建节点)
- JQuery DOM 创建节点
- Jquery6_控制Dom元素_动态创建节点及删除节点
- JavaScript及jQuery选择器 + DOM创建节点
- jQuery之dom操作(查询、创建、插入、删除、复制节点)
- jQuery – 7.动态创建Dom、删除节点
- jQuery-DOM节点的创建
- jQuery中的DOM节点的创建与多种插入方式
- jQuery操作DOM基础 - 创建节点
- JQuery创建DOM节点的方法
- JavaScript之jQuery-3 jQuery操作DOM(查询、样式操作、遍历节点、创建插入删除、替换、复制)
- jQuery及javascript DOM创建节点(三)
- JQuery创建DOM节点的方法
- js和jquery对dom节点的操作(创建/追加)
- jQuery的DOM操作实例(3)——创建节点&&编写一个弹窗
- jquery DOM操作_创建节点
- 3.2.2: jQuery的DOM操作之创建节点