深入理解javascript动态插入技术

最近发现各大类库都能利用div.innerHTML=HTML片断来生成节点元素,再把它们插入到目标元素的各个位置上。这东西实际上就是insertAdjacentHTML,但是IE可恶的innerHTML把这优势变成劣势。首先innerHTML会把里面的某些位置的空白去掉,见下面运行框的结果:

代码如下:

<!doctype html>
<html dir="ltr" lang="zh-CN">
    <head>
        <meta charset="utf-8" />
        <title>
            IE的innerHTML By 司徒正美
        </title>
        <script type="text/javascript">
            window.onload = function() {
                var div = document.createElement("div");
                div.innerHTML = "   <td>    <b>司徒</b>正美         </td>        "
                alert("|" + div.innerHTML + "|");
                var c = div.childNodes;
                alert("生成的节点个数  " + c.length);
                for(var i=0,n=c.length;i<n;i++){
                      alert(c[i].nodeType);
                      if(c[i].nodeType === 1){
                          alert(":: "+c[i].childNodes.length);
                      }
                }       
            }
        </script>
    </head>

<body>
        <p id="p">
        </p>
    </body>

</html>

另一个可恶的地方是,在IE中以下元素的innerHTML是只读的:col、 colgroup、frameset、html、 head、style、table、tbody、 tfoot、 thead、title 与 tr。为了收拾它们,Ext特意弄了个insertIntoTable。insertIntoTable就是利用DOM的insertBefore与appendChild来添加,情况基本同jQuery。不过jQuery是完全依赖这两个方法,Ext还使用了insertAdjacentHTML。为了提高效率,所有类库都不约而同地使用了文档碎片。基本流程都是通过div.innerHTML提取出节点,然后转移到文档碎片上,然后用insertBefore与appendChild插入节点。对于火狐,Ext还使用了createContextualFragment解析文本,直接插入其目标位置上。显然,Ext的比jQuery是快许多的。不过jQuery的插入的不单是HTML片断,还有各种节点与jQuery对象。下面重温一下jQuery的工作流程吧。

代码如下:

append: function() {
  //传入arguments对象,true为要对表格进行特殊处理,回调函数
  return this.domManip(arguments, true, function(elem){
    if (this.nodeType == 1)
      this.appendChild( elem );
  });
},
domManip: function( args, table, callback ) {
  if ( this[0] ) {//如果存在元素节点
    var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(),
    //注意这里是传入三个参数
    scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ),
    first = fragment.firstChild;

if ( first )
      for ( var i = 0, l = this.length; i < l; i++ )
        callback.call( root(this[i], first), this.length > 1 || i > 0 ?
      fragment.cloneNode(true) : fragment );

if ( scripts )
      jQuery.each( scripts, evalScript );
  }

return this;

function root( elem, cur ) {
    return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ?
      (elem.getElementsByTagName("tbody")[0] ||
      elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
      elem;
  }
}
//elems为arguments对象,context为document对象,fragment为空的文档碎片
clean: function( elems, context, fragment ) {
  context = context || document;

// !context.createElement fails in IE with an error but returns typeof 'object'
  if ( typeof context.createElement === "undefined" )
  //确保context为文档对象
    context = context.ownerDocument || context[0] && context[0].ownerDocument || document;

// If a single string is passed in and it's a single tag
  // just do a createElement and skip the rest
  //如果文档对象里面只有一个标签,如<div>
  //我们大概可能是在外面这样调用它$(this).append("<div>")
  //这时就直接把它里面的元素名取出来,用document.createElement("div")创建后放进数组返回
  if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
    var match = /^<(\w+)\s*\/?>$/.exec(elems[0]);
    if ( match )
      return [ context.createElement( match[1] ) ];
  }
  //利用一个div的innerHTML创建众节点
  var ret = [], scripts = [], div = context.createElement("div");
  //如果我们是在外面这样添加$(this).append("<td>表格1</td>","<td>表格1</td>","<td>表格1</td>")
  //jQuery.each按它的第四种支分方式(没有参数,有length)遍历aguments对象,callback.call( value, i, value )
  jQuery.each(elems, function(i, elem){//i为索引,elem为arguments对象里的元素
    if ( typeof elem === "number" )
      elem += '';

if ( !elem )
      return;

// Convert html string into DOM nodes
    if ( typeof elem === "string" ) {
      // Fix "XHTML"-style tags in all browsers
      elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
        return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
          all :
          front + "></" + tag + ">";
      });

// Trim whitespace, otherwise indexOf won't work as expected
      var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase();

var wrap =
        // option or optgroup
        !tags.indexOf("<opt") &&
        [ 1, "<select multiple='multiple'>", "</select>" ] ||

!tags.indexOf("<leg") &&
        [ 1, "<fieldset>", "</fieldset>" ] ||

tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
        [ 1, "<table>", "</table>" ] ||

!tags.indexOf("<tr") &&
        [ 2, "<table><tbody>", "</tbody></table>" ] ||

// <thead> matched above
      (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
        [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||

!tags.indexOf("<col") &&
        [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||

// IE can't serialize <link> and <script> tags normally
        !jQuery.support.htmlSerialize &&//用于创建link元素
      [ 1, "div<div>", "</div>" ] ||

[ 0, "", "" ];

// Go to html and back, then peel off extra wrappers
      div.innerHTML = wrap[1] + elem + wrap[2];//比如"<table><tbody><tr>" +<td>表格1</td>+"</tr></tbody></table>"

// Move to the right depth
      while ( wrap[0]-- )
        div = div.lastChild;

//处理IE自动插入tbody,如我们使用$('<thead></thead>')创建HTML片断,它应该返回
      //'<thead></thead>',而IE会返回'<thead></thead><tbody></tbody>'
      if ( !jQuery.support.tbody ) {

// String was a <table>, *may* have spurious <tbody>
        var hasBody = /<tbody/i.test(elem),
        tbody = !tags.indexOf("<table") && !hasBody ?
          div.firstChild && div.firstChild.childNodes :

// String was a bare <thead> or <tfoot>
        wrap[1] == "<table>" && !hasBody ?
          div.childNodes :
          [];

for ( var j = tbody.length - 1; j >= 0 ; --j )
        //如果是自动插入的里面肯定没有内容
          if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )
            tbody[ j ].parentNode.removeChild( tbody[ j ] );

}

// IE completely kills leading whitespace when innerHTML is used
      if ( !jQuery.support.leadingWhitespace && /^\s/.test( elem ) )
        div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
     //把所有节点做成纯数组
      elem = jQuery.makeArray( div.childNodes );
    }

if ( elem.nodeType )
      ret.push( elem );
    else
    //全并两个数组,merge方法会处理IE下object元素下消失了的param元素
      ret = jQuery.merge( ret, elem );

});

if ( fragment ) {
    for ( var i = 0; ret[i]; i++ ) {
      //如果第一层的childNodes就有script元素节点,就用scripts把它们收集起来,供后面用globalEval动态执行
      if ( jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
        scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
      } else {
        //遍历各层节点,收集script元素节点
        if ( ret[i].nodeType === 1 )
          ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
        fragment.appendChild( ret[i] );
      }
    }

return scripts;//由于动态插入是传入三个参数,因此这里就返回了
  }

return ret;
},

真是复杂的让人掉眼泪!不过jQuery的实现并不太高明,它把插入的东西统统用clean转换为节点集合,再把它们放到一个文档碎片中,然后用appendChild与insertBefore插入它们。在除了火狐外,其他浏览器都支持insertAdjactentXXX家族的今日,应该好好利用这些原生API。下面是Ext利用insertAdjactentHTML等方法实现的DomHelper方法,官网给出的数据:

这数据有点老了,而且最新3.03早就解决了在IE table插入内容的诟病(table,tbody,tr等的innerHTML都是只读,insertAdjactentHTML,pasteHTML等方法都无法修改其内容,要用又慢又标准的DOM方法才行,Ext的早期版本就在这里遭遇滑铁卢了)。可以看出,结合insertAdjactentHTML与文档碎片后,IE6插入节点的速度也得到难以置信的提升,直逼火狐。基于它,Ext开发了四个分支方法insertBefore、insertAfter、insertFirst、append,分别对应jQuery的before、after、prepend与append。不过,jQuery还把这几个方法巧妙地调换了调用者与传入参数,衍生出insertBefore、insertAfter、prependTo与appendTo这几个方法。但不管怎么说,jQuery这样一刀切的做法实现令人不敢苛同。下面是在火狐中实现insertAdjactentXXX家族的一个版本:

代码如下:

(function() {
    if ('HTMLElement' in this) {
        if('insertAdjacentHTML' in HTMLElement.prototype) {
            return
        }
    } else {
        return
    }

function insert(w, n) {
        switch(w.toUpperCase()) {
        case 'BEFOREEND' :
            this.appendChild(n)
            break
        case 'BEFOREBEGIN' :
            this.parentNode.insertBefore(n, this)
            break
        case 'AFTERBEGIN' :
            this.insertBefore(n, this.childNodes[0])
            break
        case 'AFTEREND' :
            this.parentNode.insertBefore(n, this.nextSibling)
            break
        }
    }

function insertAdjacentText(w, t) {
        insert.call(this, w, document.createTextNode(t || ''))
    }

function insertAdjacentHTML(w, h) {
        var r = document.createRange()
        r.selectNode(this)
        insert.call(this, w, r.createContextualFragment(h))
    }

function insertAdjacentElement(w, n) {
        insert.call(this, w, n)
        return n
    }

HTMLElement.prototype.insertAdjacentText = insertAdjacentText
    HTMLElement.prototype.insertAdjacentHTML = insertAdjacentHTML
    HTMLElement.prototype.insertAdjacentElement = insertAdjacentElement
})()

我们可以利用它设计出更快更合理的动态插入方法。下面是我的一些实现:

代码如下:

//四个插入方法,对应insertAdjactentHTML的四个插入位置,名字就套用jQuery的
//stuff可以为字符串,各种节点或dom对象(一个类数组对象,便于链式操作!)
//代码比jQuery的实现简洁漂亮吧!
    append:function(stuff){
        return  dom.batch(this,function(el){
            dom.insert(el,stuff,"beforeEnd");
        });
    },
    prepend:function(stuff){
        return  dom.batch(this,function(el){
            dom.insert(el,stuff,"afterBegin");
        });
    },
    before:function(stuff){
        return  dom.batch(this,function(el){
            dom.insert(el,stuff,"beforeBegin");
        });
    },
    after:function(stuff){
        return  dom.batch(this,function(el){
            dom.insert(el,stuff,"afterEnd");
        });
    }

它们里面都是调用了两个静态方法,batch与insert。由于dom对象是类数组对象,我仿效jQuery那样为它实现了几个重要迭代器,forEach、map与filter等。一个dom对象包含复数个DOM元素,我们就可以用forEach遍历它们,执行其中的回调方法。

代码如下:

batch:function(els,callback){
    els.forEach(callback);
    return els;//链式操作
},

insert方法执行jQuery的domManip方法相应的机能(dojo则为place方法),但insert方法每次处理一个元素节点,不像jQuery那样处理一组元素节点。群集处理已经由上面batch方法分离出去了。

代码如下:

insert : function(el,stuff,where){
     //定义两个全局的东西,提供内部方法调用
     var doc = el.ownerDocument || dom.doc,
     fragment = doc.createDocumentFragment();
     if(stuff.version){//如果是dom对象,则把它里面的元素节点移到文档碎片中
         stuff.forEach(function(el){
             fragment.appendChild(el);
         })
         stuff = fragment;
     }
     //供火狐与IE部分元素调用
     dom._insertAdjacentElement = function(el,node,where){
         switch (where){
             case 'beforeBegin':
                 el.parentNode.insertBefore(node,el)
                 break;
             case 'afterBegin':
                 el.insertBefore(node,el.firstChild);
                 break;
             case 'beforeEnd':
                 el.appendChild(node);
                 break;
             case 'afterEnd':
                 if (el.nextSibling) el.parentNode.insertBefore(node,el.nextSibling);
                 else el.parentNode.appendChild(node);
                 break;
         }
     };
      //供火狐调用
     dom._insertAdjacentHTML = function(el,htmlStr,where){
         var range = doc.createRange();
         switch (where) {
             case "beforeBegin"://before
                 range.setStartBefore(el);
                 break;
             case "afterBegin"://after
                 range.selectNodeContents(el);
                 range.collapse(true);
                 break;
             case "beforeEnd"://append
                 range.selectNodeContents(el);
                 range.collapse(false);
                 break;
             case "afterEnd"://prepend
                 range.setStartAfter(el);
                 break;
         }
         var parsedHTML = range.createContextualFragment(htmlStr);
         dom._insertAdjacentElement(el,parsedHTML,where);
     };
     //以下元素的innerHTML在IE中是只读的,调用insertAdjacentElement进行插入就会出错
     // col, colgroup, frameset, html, head, style, title,table, tbody, tfoot, thead, 与tr;
     dom._insertAdjacentIEFix = function(el,htmlStr,where){
         var parsedHTML = dom.parseHTML(htmlStr,fragment);
         dom._insertAdjacentElement(el,parsedHTML,where)
     };
     //如果是节点则复制一份
     stuff = stuff.nodeType ?  stuff.cloneNode(true) : stuff;
     if (el.insertAdjacentHTML) {//ie,chrome,opera,safari都已实现insertAdjactentXXX家族
         try{//适合用于opera,safari,chrome与IE
             el['insertAdjacent'+ (stuff.nodeType ? 'Element':'HTML')](where,stuff);
         }catch(e){
             //IE的某些元素调用insertAdjacentXXX可能出错,因此使用此补丁
             dom._insertAdjacentIEFix(el,stuff,where);
         }     
     }else{
         //火狐专用
         dom['_insertAdjacent'+ (stuff.nodeType ? 'Element':'HTML')](el,stuff,where);
     }
 }

insert方法在实现火狐插入操作中,使用了W3C DOM Range对象的一些罕见方法,具体可到火狐官网查看。下面实现把字符串转换为节点,利用innerHTML这个伟大的方法。Prototype.js称之为_getContentFromAnonymousElement,但有许多问题,dojo称之为_toDom,mootools的Element.Properties.html,jQuery的clean。Ext没有这东西,它只支持传入HTML片断的insertAdjacentHTML方法,不支持传入元素节点的insertAdjacentElement。但有时,我们需要插入文本节点(并不包裹于元素节点之中),这时我们就需要用文档碎片做容器了,insert方法出场了。

代码如下:

parseHTML : function(htmlStr, fragment){
    var div = dom.doc.createElement("div"),
    reSingleTag =  /^<(\w+)\s*\/?>$/;//匹配单个标签,如<li>
    htmlStr += '';
    if(reSingleTag.test(htmlStr)){//如果str为单个标签
        return  [dom.doc.createElement(RegExp.$1)]
    }
    var tagWrap = {
        option: ["select"],
        optgroup: ["select"],
        tbody: ["table"],
        thead: ["table"],
        tfoot: ["table"],
        tr: ["table", "tbody"],
        td: ["table", "tbody", "tr"],
        th: ["table", "thead", "tr"],
        legend: ["fieldset"],
        caption: ["table"],
        colgroup: ["table"],
        col: ["table", "colgroup"],
        li: ["ul"],
        link:["div"]
    };
    for(var param in tagWrap){
        var tw = tagWrap[param];
        switch (param) {
            case "option":tw.pre  = '<select multiple="multiple">'; break;
            case "link": tw.pre  = 'fixbug<div>';  break;
            default : tw.pre  =   "<" + tw.join("><") + ">";
        }
        tw.post = "</" + tw.reverse().join("></") + ">";
    }
    var reMultiTag = /<\s*([\w\:]+)/,//匹配一对标签或多个标签,如<li></li>,li
    match = htmlStr.match(reMultiTag),
    tag = match ? match[1].toLowerCase() : "";//解析为<li,li
    if(match && tagWrap[tag]){
        var wrap = tagWrap[tag];
        div.innerHTML = wrap.pre + htmlStr + wrap.post;
        n = wrap.length;
        while(--n >= 0)//返回我们已经添加的内容
            div = div.lastChild;
    }else{
        div.innerHTML = htmlStr;
    }
    //处理IE自动插入tbody,如我们使用dom.parseHTML('<thead></thead>')转换HTML片断,它应该返回
    //'<thead></thead>',而IE会返回'<thead></thead><tbody></tbody>'
    //亦即,在标准浏览器中return div.children.length会返回1,IE会返回2
    if(dom.feature.autoInsertTbody && !!tagWrap[tag]){
        var ownInsert = tagWrap[tag].join('').indexOf("tbody") !== -1,//我们插入的
        tbody = div.getElementsByTagName("tbody"),
        autoInsert = tbody.length > 0;//IE插入的
        if(!ownInsert && autoInsert){
            for(var i=0,n=tbody.length;i<n;i++){
                if(!tbody[i].childNodes.length )//如果是自动插入的里面肯定没有内容
                    tbody[i].parentNode.removeChild( tbody[i] );
            }
        }
    }
    if (dom.feature.autoRemoveBlank && /^\s/.test(htmlStr) )
        div.insertBefore( dom.doc.createTextNode(htmlStr.match(/^\s*/)[0] ), div.firstChild );
    if (fragment) {
        var firstChild;
        while((firstChild = div.firstChild)){ // 将div上的节点转移到文档碎片上!
            fragment.appendChild(firstChild);
        }
        return fragment;
    }
    return div.children;
}

嘛,基本上就是这样,运行起来比jQuery快许多,代码实现也算优美,至少没有像jQuery那样乱成一团。jQuery还有四个反转方法。下面是jQuery的实现:

代码如下:

jQuery.each({
    appendTo: "append",
    prependTo: "prepend",
    insertBefore: "before",
    insertAfter: "after",
    replaceAll: "replaceWith"
}, function(name, original){
    jQuery.fn[ name ] = function( selector ) {//插入物(html,元素节点,jQuery对象)
        var ret = [], insert = jQuery( selector );//将插入转变为jQuery对象
        for ( var i = 0, l = insert.length; i < l; i++ ) {
            var elems = (i > 0 ? this.clone(true) : this).get();
            jQuery.fn[ original ].apply( jQuery(insert[i]), elems );//调用四个已实现的插入方法
            ret = ret.concat( elems );
        }
        return this.pushStack( ret, name, selector );//由于没有把链式操作的代码分离出去,需要自行实现
    };
});

我的实现:

代码如下:

dom.each({
    appendTo: 'append',
    prependTo: 'prepend',
    insertBefore: 'before',
    insertAfter: 'after'
},function(method,name){
    dom.prototype[name] = function(stuff){
        return dom(stuff)[method](this);
    };
});

大致的代码都给出,大家可以各取所需。

(0)

相关推荐

  • Javascript基于AJAX回调函数传递参数实例分析

    本文实例讲述了Javascript基于AJAX回调函数传递参数的方法.分享给大家供大家参考,具体如下: 前面介绍了<javascript实现html页面之间参数传递的四种方法>,这里针对ajax参数传递做一分析. 在Javascript 中,特别是在AJAX中,回调函数常常是一个函数名,没有地方放入参数,如下面的AJAX代码,在成功后将调用回调函数callback,但callback是有参数的,如何把参数传进来呢? var callback = function(p1){ //do somet

  • JS动态插入并立即执行回调函数的方法

    本文实例讲述了JS动态插入并立即执行回调函数的方法.分享给大家供大家参考,具体如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <

  • 谈谈JavaScript自定义回调函数

    废话不多说了,直接给大家贴代码了. 背景分析 首先看一段js的代码,主要实现添加的时候首先通过异步请求判断是否存在,如果不存在的话,在进行添加操作: function add(url,data) { var isExited = isExited(data); if(!isExited){ addRequest(url, data); } } 当我添加一个数据的时候,我首先通过判断是否在数据库中存在(当然,如果前后台彻底分离的话,不应该前端进行业务逻辑的判断,前端只应该,用来展示数据),首先,i

  • js的回调函数详解

    现在做native App  和Web App是主流,也就是说现在各种基于浏览器的web app框架也会越来越火爆了,做js的也越来越有前途.我也决定从后端开发渐渐向前端开发和手机端开发靠拢,废话不说了,我们来切入正题"js的回调函数"相关的东西. 说起回调函数,好多人虽然知道意思,但是还是一知半解.至于怎么用,还是有点糊涂.网上的一些相关的也没有详细的说一下是怎么回事,说的比较片面.下面我只是说说个人的一点理解,大牛勿喷.我们来看一下一个粗略的一个定义"函数a有一个参数,这

  • js自定义回调函数

    背景分析 首先看一段js的代码,主要实现添加的时候首先通过异步请求判断是否存在,如果不存在的话,在进行添加操作: function add(url,data) { var isExited = isExited(data); if(!isExited){ addRequest(url, data); } } 当我添加一个数据的时候,我首先通过判断是否在数据库中存在(当然,如果前后台彻底分离的话,不应该前端进行业务逻辑的判断,前端只应该,用来展示数据),首先,isExited()的请求是ajax请

  • 告诉你什么是javascript的回调函数

    函数也是对象 想弄明白回调函数,首先的清楚地明白函数的规则.在javascript中,函数是比较奇怪的,但它确确实实是对象.确切地说,函数是用Function()构造函数创建的Function对象.Function对象包含一个字符串,字符串包含函数的javascript代码.假如你是从C语言或者java语言转过来的,这也许看起来很奇怪,代码怎么可能是字符串?但是对于javascript来说,这很平常.数据和代码之间的区别是很模糊的. //可以这样创建函数 var fn = new Functio

  • js中回调函数的学习笔记

    回调函数是什么在学习之前还真不知道js回调函数怎么使用及作用了,下面本文章把我在学习回调函数例子给各位同学介绍一下吧,有需了解的同学不防进入参考. 回调函数原理: 我现在出发,到了通知你" 这是一个异步的流程,"我出发"这个过程中(函数执行),"你"可以去做任何事,"到了"(函数执行完毕)"通知你"(回调)进行之后的流程 例子 1.基本方法 <script language="javascript&q

  • JavaScript动态插入CSS的方法

    写组件时有时想把一些组件特性相关的 CSS 样式封装在 JS 里,这样更内聚,改起来方便.JS 动态插入 CSS 两个步骤:创建1.一个 style 对象 2.使用 stylesheet 的 insertRule 或 addRule 方法添加样式 一.查看样式表 先看下 document.styleSheets,随意打开一个页面 其中前三个是通过 link 标签引入的 CSS 文件,第四个是通过 style 标签内联在页面里的 CSS.有如下属性 每一个 cssRule 又有如下属性 其中的 c

  • 如何让动态插入的javascript脚本代码跑起来。

    首先,声明方法很多种,直接间接的方法都有,只罗列一般情况下的两种模式: 假设我们要装入的代码是a.js: var foo=function(){ document.write("I am a.js content foo() function by never-online"); }; 一.直接插入src,这种方法简单而直接,但有局限性, 1) <script> var x=document.createElement("SCRIPT"); x.src=

  • JavaScript动态插入script的基本思路及实现函数

    在日常的前端开发中,偶尔有需要动态插入javascript代码的需求,基本思路是: 1.动态创建一个script标签,设置其src属性,type属性等 2.将script节点插入页面,加载js文件 即相当于将<script type="text/javascript" src="xxx.js"></script>添加到了页面,只不过这个过程是动态完成的,为此特意封装了一个函数来实现: 复制代码 代码如下: // 动态插入script标签 fu

  • 得到文本框选中的文字,动态插入文字的js代码

    复制代码 代码如下: <script language="javascript" src="js/settags.js"></script>  function AppTag(tagcode)  {   document.PostMessage.Message.value += tagcode;  } function InsertTag(tagbegin,tagend)  {   if ((document.selection)&&

随机推荐