js TreeWalker和/或document.createRange()没有拾取单个元素

时间:2017-10-17 21:46:39

标签: javascript html range

我有一个内部节点的div:

<section id="Source" class="source">
  <div>
    test
  </div>
</section>

我正在尝试使用document.createRange()document.createTreeWalker()获取其内容,如下所示:

function findEndNode(source, maxHeight) {
  const range = document.createRange();
  range.selectNodeContents(source);

  var nodes = document.createTreeWalker(
    source,
    NodeFilter.SHOW_ELEMENT,
    null,
    null
  );

  while (node = nodes.nextNode()) {
    range.setEndBefore(nodes.currentNode);
    const {
      height
    } = range.getBoundingClientRect();
    const rangeHeight = height;

    if (maxHeight <= rangeHeight) {
      console.log('out of  bounds');
      const newNode = nodes.previousNode();
      range.setEndBefore(nodes.currentNode);
      break;
    } else {
      console.log('within bounds');
      continue;
    }
  }

  return range;
};

但是在某个地方,最里面的节点会丢失。

正如您在完整代码中看到的那样(包含在代码段中),“test”范围保留在Source中,而应该移动到Clone。

const source = document.getElementById('Source');
const target = document.getElementById('Target');
const wrapper = document.getElementById('Wrapper');

wordWrap(source);
splitContent(source, target, wrapper);
//splitContent(source, target, wrapper);

function splitContent(source, target, wrapper) {
  const {
    height
  } = target.getBoundingClientRect();
  const maxHeight = height;

  const range = document.createRange();
  const endNode = findEndNode(source, maxHeight);
  
  range.setStart(source, 0);
  range.setEnd(endNode.endContainer, endNode.endOffset);

  const content = range.extractContents();
  const clone = target.cloneNode(false);
  clone.id = 'Clone';
  clone.appendChild(content);
  wrapper.appendChild(clone);

  const hasChildren = source.hasChildNodes();
};


function findEndNode(source, maxHeight) {
  const range = document.createRange();
  range.selectNodeContents(source);

  var nodes = document.createTreeWalker(
    source,
    NodeFilter.SHOW_ELEMENT,
    null,
    null
  );

  while (node = nodes.nextNode()) {
    range.setEndBefore(nodes.currentNode);
    const {
      height
    } = range.getBoundingClientRect();
    const rangeHeight = height;

    if (maxHeight <= rangeHeight) {
      console.log('out of  bounds');
      const newNode = nodes.previousNode();
      range.setEndBefore(nodes.currentNode);
      break;
    } else {
      console.log('within bounds');
      continue;
    }
  }

  return range;
};



function wordWrap(element) {
  var nodes = document.createTreeWalker(
    element,
    NodeFilter.SHOW_TEXT,
    null,
    null
  );
  var node;
  while (node = nodes.nextNode()) {
    var p = node.parentNode;
    var text = node.nodeValue;
    var m;
    while (m = text.match(/^(\s*)(\S+)/)) {
      text = text.slice(m[0].length);
      p.insertBefore(document.createTextNode(m[1]), node);
      var word = p.insertBefore(document.createElement('span'), node);
      word.appendChild(document.createTextNode(m[2]));
      word.className = 'word';
    }
    node.nodeValue = text;
  }
}
section {
  font-family: arial;
  font-size: 11pt;
}

.target {
  height: 400px;
  width: 400px;
  border: 2px dashed green;
  margin: 20px;
}

.source {
  border: 2px dashed blue;
  width: 400px;
  margin: 20px;
}
#Clone {
  border-color: red;
}
<section id="Source" class="source">
  <div>
    test
  </div>
</section>

<div id="Target" class="target">
</div>

<section id="Wrapper">
</section>

1 个答案:

答案 0 :(得分:1)

您的endoffset已关闭。在findEndNodes当您找到当前代码所假定的节点时,偏移的数量比必要的少一个,这是因为您在使用setEndAfter时正在使用setEndBefore。

const source = document.getElementById('Source');
const target = document.getElementById('Target');
const wrapper = document.getElementById('Wrapper');

wordWrap(source);
splitContent(source, target, wrapper);
//splitContent(source, target, wrapper);

function splitContent(source, target, wrapper) {
  const {
    height
  } = target.getBoundingClientRect();
  const maxHeight = height;

  const range = document.createRange();
  const endNode = findEndNode(source, maxHeight);
  
  range.setStart(source, 0);
  range.setEnd(endNode.endContainer, endNode.endOffset);

  const content = range.extractContents();
  const clone = target.cloneNode(false);
  clone.id = 'Clone';
  clone.appendChild(content);
  wrapper.appendChild(clone);

  const hasChildren = source.hasChildNodes();
};


function findEndNode(source, maxHeight) {
  const range = document.createRange();
  range.selectNodeContents(source);

  var nodes = document.createTreeWalker(
    source,
    NodeFilter.SHOW_ELEMENT,
    null,
    null
  );

  while (node = nodes.nextNode()) {
    range.setEndAfter(nodes.currentNode);
    const {
      height
    } = range.getBoundingClientRect();
    const rangeHeight = height;

    if (maxHeight <= rangeHeight) {
      console.log('out of  bounds');
      const newNode = nodes.previousNode();
      range.setEndAfter(nodes.currentNode);
      break;
    } else {
      console.log('within bounds');
      continue;
    }
  }

  return range;
};



function wordWrap(element) {
  var nodes = document.createTreeWalker(
    element,
    NodeFilter.SHOW_TEXT,
    null,
    null
  );
  var node;
  while (node = nodes.nextNode()) {
    var p = node.parentNode;
    var text = node.nodeValue;
    var m;
    while (m = text.match(/^(\s*)(\S+)/)) {
      text = text.slice(m[0].length);
      p.insertBefore(document.createTextNode(m[1]), node);
      var word = p.insertBefore(document.createElement('span'), node);
      word.appendChild(document.createTextNode(m[2]));
      word.className = 'word';
    }
    node.nodeValue = text;
  }
}
section {
  font-family: arial;
  font-size: 11pt;
}

.target {
  height: 400px;
  width: 400px;
  border: 2px dashed green;
  margin: 20px;
}

.source {
  border: 2px dashed blue;
  width: 400px;
  margin: 20px;
}
#Clone {
  border-color: red;
}
<section id="Source" class="source">
  <div>
    test
  </div>
</section>

<div id="Target" class="target">
</div>

<section id="Wrapper">
</section>