Skip to content

Note 10

innerText

HTMLElement 接口的 innerText 属性表示一个节点及其后代所渲染文本的内容。

  • 作为一个 getter,它近似于用户用光标突出该元素的内容,然后将其复制到剪贴板上所得到的文本
  • 作为一个 setter,这将用给定的值替换该元素的子元素,并将任何换行符转换为 <br> 元素。

备注

innerText 很容易与 Node.textContent 混淆,但这两个属性间实际上有很重要的区别。大体来说,innerText 知道文本的渲染外观,而 textContent 不知道。

输出

一个字符串,代表元素的渲染文本内容。

如果元素本身没有被渲染(例如,从文档中分离出来或从视图中隐藏起来),返回值与 Node.textContent 属性相同。

示例

这个示例对比了 innerTextNode.textContent。请注意 innerText 是如何意识到像 <br> 这样的元素,并忽略了隐藏的元素的。

html
<h3>源元素:</h3>
<p id="source">
  <style>
    #source {
      color: red;
    }
    #text {
      text-transform: uppercase;
    }
  </style>
  <span id="text">
    来看看<br />
    这段文字<br />
    在下方怎么表示。
  </span>
  <span style="display:none">隐藏文字</span>
</p>
<h3>textContent 结果:</h3>
<textarea id="textContentOutput" rows="6" cols="30" readonly>…</textarea>
<h3>innerText 结果:</h3>
<textarea id="innerTextOutput" rows="6" cols="30" readonly>…</textarea>
js
const source = document.getElementById("source")
const textContentOutput = document.getElementById("textContentOutput")
const innerTextOutput = document.getElementById("innerTextOutput")

textContentOutput.value = source.textContent
innerTextOutput.value = source.innerText

Alt textAlt text

Node.textContent

Node 接口的 textContent 属性表示一个节点及其后代的文本内容。

备注

textContentHTMLElement.innerText 容易混淆,但这两个属性在重要方面有不同之处 。

语法

js
let text = someNode.textContent
someOtherNode.textContent = string

返回值

一个字符串或 null.

描述

textContent 的值取决于具体情况:

  • 如果节点是一个 document,或者一个 DOCTYPE ,则 textContent 返回 null

    备注

    如果你要获取整个文档的文本以及 CDATA data ,可以使用 document.documentElement.textContent

  • 如果节点是个 CDATA section、注释、processing instruction (en-US) 或者 text node,textContent 返回节点内部的文本内容,例如 Node.nodeValue

  • 对于其他节点类型,textContent 将所有子节点的 textContent 合并后返回,除了注释和 processing instructions。(如果该节点没有子节点的话,返回一个空字符串。) 在节点上设置 textContent 属性的话,会删除它的所有子节点,并替换为一个具有给定值的文本节点。

与 innerText 的区别

不要对 Node.textContentHTMLElement.innerText 之间的差异感到困惑。虽然名字看起来很相似,但有重要的不同之处:

  • textContent 会获取所有元素的内容,包括 <script><style> 元素,然而 innerText 只展示给人看的元素。
  • textContent 会返回节点中的每一个元素。相反,innerTextCSS 样式的影响,并且不会返回隐藏元素的文本,
    • 此外,由于 innerText 受 CSS 样式的影响,它会触发回流( reflow )去确保是最新的计算样式。(回流在计算上可能会非常昂贵,因此应尽可能避免。)
  • textContent 不同的是,在 Internet Explorer (小于和等于 11 的版本) 中对 innerText 进行修改,不仅会移除当前元素的子节点,而且还会永久性地破坏所有后代文本节点。在之后不可能再次将节点再次插入到任何其他元素或同一元素中。

与 innerHTML 的区别

正如其名称,Element.innerHTML 返回 HTML。通常,为了在元素中检索或写入文本,人们使用 innerHTML。但是,textContent 通常具有更好的性能,因为文本不会被解析为 HTML

示例

给出这个 HTML 片段

html
<div id="divA">This is <span>some</span> text!</div>

你可以使用 textContent 去获取该元素的文本内容:

js
let text = document.getElementById("divA").textContent
// The text variable is now: 'This is some text!'

或者设置元素的文字内容:

js
document.getElementById("divA").textContent = "This text is different!"
// The HTML for divA is now:
// <div id="divA">This text is different!</div>

File对象转Blob

js
uploadFile (files) { // 统一上传文件方法
  console.log('files:', files)
  if (files.length) {
    const file = files[0]
    console.log('file', file)
    const type = file.type
    const reader = new FileReader()
    reader.readAsArrayBuffer(file)
    reader.onload = () => {
      const blob = new Blob([ reader.result ], { type })
      console.log('blob:', blob)
    }
  }
}

js属性检测

js
var boy = {
      name: 'curry'
    }

// ①检测对象属性是否存在
if ('age' in boy) { // 如果指定的属性在指定的对象或其原型链中,则 in 运算符返回 true
  console.log('age exist')
}

// ②检测是否为对象
if (Object.prototype.toString.call(boy.age) === '[object Object]') {
  console.log('boy.age is object')
}

// ③检测对象是否为空
if (JSON.stringify(boy.age) === '{}') {
  console.log('boy.age is {}')
}

// ④检测变量是否存在
// curry未声明 或者 声明未赋值 var/let curry
if (curry === 'undefined') {
  console.log('curry is undefined')
} else {
  console.log('curry is defined')
}

if (typeof curry === 'undefined') {
  console.log('curry is undefined')
} else {
  console.log('curry is defined')
}

Document.createDocumentFragment()

创建一个新的空白的文档片段 ( DocumentFragment (en-US))。

  • 语法

    js
    let fragment = document.createDocumentFragment() // fragment 是一个指向空DocumentFragment对象的引用
  • 描述

    DocumentFragments (en-US) 是 DOM 节点。它们不是主 DOM 树的一部分。通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到 DOM 树。在 DOM 树中,文档片段被其所有的子元素所代替。

    因为文档片段存在于内存中,并不在 DOM 树中,所以将子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。因此,使用文档片段通常会带来更好的性能。

示例

html
<ul id="ul"></ul>
js
var element = document.getElementById('ul') // assuming ul exists
var fragment = document.createDocumentFragment()
var browsers = ['Firefox', 'Chrome', 'Opera', 'Safari', 'Internet Explorer']

browsers.forEach(function (browser) {
  var li = document.createElement('li')
  li.textContent = browser
  fragment.appendChild(li)
})

element.appendChild(fragment) // 一次性插入。可以避免每次插入时导致的回流和重绘

Web Worker

Web Worker 使得在一个独立于 Web 应用程序主执行线程的后台线程中运行脚本操作成为可能。这样做的好处是可以在独立线程中执行费时的处理任务,使主线程(通常是 UI 线程)的运行不会被阻塞/放慢。(解决javascript单线程执行的一些弊端)

语法

js
const myWorker = new Worker(aURL, options)

参数


如果文档不允许启动 worker,则会引发 SecurityError 如果脚本之一的 MIME 类型为 text/csv, image/*, video/*audio/*, 则会引发 NetworkError。它应该始终是 text/javascript。 如果 aURL 无法解析,则引发 SyntaxError

  • aURL: 是一个 DOMString 表示 worker 将执行的脚本的 URL。它必须遵守同源策略
  • options
    可选
    : 包含可在创建对象实例时设置的选项属性的对象。可用属性如下:
    • type:用以指定 worker 类型的 DOMString 值。该值可以是 classicmodule. 如果未指定,将使用默认值 classic.
    • credentials:用以指定 worker 凭证的 DOMString 值。该值可以是 omit, same-origininclude。如果未指定,或者 typeclassic, 将使用默认值 omit (不要求凭证)。
    • name:在 DedicatedWorkerGlobalScope 的情况下,用来表示 workerscope 的一个 DOMString 值,主要用于调试目的

Web Worker 是一种在浏览器中运行 JavaScript 代码的机制,它允许您在后台线程中执行一些任务,而不会阻塞主线程。主线程通常用于处理用户界面的交互和渲染,而 Web Worker 可以用于执行一些耗时的计算、网络请求、数据处理等任务,以提高应用的性能和响应速度。 它的主要特点是能进行并行计算,他允许在后台同时运行多个线程,这些线程可以并行执行任务。这使得可以同时处理多个耗时的操作,而不会阻塞用户界面

Web Worker 概念与用法


Worker 是一个使用构造函数创建的对象(例如 Worker()),它运行一个具名 JavaScript 文件——该文件包含将在 worker 线程中运行的代码。

除了标准的 JavaScript 函数集(如 StringArrayObjectJSON 等),你可以在 worker 线程中运行任何你喜欢的代码,有一些例外:你不能直接在 worker 线程中操作 DOM 元素,或使用 window 对象中的某些方法和属性。有关你可以运行的代码的信息,请参见下面的 Worker 全局上下文和函数支持的 Web API

数据通过消息系统在 worker 和主线程之间发送——双方都使用 postMessage() 方法发送消息,并通过 onmessage 事件处理程序响应消息(消息包含在 message 事件的 data 属性中)。数据是复制的,而不是共享的

worker 可以依次生成新的 worker,只要这些 worker 与父页面托管在同一个 origin 中。此外,worker 可以通过 XMLHttpRequest 来访问网络,但 XMLHttpRequestresponseXMLchannel 属性始终返回 null

Web Worker 使用场景

  • 定时器场景,setIntervalrequestAnimationFrame,需要在用户切换 tab 栏的时候仍然执行 requestAnimationFramesetInterval

示例

work.js 代码

js
// self.onmessage = (event) => { ... }
self.addEventListener('message', (e) => {
  console.log('web worker 收到来自主线程的消息:', e.data)
  const result = doSomeHeavyWork(e.data)
  self.postMessage(result) // 将操作结果发送到主线程
})
function doSomeHeavyWork (data) {
  // 执行耗时的计算或任务
  return data * 2
}

// ESModule模式
import doSomeHeavyWork from './utils.js' // 导入外部js
// utils.js
// export default doSomeHeavyWork = (a) => a * 2

self.addEventListener('message', e => { 
  const result = doSomeHeavyWork(e.data)
  postMessage(e.data)
})

export default self // 把顶级对象self暴露出去

主线程代码

js
const myWorker = new Worker('worker.js')
// 发送消息到 Web Worker
myWorker.postMessage(66)
// 监听从 Web Worker 返回的结果
myWorker.addEventListener('message', (event) => {
  console.log('接收到 web worker 返回的信息:', event.data)
  myWorker.terminate() // 立即终止 web worker
})

// ESModule模式
const worker = new Worker('worker.js', {
  type: 'module' // 指定 worker.js 的类型
})

Worker.postMessage()
宏任务


Worker 接口的 postMessage() 方法可以向 worker 发送消息。第一个参数是要发送到 worker 的数据。该数据可以是任何可以被结构化克隆算法处理的 JavaScript 对象。

  • 语法
js
postMessage(message)
postMessage(message, transfer)
  • 参数
    • message
      要传递给 worker 的对象;这将在传递给 DedicatedWorkerGlobalScope.message_event 事件的 data 字段中。这可以是任何值或可以通过结构化克隆算法处理的 JavaScript 对象(可以包含循环引用)。

      如果未提供 message 参数,则解析器将抛出 SyntaxError。如果要传递给 worker 的数据不重要,可以显式传递 nullundefined

    • transfer

      可选

      一个可选的、会被转移所有权的可转移对象数组。如果一个对象的所有权被转移,它将在发送它的上下文中变为不可用(中止),而仅在接收方的 worker 中可用。

      ArrayBufferMessagePortImageBitmap 类的实例才是可转移对象,才能够被转移。不能将 null 作为 transfer 的值。

Worker:message 事件


worker 的父级接收到来自其 worker 的消息时(也就是说,当 worker 通过 DedicatedWorkerGlobalScope.postMessage() (en-US) 发送消息时),会在 Worker 对象上触发 message 事件。此事件不能取消,也不会冒泡。

  • 语法
js
addEventListener('message', (event) => {})
onmessage = (event) => {}
  • 示例

下面的代码创建了一个 worker 并使用 addEventListener() 监听从 worker 发来的消息:

js
const worker = new Worker("static/scripts/worker.js")

worker.addEventListener("message", (event) => {
  console.log(`Received message from worker: ${event.data}`)
})

另外,也可以使用 onmessage 事件处理器属性进行监听:

js
const worker = new Worker("static/scripts/worker.js")

worker.onmessage = (event) => {
  console.log(`Received message from worker: ${event.data}`)
}

Worker.terminate()


Worker 接口中的 terminate() 方法用于立即终止 Worker 的行为。本方法并不会等待 worker 去完成它剩余的操作;worker 将会被立刻停止

js
var myWorker = new Worker("worker.js")

myWorker.terminate()

importScripts()

WorkerGlobalScope 接口的 importScripts() 方法将一个或多个脚本同步导入到工作者的作用域中

语法

js
self.importScripts('foo.js') /* 只引入 "foo.js" */
self.importScripts('foo.js', 'bar.js', ...) /* 引入两个脚本 */
self.importScripts("//example.com/hello.js") /* 你可以从其他来源导入脚本 */

示例

如果你在一个名为 foo.js 的单独脚本中编写了一些你想在 worker.js 中使用的功能,则可以使用以下行导入它:

js
importScripts('foo.js')

importScripts()self.importScripts() 实际上是等效的 — 都表示从工作者的内部范围内调用的 importScripts()

window.self

返回一个指向当前 window 对象的引用。

语法

js
objRef = window.self

示例

js
if (window.parent.frames[0] != window.self) {
  // 当前对象不是 frames 列表中的第一个时
}

备注

window.self 几乎总是用于上面示例那样的比较,用来判断当前 window 是不是父 frameset 中的第一个 frame

Released under the MIT License.