资讯专栏INFORMATION COLUMN

掌控 DOM - 它不像你想的那么难

Reducto / 559人阅读

摘要:很多开发者认为是真的很难或者很慢以至于你需要一个巨大的框架才能让它服帖。如果我告诉你其实没那么复杂,你信吗并不难并且它也不慢。它很聪明的和已经附加在的元素进行比较并按需进行插入移除重排等操作

很多开发者认为 DOM 是真的很难(或者很慢)以至于你需要一个巨大的框架才能让它服帖。于是他们投入了大量的时间去学习这些框架。一两年过去了,又一个框架火了于是你不得不扔掉之前的框架从头学起。这样的事情多重复几次就能让你对 JavaScript 产生疲劳,更不用说那多的数不过来的依赖。

如果我告诉你 DOM 其实没那么复杂,你信吗?

DOM 并不难并且它也不慢。

创建元素

要创建一个元素,你只需要写 document.createElement(tagName)

const h1 = document.createElement("h1")

// 

修改文本内容

HTML 元素如果没有任何内容,那就是空的,让我们用 element.textContent 来增加一些文本

h1.textContent = "Hello world!"

// 

Hello world!

属性

要定义一个 HTML 元素的属性,你可以用 element.setAttribute(name, value)

h1.setAttribute("class", "hello")

// 

Hello world!

若要管理 class 有一个 element.className 属性

h1.className = "hello"

// 

Hello world!

但是,最好的方式是使用 classList

h1.classList.add("hello")

// 

Hello world!

h1.classList.remove("hello") //

Hello world!

要设置一个元素的 ID,你可以使用标签属性或者 id 属性

h1.setAttribute("id", "hello-world")

h1.id = "hello-world"

// 

Hello world!

如果你不确定用标签属性(attributes)还是对象属性(properties),就用标签属性 (表单元素的状态除外,如 value 和 checked)

注意,有些布尔值的修改不能使用 element.setAttribute(someBoolean, false),下面这些则可以

input.checked = true

// 

input.checked = false

// 

input.setAttribute(‘checked’, ‘’)

// 

input.removeAttribute("checked")
// 
元素附加

HTML 是结构化的。可以通过 parent.appendChild(child) 来实现元素附加

document.body.appendChild(h1)

// 

Hello world!

元素移除

有时候你希望去掉一个元素,那么你可以使用 parent.removeChild(child)

document.body.removeChild(h1)

// 
元素查找

你可以使用下列方法来查找子元素

document.getElementById(id)

element.childNodes[i]

element.firstChild === element.childNodes[0]

element.lastChild === element.childNodes[element.childNodes.length - 1]

element.getElementsByTagName(tagName)

element.getElementsByClassName(className)

element.querySelector(query)

element.querySelectorAll(query)

注意 getElementsByTagName, getElementsByClassName 和 querySelectorAll 返回的不是数组,而是 NodeList,你不能通过 ES5 的数组快速访问方式来迭代。

元素间插入元素

想要将元素查到另一个元素的前面?试试 parent.insertBefore(child, before)

/*

 *  

 *    

 *  

 */

document.body.insertBefore(h1, document.body.firstChild)

/*  

 *    

Hello world!

* * */
创建元素列表

如果我们有一些数据,可以很容易的动态创建元素。

const data = [
  [ 1, 2, 3 ],
  [ 4, 5, 6 ],
  [ 7, 8, 9 ]
]
const table = document.createElement("table")

data.forEach(row => {
  const tr = document.createElement("tr")

  row.forEach(cell => {
    const td = document.createElement("td")

    td.textContent = cell
    tr.appendChild(td)
 })

  table.appendChild(tr)
})

document.body.appendChild(table)

https://jsfiddle.net/pakastin...

更新元素列表

你希望元素保持最新状态,可以这么做

const table = document.createElement("table")

document.body.appendChild(table)

updateTable(table, [
  [ 1, 2 ],
  [ 3, 4, 5 ],
  [ 6, 7, 8, 9 ]
])

setTimeout(() => {
  updateTable(table, [
    [ 1, 2, 3, 4 ],
    [ 5, 6, 7 ],
    [ 8, 9 ]
  ])
}, 1000)

function updateTable (table, data) {
  const rowLookup = table._lookup || (table._lookup = [])

  setChildren(table, updateRows(rowLookup, data))
}

function updateRows (rowLookup, rows) {
     return rows.map((row, y) => {
    const tr = rowLookup[y] || (rowLookup[y] = document.createElement("tr"))
    const cellLookup = tr._lookup || (tr._lookup = [])

    setChildren(tr, updateCells(cellLookup, row))

    return tr
  })
}

function updateCells (cellLookup, cells) {
     return cells.map((cell, x) => {
    const td = cellLookup[x] || (cellLookup[x] = document.createElement("td"))

    td.textContent = cell

    return td
  })
}

function setChildren (parent, children) {
  let traverse = parent.firstChild

  for (let i = 0; i < children.length; i++) {
    const child = children[i]

    if (child == null) {
      return
    }

    if (child === traverse) {
      traverse = traverse.nextSibling
    } else if (traverse) {
      parent.insertBefore(child, traverse)
    } else {
      parent.appendChild(child)
    }
  }

  while (traverse) {
    const next = traverse.nextSibling

    parent.removeChild(traverse)

    traverse = next
  }
}

https://jsfiddle.net/pakastin...

以上代码有两个事情发生

一个隐藏属性 element._lookup = [] 用来查找子元素,使用lookup 我们可以复用DOM中已经存在的元素并更新它们。

setChildren(parent, children) 方法能让你提供一个元素列表。它很聪明的和已经附加在 parent的元素进行比较并按需进行 插入 移除 重排等操作

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91357.html

相关文章

  • 二十五岁零基础转行做软件测试怎么样?一个过来人的心路历程送给迷茫的你

    摘要:一个软件测试在职老人帮你详细分析一下。在软件测试行业,前两点可以结合起来说,就是大环境和前景以及人才缺口的问题。软件测试属于互联网技术的一个分支,就是经常被提到的行业。你零基础转行嗷,良心奉劝你不要自学。 一个软件测试在职老人帮你详细分析一下。先不说软件测试领域,你想转行的话,得知道这个行...

    AlienZHOU 评论0 收藏0
  • 和BEM的战斗:10个常见问题及如何避免

    摘要:我发现使用这些命名空间会使我的代码非常具有可读性。跨组件的组建我们面临的另一个常见的问题是组件的样式和位置会受到父级容器的影响。 无论你是刚刚发现BEM或者已经是个中熟手(作为web术语来说),你可能已经意识到它是一种有用的方法。如果你还不知道BEM是什么,我建议你在继续阅读这篇文章之前去BEM website了解一下它,因为我会假设你对这种CSS的方法有一个基础的理解。 本文旨在对那...

    dongfangyiyu 评论0 收藏0
  • 和BEM的战斗:10个常见问题及如何避免

    摘要:我发现使用这些命名空间会使我的代码非常具有可读性。跨组件的组建我们面临的另一个常见的问题是组件的样式和位置会受到父级容器的影响。 无论你是刚刚发现BEM或者已经是个中熟手(作为web术语来说),你可能已经意识到它是一种有用的方法。如果你还不知道BEM是什么,我建议你在继续阅读这篇文章之前去BEM website了解一下它,因为我会假设你对这种CSS的方法有一个基础的理解。 本文旨在对那...

    mumumu 评论0 收藏0
  • 和BEM的战斗:10个常见问题及如何避免

    摘要:我发现使用这些命名空间会使我的代码非常具有可读性。跨组件的组建我们面临的另一个常见的问题是组件的样式和位置会受到父级容器的影响。 无论你是刚刚发现BEM或者已经是个中熟手(作为web术语来说),你可能已经意识到它是一种有用的方法。如果你还不知道BEM是什么,我建议你在继续阅读这篇文章之前去BEM website了解一下它,因为我会假设你对这种CSS的方法有一个基础的理解。 本文旨在对那...

    荆兆峰 评论0 收藏0
  • 学习python12小时后,告诉你,学python真没你想的那么

    摘要:列入全国计算机二级取代,部分城市试点,引入高中。建议通过视频学习,这样不但节省时间,而且效果很好。能否回忆起那个陡峭的学习曲线问题越多,学的越快。出报告每完成一个项目,总结报告,必不可少。结构化学习,才是你我需要真正培养的能力。 编程就如同你学习开车,即使,你可以一口气,说出一辆车的全部零部件,以及内燃机进气、压缩、做功和排气过程,但你就是不去练如何开车,怎么上路。你确定,你敢开吗?你...

    Kaede 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<