admin管理员组

文章数量:1431720

Is it possible to have DocumentFragments contain tr, th or td tags?

If I do this:

var template = document.createRange().createContextualFragment(
        '<table></table>'
    );

    console.log(template.childNodes);

I get the output of [table].

If I do this:

var template = document.createRange().createContextualFragment(
        '<td></td>'
    );

    console.log(template.childNodes);

I get the output of []!!!?!?

If I do this:

var template = document.createRange().createContextualFragment(
        '<td><p></p></td>'
    );

    console.log(template.childNodes);

I get [p]??!?!?!??!?!??!

And finally if I do this:

var template = document.createRange().createContextualFragment(
        '<span><td></td></span>'
    );

    console.log(template.childNodes);

I get [span] - where's the td gone??!

I don't understand the inconsistency here. Is it possible for document fragments to only hold certain elements? What I would like to do is do something akin to the second this above, and then retrieve the td using querySelector.

Thanks

Is it possible to have DocumentFragments contain tr, th or td tags?

If I do this:

var template = document.createRange().createContextualFragment(
        '<table></table>'
    );

    console.log(template.childNodes);

I get the output of [table].

If I do this:

var template = document.createRange().createContextualFragment(
        '<td></td>'
    );

    console.log(template.childNodes);

I get the output of []!!!?!?

If I do this:

var template = document.createRange().createContextualFragment(
        '<td><p></p></td>'
    );

    console.log(template.childNodes);

I get [p]??!?!?!??!?!??!

And finally if I do this:

var template = document.createRange().createContextualFragment(
        '<span><td></td></span>'
    );

    console.log(template.childNodes);

I get [span] - where's the td gone??!

I don't understand the inconsistency here. Is it possible for document fragments to only hold certain elements? What I would like to do is do something akin to the second this above, and then retrieve the td using querySelector.

Thanks

Share Improve this question edited Dec 4, 2017 at 19:11 Supersharp 31.3k11 gold badges102 silver badges147 bronze badges asked Mar 29, 2017 at 19:54 Raiden616Raiden616 1,5643 gold badges19 silver badges46 bronze badges 3
  • Why are you using document.createRange()… and not just document.createDocumentFragment()? The later can contain just <td>s perfectly well. – Matijs Commented Mar 29, 2017 at 20:02
  • I wasn't awRe there was a difference to be honest.. I was using the former to allow me to specify xhtml direct. Is there a way of doing that with the latter method? – Raiden616 Commented Mar 29, 2017 at 20:15
  • @Matijs I just tried it with createDocumentFragment() and get the same result... – Raiden616 Commented Mar 29, 2017 at 20:34
Add a ment  | 

3 Answers 3

Reset to default 7

Solution 1

Use createDocumentFragment(), create a <td> element, and add it to the DocumentFragment with appendChild():

var frag = document.createDocumentFragment()
frag.appendChild( document.createElement( 'td' ) )
console.log( frag.childNodes )  // output => [td]

Solution 2

Create a <template> element, add HTML content to innerHTML, then get the DocumentFragment from the content property:

var template = document.createElement( 'template' )
template.innerHTML = '<td></td>'
var frag = template.content
console.log( frag.childNodes )   // output => [td]

I have written a library for doing just this (creating document fragments from an HTML string). It is called html-fragment.

This small library attempts to use the range API (as you are doing), but if the top level node is a node that needs a specific parent node (such as a td), it will attempt to try some other solutions, such as a template if it is supported, otherwise it does it the "old fashioned way" where it wraps it first with the correct parent tag, and then adds the nodes you wanted to the document fragment (without the temporary parent nodes).

You would use it like so:

var html = '<td><p>Hello World</p></td>';
var fragment = HtmlFragment(html);

console.log(fragment.firstChild) //td
<script src="https://unpkg./[email protected]/lib/html-fragment.min.js"></script>

const range = new Range()
const tableRange = new Range()

const table = document.createElement('table')
const tbody = document.createElement('tbody')
const tr = document.createElement('tr')
const colgroup = document.createElement('colgroup')

/**
 * https://developer.mozilla/en-US/docs/Web/HTML/Element#Table_content
 */
const tableTags = [
  'tbody',
  'thead',
  'tfoot',
  'caption',
  'colgroup',
  'col',
  'tr',
  'td',
  'th'
]


export function createFragment(str: string) {
  const firstTag = str.match(/^<(([a-z]|-)+)/)?.[1]
  if (firstTag && tableTags.includes(firstTag)) {
    switch (firstTag) {
      case 'tbody':
      case 'thead':
      case 'tfoot':
      case 'caption':
      case 'colgroup':
        tableRange.selectNodeContents(table)
        break
      case 'tr':
        tableRange.selectNodeContents(tbody)
        break
      case 'td':
      case 'th':
        tableRange.selectNodeContents(tr)
        break
      case 'col':
        tableRange.selectNodeContents(colgroup)
        break
      default:
        break
    }
    return tableRange.createContextualFragment(str)
  }
  return range.createContextualFragment(str)
}

本文标签: javascriptCannot create DocumentFragment storing tdtr or thStack Overflow