用JS / jQuery中的文本替换DOM树中的非图像元素

时间:2011-08-22 08:42:09

标签: javascript jquery dom contenteditable

我想将img内的非contenteditable元素替换为其文本。但是,我想保留任何img元素,包括嵌套在其他元素中的元素。换句话说:

给出如下输入:

<div><span>Foo <strong>Bar <img src="blah.png"></strong> and more text <img src="another.png"></span> With some other text <img src="yetmore.png"></div>

我想制作:

Foo Bar <img src="blah.png"> and more text <img src="another.png"> With some other text <img src="yetmore.png">

由于这是一个contenteditable,我不想使用innerHTML读/写,因为它将丢失光标位置等(恢复它是硬的,因为你最终得到一个不同的DOM树,所以您的选择节点会丢失)。

我最好的选择是迭代树并手动拆分和连接文本节点等等?我希望有更好的方法,或者已经可以做这样的事情的图书馆...

3 个答案:

答案 0 :(得分:3)

对根元素进行浅层克隆。沿着原始元素树走,收集文本。当您遇到img元素时,将收集的文本添加到作为克隆子项的文本节点。附加img。再次开始收集文本。

一直走到最后,然后用克隆替换文档中的原始根元素。

修改

类似的东西:

function toArray(o) {
  var a = [], i = o.length;
  while (i--) {
    a[i] = o[i];
  }
  return a;
}

function cleanUp(el) {

  var e = el.cloneNode(false);

  function addText(text) {
    if (text != '') {
      e.appendChild(document.createTextNode(text));
    }
  }

  function collectText(el) {
    var node, nodes = toArray(el.childNodes);
    var text = '';

    for (var i=0, iLen=nodes.length; i<iLen; i++) {
      node = nodes[i];

      if (node.tagName && node.tagName.toLowerCase() == 'img') {
        addText(text);
        e.appendChild(node);
        text = '';

      } else if (node.nodeType == 3) {
        text += node.data;

      } else if (node.nodeType == 1) {
        addText(text);
        text = '';
        collectText(node);
      }
    }

    if (text != '') {
      e.appendChild(document.createTextNode(text));
    }
  }
  collectText(el);
  el.parentNode.replaceChild(e, el);
}

答案 1 :(得分:3)

进行DOM替换几乎肯定会丢失光标位置/选择,但仍然是正确的方法。我建议Rangy saving and restoring the selection和跨浏览器范围/选择处理(披露:我是Rangy的作者)。

这是一个删除非<img>元素并在所有主流浏览器(包括IE 6)中保留先前选择/插入位置的示例。它递归地将主容器节点的<img>和文本后代移动到DocumentFragment,并在最终将片段附加到现在为空的容器节点之前移除所有其他节点。它还规范化(即连接相邻的文本节点)。

jsFiddle with Rangy选择保存并恢复:http://jsfiddle.net/CRLRj/1/

元素删除代码:

function removeNonImgElements(node) {
    var frag = document.createDocumentFragment();

    function move(node, moveSelf) {
        var type = node.nodeType, name = node.nodeName;

        // Deal with child nodes first
        var child;
        while ( (child = node.firstChild) ) {
            move(child, true);
        }

        if (!moveSelf) {
            return;
        }

        // Keep text, images and Rangy selection marker elements
        if (type == 1 && (name == "IMG" ||
                 (name == "SPAN" && /^selectionBoundary/.test(node.id)))) {
            frag.appendChild(node);
        } else if (type == 3) {
            var previousNode = frag.lastChild;
            if (previousNode && previousNode.nodeType == 3) {
                // Concatenate text nodes rather than have two adjacent
                previousNode.data = previousNode.data + node.data;
                node.parentNode.removeChild(node);
            } else {
                frag.appendChild(node);
            }
        } else {
            node.parentNode.removeChild(node);
        }
    }

    move(node, false);
    node.appendChild(frag);
}

答案 2 :(得分:1)

$(document).ready(function(){
    replaceChildren($('#contenteditable'));
});

function replaceChildren(elem){
    $(elem).children("*").not("img").each(function(){
        if ($(this).children("*").not("img").length>0){
            replaceChildren(this);
        }
        $(this).after($(this).html());
        $(this).remove();
    });
}

某种递归解决方案。