Vanilla JavaScript中基本的DOM操作(二)

本文介绍JavaScript中的事件绑定、监听及动画实现方法。探讨了事件侦听器的不同绑定方式及其优缺点,介绍了事件委托技巧和使用requestAnimationFrame进行平滑动画的技术。
第三节:事件侦听

这可能是绑定事件侦听器最有名的方法:

myElement.onclick = function onclick(event) {
    console.log(event.type + ' got fired');
};

但通常应该避免这样做。这里, .onclick 是该元素的一个属性,意味着你可以改变它,但是你不能使用它来添加额外的侦听器 — 通过指定一个新的函数,你将覆盖旧的引用。

相反,我们可以使用更强大的 .addEventListener() 方法来添加尽可能多的类型的事件。它有三个参数:事件类型(比如 click),一个无论何时元素上的事件发生会被调用的函数,一个可选的配置对象,它将会被进一步解释。

myElement.addEventListener('click', function (event) {
  console.log(event.type + ' got fired')
})

myElement.addEventListener('click', function (event) {
  console.log(event.type + ' got fired again')
})

在监听函数内,event.target引用事件触发的元素(就像 this,除非我们使用箭头函数)。因此,你可以轻松地访问它的属性,如下所示:

// document 的`forms`属性是一个数组
// 引用所有的form
const myForm = document.form[0];
const myInputElements = myForm.querySelectorAll('input');
Array.form(myInputElements).forEach(el => {
    el.addEventListener('change', function(event) {
        console.log(event.target.value);
    });
});
阻止默认行为

请注意,事件在监听函数中始终可用,但在需要时将其明确地传递给它是很好的选择(当然,我们可以按照我们的喜好命名它)。没有详细说明事件接口本身,一个特别值得注意的方法是 .preventDefault() ,它将阻止浏览器的默认行为,例如 链接。另一个常见的用例是在客户端表单验证失败时有条件地阻止提交表单。

myForm.addEventListener('submit', function(event) {
  const name = this.querySelector('#name')

  if (name.value === 'Donald Duck') {
    alert('You gotta be kidding!')
    event.preventDefault()
  }
})

另一个重要的事件方法是 .stopPropagation() ,它将防止事件冒泡DOM。这意味着如果我们有一个停止传播的 click 监听器,(比如说)在一个元素上,而另一个 click 监听器在它的父元素上,那么在子元素上触发的点击事件不会在父级上触发 - 否则,它会在两者上触发。

现在,.addEventListener() 将可选配置对象作为第三个参数,它可以具有以下任何布尔属性(所有这些属性都默认为 false):

  • capture(捕获):事件将在DOM中的任何其他元素之前被触发(事件捕获和冒泡本身就是一篇文章,更多细节请看这里);

  • once(一次):正如你可能猜到的那样,这表示该事件只会触发一次;

  • passive(被动):这意味着 event.preventDefault() 将被忽略(并且通常在控制台中产生警告);

最常见的选择是 .capture;实际上,这是很常见的,有一个简写:不需要在配置对象中指定它,你可以在这里传递一个布尔值:

myElement.addEventListener(type, listener, true)

事件监听器可以使用 .removeEventListener() 来移除,它将事件类型和对回调函数的引用移除;例如,once 选项也可以实现。

myElement.addEventListener('change', function listener(event) {
  console.log(event.type + ' got triggered on ' + this)
  this.removeEventListener('change', listener)
})
事件委托

另一个有用的模式是事件委托(事件代理):假设我们有一个表单并且想要为其所有输入子项添加一个更改事件监听器。一种方法是使用 myForm.querySelectorAll('input') 来迭代它们,如上所示。但是,当我们可以将它添加到表单本身并检查 event.target 的内容时,这是不必要的。

myForm.addEventListener('change', function(event) {
  const target = event.target
  if (target.matches('input')) {
    console.log(target.value)
  }
})

这种模式的另一个优点是它也自动地为动态插入的子项计算帐户,而不必为每个子项绑定新的监听者。


第四节:动画

通常,执行动画的最简洁的方法是将CSS类与 transition 属性一起应用,或者使用CSS @keyframes 。但是如果你需要更多的灵活性(例如对于一款游戏),那么也可以使用JavaScript来完成。

幼稚的做法是让一个 window.setTimeout() 函数调用自己,直到完成所需的动画。

幼稚的做法是让一个 window.setTimeout() 函数调用自己,直到完成所需的动画。但是,这无效地迫使文件快速回流;而这种布局变换可能会迅速导致卡顿,尤其是在移动设备上。 相反,我们可以使用 window.requestAnimationFrame() 同步更新来安排当前对下一个浏览器重绘帧的更改。它将回调作为接收当前(高分辨率)时间戳的参数:

const start = window.performance.now();
const duration = 2000;

window.requestAnimationFrame(function fadeIn(now)) {
  const progress = now - start;
  myElement.style.opacity = progress / duration;

  if (progress < duration) {
    window.requestAnimationFrame(fadeIn);
  }
}

这样我们可以实现非常流畅的动画。有关更详细的讨论,请查看Mark Brown撰写的这篇文章

编写你自己的帮手方法

诚然,与jQuery的简洁和可链接的 $('.foo').css({color:'red'}) 语法相比,总是需要遍历元素来处理元素可能相当麻烦。那么,为什么不简单地写我们自己的速记方法呢?

const $ = function $ (selector, context = document) {
const elements = Array.from(context.querySelectorAll(selector))
  return {
    elements,

    html (newHtml) {
      this.elements.forEach(element => {
        element.innerHTML = newHtml
      })
      return this
    },

    css (newCss) {
      this.elements.forEach(element => {
        Object.assign(element.style, newCss)
      })
      return this
    },

    on (event, handler, options) {
      this.elements.forEach(element => {
        element.addEventListener(event, handler, options)
      })
      return this
    }
    // etc.
  }
}

因此,我们有一个超薄的DOM库,只有我们真正需要的方法,并且没有所有的向后兼容性权重。通常我们会在我们的集合的原型中使用这些方法。这里有一些(更精细)的要点,提供一些如何实现这些帮助者的想法。或者,我们可以保持它像

const $ = (selector, context = document) => context.querySelector(selector)
const $$ = (selector, context = document) => context.querySelectorAll(selector)

const html = (nodeList, newHtml) => {
  Array.from(nodeList).forEach(element => {
    element.innerHTML = newHtml
  })
}

// And so on...
Demo

为了关闭这篇文章,下面是一个CodePen,它演示了许多上面解释的概念来实现一个简单的灯箱技术。我鼓励你花一些时间浏览源代码,如果你有任何意见或问题,请在下面的评论中告诉我。

demo地址

结论

我希望我可以证明用普通的JavaScript进行DOM操作不是火箭科学,实际上,许多jQuery方法在本地DOM API中有直接的等价物。这意味着对于一些日常使用情况(例如导航菜单或模式弹出窗口),DOM库的额外开销可能不合适。

虽然本地API的某些部分确实是冗长或不方便的(例如必须始终手动迭代节点列表),但我们可以很轻松地编写自己的小帮助函数来抽象出这些重复的任务。

但现在它已经结束了。你怎么看?你是否愿意尽可能地避免使用第三方库,或者自己动手干脆不值得认知开销?请在下面的评论中告诉我。

本文由Vildan Softic和Joan Yin同行评审。感谢SitePoint的所有同行评论员,让SitePoint的内容达到最佳状态!

返回第一部分


  • 参考资料

原文地址

先展示下效果 https://pan.quark.cn/s/e81b877737c1 Node.js 是一种基于 Chrome V8 引擎的 JavaScript 执行环境,它使开发者能够在服务器端执行 JavaScript 编程,显著促进了全栈开发的应用普及。 在 Node.js 的开发流程中,`node_modules` 文件夹用于存储所有依赖的模块,随着项目的进展,该文件夹可能会变得异常庞大,其中包含了众多可能已不再需要的文件和文件夹,这不仅会消耗大量的硬盘空间,还可能减慢项目的加载时间。 `ModClean 2.0` 正是为了应对这一挑战而设计的工具。 `ModClean` 是一款用于清理 `node_modules` 的软件,其核心功能是移除那些不再被使用的文件和文件夹,从而确保项目的整洁性和运行效率。 `ModClean 2.0` 是此工具的改进版本,在原有功能上增加了更多特性,从而提高了清理工作的效率和精确度。 在 `ModClean 2.0` 中,用户可以设置清理规则,例如排除特定的模块或文件类型,以防止误删重要文件。 该工具通常会保留项目所依赖的核心模块,但会移除测试、文档、示例代码等非运行时必需的部分。 通过这种方式,`ModClean` 能够协助开发者优化项目结构,减少不必要的依赖,加快项目的构建速度。 使用 `ModClean` 的步骤大致如下:1. 需要先安装 `ModClean`,在项目的根目录中执行以下命令: ``` npm install modclean -g ```2. 创建配置文件 `.modcleanrc.json` 或 `.modcleanrc.js`,设定希望清理的规则。 比如,可能需要忽略 `LICENSE` 文件或整个 `docs`...
2026最新微信在线AI客服系统源码 微信客服AI系统是一款基于PHP开发的智能客服解决方案,完美集成企业微信客服,为企业提供7×24小时智能客服服务。系统支持文本对话、图片分析、视频分析等多种交互方式,并具备完善的对话管理、人工转接、咨询提醒等高级功能。 核心功能 ### 1.  智能AI客服 #### 自动回复 - **上下文理解**:系统自动保存用户对话历史,AI能够理解上下文,提供连贯的对话体验 - **个性化配置**:可自定义系统提示词、最大输出长度等AI参数 #### 产品知识库集成 - **公司信息**:支持配置公司简介、官网、竞争对手等信息 - **产品列表**:可添加多个产品,包括产品名称、配置、价格、适用人群、特点等 - **常见问题FAQ**:预设常见问题及答案,AI优先使用知识库内容回答 - **促销活动**:支持配置当前优惠活动,AI会自动向用户推荐 ### 2. 多媒体支持 #### 图片分析 - 支持用户发送图片,AI自动分析图片内容 - 可结合文字描述,提供更精准的分析结果 - 支持常见图片格式:JPG、PNG、GIF、WebP等 #### 视频分析 - 支持用户发送视频,AI自动分析视频内容 - 视频文件自动保存到服务器,提供公网访问 - 支持常见视频格式:MP4、等 ### 3.  人工客服转接 #### 关键词触发 - **自定义关键词**:可配置多个转人工触发关键词(如:人工、客服、转人工等) - **自动转接**:用户消息包含关键词时,自动转接给指定人工客服 - **友好提示**:转接前向用户发送提示消息,提升用户体验 #### 一键介入功能 - **后台管理**:管理员可在对话管理页面查看所有对话记录 - **快速转接**:点击"一键介入"按钮,立即将用户转接给人工客服
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值