Converting Range or DocumentFragment to string

前端 未结 6 1083
无人共我
无人共我 2021-02-05 03:07

Is there a way to get the html string of a JavaScript Range Object in W3C compliant browsers?

For example, let us say the user selects the following: Hello

相关标签:
6条回答
  • 2021-02-05 03:28

    To spell out an example from here:

    //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>'
    
    0 讨论(0)
  • 2021-02-05 03:41

    No, that is the only way of doing it. The DOM Level 2 specs from around 10 years ago had almost nothing in terms of serializing and deserializing nodes to and from HTML text, so you're forced to rely on extensions like innerHTML.

    Regarding your comment that

    But that method will auto close any open tags within the area I select.

    ... how else could it work? The DOM is made up of nodes arranged in a tree. Copying content from the DOM can only create another tree of nodes. Element nodes are delimited in HTML by a start and sometimes an end tag. An HTML representation of an element that requires an end tag must have an end tag, otherwise it is not valid HTML.

    0 讨论(0)
  • 2021-02-05 03:43

    Another way to do it would be to iterate over childNodes:

    Array.prototype.reduce.call(
        documentFragment.childNodes, 
        (result, node) => result + (node.outerHTML || node.nodeValue),
        ''
    );
    

    Wouldn't work for inlined SVG, but something could be done to get it to work. It also helps if you need to dome some chained manipulation with the nodes and get an html string as a result.

    0 讨论(0)
  • 2021-02-05 03:44

    So, how to get the string of the html of a Range or DocFrag?

    Contrary to the other responses, it is possible to directly turn a DocumentFragment object into a DOMString using the XMLSerializer.prototype.serializeToString method described at https://w3c.github.io/DOM-Parsing/#the-xmlserializer-interface.

    To get the DOMString of a Range object, simply convert it to a DocumentFragment using either of the Range.prototype.cloneContents or Range.prototype.extractContents methods and then follow the procedure for a DocumentFragment object.

    I've attached a demo, but the gist of it is in these two lines:

    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>

    0 讨论(0)
  • 2021-02-05 03:48

    Could DocumentFragment.textContent give you what you need?

    var frag = document.createRange().createContextualFragment("Hello <b>World</b>.");
    
    console.log(frag.textContent)

    0 讨论(0)
  • 2021-02-05 03:50

    FWIW, the jQuery way:

    $('<div>').append(fragment).html()
    
    0 讨论(0)
提交回复
热议问题