Sam*_*ody 20 javascript range tostring selection documentfragment
有没有办法在W3C兼容的浏览器中获取JavaScript范围对象的html字符串?
例如,假设用户选择以下内容:Hello <b>World</b>
可以使用该Range.toString()方法将"Hello World"作为字符串.(在Firefox中,也可以使用文档的getSelection方法.)
但我似乎无法找到获取内部HTML的方法.
经过一番搜索,我发现范围可以转换为DocumentFragmentObject.
但是DocumentFragments没有innerHTML属性(至少在Firefox中;没有尝试过Webkit或Opera).
这对我来说似乎很奇怪:显然应该有一些方法来访问所选项目.
我意识到我可以创建一个documentFragment,将文档片段附加到另一个元素,然后获取该innerHTML元素.
但该方法将自动关闭我选择的区域内的任何打开的标签.
除此之外,肯定有一个明显的"更好的方法",而不是将它附加到dom只是为了让它成为一个字符串.
那么,如何获取Range或DocFrag的html字符串?
Bri*_*unt 13
FWIW,jQuery方式:
$('<div>').append(fragment).html()
Run Code Online (Sandbox Code Playgroud)
从这里拼出一个例子:
//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>'
Run Code Online (Sandbox Code Playgroud)
不,这是唯一的方法。大约 10 年前的 DOM Level 2 规范在节点与 HTML 文本之间的序列化和反序列化方面几乎没有任何内容,因此您不得不依赖innerHTML.
关于你的评论
但该方法将自动关闭我选择的区域内的所有打开标签。
......它还能如何工作?DOM 由排列在树中的节点组成。从 DOM 复制内容只能创建另一个节点树。元素节点在 HTML 中由开始标记(有时是结束标记)分隔。需要结束标记的元素的 HTML 表示必须有结束标记,否则它不是有效的 HTML。
那么,如何获取Range或DocFrag的html字符串?
违背其他响应,它是可以直接把一个DocumentFragment对象到DOMString使用XMLSerializer.prototype.serializeToString在描述的方法https://w3c.github.io/DOM-Parsing/#the-xmlserializer-interface.
为了得到DOMString一个的Range对象,简单地把它转换到DocumentFragment使用任一Range.prototype.cloneContents或Range.prototype.extractContents方法,然后按照一个程序DocumentFragment对象.
我附上了一个演示,但它的要点是这两行:
const serializer = new XMLSerializer();
const document_fragment_string = serializer.serializeToString(document_fragment);
Run Code Online (Sandbox Code Playgroud)
(() => {
"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 });
})();Run Code Online (Sandbox Code Playgroud)
<p id="paragraph">Hello <b>World</b></p>Run Code Online (Sandbox Code Playgroud)
另一种方法是迭代 childNodes:
Array.prototype.reduce.call(
documentFragment.childNodes,
(result, node) => result + (node.outerHTML || node.nodeValue),
''
);
Run Code Online (Sandbox Code Playgroud)
不适用于内联 SVG,但可以采取一些措施使其正常工作。如果您需要对节点进行一些链式操作并因此获得 html 字符串,它也有帮助。