有没有办法在符合 W3C 的浏览器中获取 JavaScript Range 对象的 html 字符串?
例如,假设用户选择以下内容:
Hello <b>World</b>
Range.toString()
方法获取字符串形式的“Hello World”。
(在 Firefox 中,也可以使用 document 的 getSelection
方法。)
但我似乎找不到获取内部 HTML 的方法。
经过一番搜索,我发现范围可以转换为
DocumentFragment
对象。
但是
DocumentFragments
没有 innerHTML
属性(至少在 Firefox 中;没有尝试过 Webkit 或 Opera)。我意识到我可以创建一个
documentFragment
,将文档片段附加到另一个元素,然后获取该元素的 innerHTML
。那么,如何获取Range或DocFrag的html字符串呢?
那么,如何获取Range或DocFrag的html字符串呢?
与其他响应相反,可以使用 https://w3c.github.io/DOM-Parsing/#the 中描述的
DocumentFragment
方法直接将 DOMString
对象转换为 XMLSerializer.prototype.serializeToString
。 -xmlserializer-interface.
要获取 DOMString
对象的
Range
,只需使用
DocumentFragment
或
Range.prototype.cloneContents
方法将其转换为
Range.prototype.extractContents
,然后按照
DocumentFragment
对象的过程进行操作即可。我附上了一个演示,但其要点在于这两行:
const serializer = new XMLSerializer();
const document_fragment_string = serializer.serializeToString(document_fragment);
(() => {
"use strict";
const HTML_namespace = "http://www.w3.org/1999/xhtml";
document.addEventListener("DOMContentLoaded", () => {
/* Create Hypothetical User Range: */
const selection = document.defaultView.getSelection();
const user_range_paragraph = document.getElementById("paragraph");
const user_range = document.createRange();
user_range.setStart(user_range_paragraph.firstChild, 0);
user_range.setEnd(user_range_paragraph.lastChild, user_range_paragraph.lastChild.length || user_range_paragraph.lastChild.childNodes.length);
selection.addRange(user_range);
/* Clone Hypothetical User Range: */
user_range.setStart(selection.anchorNode, selection.anchorOffset);
user_range.setEnd(selection.focusNode, selection.focusOffset);
const document_fragment = user_range.cloneContents();
/* Serialize the User Range to a String: */
const serializer = new XMLSerializer();
const document_fragment_string = serializer.serializeToString(document_fragment);
/* Output the Serialized User Range: */
const output_paragraph = document.createElementNS(HTML_namespace, "p");
const output_paragraph_code = document.createElementNS(HTML_namespace, "code");
output_paragraph_code.append(document_fragment_string);
output_paragraph.append(output_paragraph_code);
document.body.append(output_paragraph);
}, { "once": true });
})();
<p id="paragraph">Hello <b>World</b></p>
$('<div>').append(fragment).html()
这里拼出一个例子:
//Example setup of a fragment
var frag = document.createDocumentFragment(); //make your fragment
var p = document.createElement('p'); //create <p>test</p> DOM node
p.textContent = 'test';
frag.appendChild( p );
//Outputting the fragment content using a throwaway intermediary DOM element (div):
var div = document.createElement('div');
div.appendChild( frag.cloneNode(true) );
console.log(div.innerHTML); //output should be '<p>test</p>'
Array.prototype.reduce.call(
documentFragment.childNodes,
(result, node) => result + (node.outerHTML || node.nodeValue),
''
);
不适用于内联 SVG,但可以采取一些措施让它工作。如果您需要对节点进行一些链式操作并获得 html 字符串作为结果,它也会有所帮助。
innerHTML
这样的扩展。关于您的评论
但是该方法会自动关闭任何 在我选择的区域内打开标签。...它还能如何工作? DOM 由排列在树中的节点组成。从 DOM 复制内容只能创建另一个节点树。在 HTML 中,元素节点由开始标记(有时也由结束标记)分隔。需要结束标记的元素的 HTML 表示形式必须具有结束标记,否则它不是有效的 HTML。
var frag = document.createRange().createContextualFragment("Hello <b>World</b>.");
console.log(frag.textContent)