脚本标记中的Text属性-澄清

Text property in script tags - Clarification?

本文关键字:属性 澄清 Text 脚本      更新时间:2023-09-26

在读取angular的指令代码时,我看到这个

var scriptDirective = ['$templateCache', function($templateCache) {
  return {
    restrict: 'E',
    terminal: true,
    compile: function(element, attr) {
      if (attr.type == 'text/ng-template') {
        var templateUrl = attr.id,
            text = element[0].text;// <-- Look here
        $templateCache.put(templateUrl, text);
      }
    }
  };
}];

但我不知道text属性是什么(我的意思是——为什么不使用innerText?)

有人告诉我:

"这就像textContent只抓取元素内部的文本节点,没有递归或类似的东西"

同时查看文档:

IDL属性文本必须返回的内容的串联作为script元素子级的所有Text节点(忽略诸如注释或元素之类的任何其他节点)。在…上设置,它必须以与textContent IDL属性相同的方式操作。

我还不清楚。

马里兰州:

text:与textContent属性一样,该属性设置元素的文本内容。然而与textContent属性不同,在节点被插入到DOM中。

所以我创建了一个测试

<script id="a"   type="blabla">
 foo
   <b>bar</b>
   baz
</script> 

<script >
 console.log(document.getElementById('a').text)
 console.log(document.getElementById('a').textContent)
</script>

但两者都显示了精确的内容:

"
 foo
   <b>bar</b>
   baz
"

问题:

  • 为什么angular使用text而不使用textContent?如果这是一个模板,那么他们确实需要考虑标签。。。。不

  • innerText/text/textContent之间(在脚本标记中)有什么区别?

顺便说一句,这里也有一个类似的问题,但它没有太多地谈论script范围(这实际上是我问题中的必选项)

这里是jsbin的一个分支,您可以在其中看到差异:http://jsbin.com/tovipiruce/1/edit?html,js,输出

或者,如果你是一个片段爱好者:

var scriptElem = document.getElementById('a');
var child = document.createElement('b');
child.textContent = 'Look at me! I am irrelevant!';
var comment = document.createComment('I contain a lot of wisdom');
var justText = document.createTextNode('just your average text node');
scriptElem.appendChild(child);
scriptElem.appendChild(comment);
scriptElem.appendChild(justText);
console.log(scriptElem);
console.log('textContent:', scriptElem.textContent);
console.log('innerText:', scriptElem.innerText);
console.log('text:', scriptElem.text);
<!DOCTYPE html>
<html>
<body>
  
<p>Open your console</p>
<script id="a" type="blabla">
foo
<b>bar</b>
baz
</script>
</body>
</html>

这里最大的区别是如何处理子元素:textContent包括子元素,因此输出包含Look at me! I am irrelevant!,而text不会

我将在代码中重复一遍:

scriptElem.textContent.includes('Look at me!'); // true
scriptElem.text.includes('Look at me!'); // false

Getter

让我们来看看textContenttext的getter的一个非常天真的实现:

function textContent(elem) {
    return Array.from(elem.childNodes).map(node => {
        // recurse into element nodes
        if (node.type === Node.ELEMENT_NODE) {
            return textContent(elem);
        }
        // return the value of text nodes
        if (node.type === Node.TEXT_NODE) {
            return node.nodeValue;
        }
        // and ignore everything else
        return '';
    }).join('');
}
function text(elem) {
    return Array.from(elem.childNodes).map(node => {
        // return the value of text nodes
        if (node.type === Node.TEXT_NODE) {
            return node.nodeValue;
        }
        // and ignore everything else
        return '';
    }).join('');
}

正如您所看到的(正如规范和示例所示),当get处理元素的text属性时,只处理文本节点,而textContent还将其元素子级的textContent放入混合中。

CCD_ 17是一个更复杂的野兽,在这个答案中不会解释;它就像一个标准化的CCD_ 18。你可以在Kagnax的这篇精彩的博客文章中阅读更多关于它的信息。

The Setter

现在让我们来谈谈set ter。规范说它应该以与设置textContent相同的方式进行操作,但mdn说了以下奇怪的事情:

然而,与textContent属性不同的是,在将节点插入DOM后,该属性将被评估为可执行代码。

有两种方法可以解释这句话:要么在将脚本的textContent注入页面之前设置它没有效果,而设置text有效果,要么在将其注入页面之后设置textContent没有效果,但设置text有效果。

在最新的Chrome(47)和Firefox(43)上测试表明,这两种解释都是错误的:在注入前设置textContent有效,在注入后设置text无效。如果有人有一个IE,并希望测试这个,如果你编辑这个答案,我将不胜感激。

。。。但为什么呢

所以我们已经经历了二传手和接球手。现在让我们来问一下text为什么有用?这是一个悬而未决的问题。坦率地说,我真的不知道。正如您在原始代码中所看到的,您不能只在脚本标记中插入标记,它不会被解析为html。因此,查看差异的唯一方法是在脚本标记中动态注入节点。

我在那个文件上运行了git blame,发现它来自这个提交:

修复(脚本):错误地读取ie 上的脚本文本

IE以特殊的方式处理脚本标记,.text()不起作用。读取.text属性可以直接修复此问题。

添加的测试用例在脚本标记内部进行绑定。我不知道angular,所以我不知道这意味着什么,我也没有IE,所以当你使用textContent而不是text时,我无法检查测试用例中发生了什么。

但当我看到IE还活着并开始工作时,我忍不住笑了。