尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

DOM 操作、事件处理与 jQuery 选择器

DOM 操作、事件处理与 jQuery 选择器 DOM 操作、事件处理与 jQuery 选择器本节聚焦网页交互的三个基础能力使用 DOM 查找和修改页面元素、通过事件响应用户行为以及使用 jQuery 简化选择与操作。DOM 是浏览器将 HTML 页面表示为对象树的方式jQuery 是建立在原生 JavaScript 之上的类库曾主要用于兼容旧浏览器和减少重复 DOM 操作。文中的 DOM 与 jQuery 示例都应在浏览器页面中运行而不是直接在 Node.js 环境中执行。一、DOM网页的对象模型DOMDocument Object Model文档对象模型把 HTML 文档中的标签、属性和文本组织成一棵树。JavaScript 可以借助document查询节点也可以创建、插入、删除和修改节点从而让页面随用户操作动态变化。假设页面中包含以下结构后续的查询示例会以它为基础。dividd1classcontainer div_dpidp1第一段/ppidp2第二段/ppidp3第三段/p/div二、查找 DOM 元素选择元素是 DOM 操作的第一步。旧方法按 ID、标签名或类名查询querySelector()和querySelectorAll()则支持完整的 CSS 选择器表达力更强是现代代码中更常用的选择方式。// 浏览器环境中运行constbyIddocument.getElementById(d1);constbyTagNamedocument.getElementsByTagName(p);constbyClassNamedocument.getElementsByClassName(div_d);constfirstParagraphdocument.querySelector(#d1 p);constallParagraphsdocument.querySelectorAll(#d1 p);console.log(byId);// 单个 Element未找到时为 nullconsole.log(byTagName);// HTMLCollectionconsole.log(byClassName);// HTMLCollectionconsole.log(firstParagraph);// 第一个匹配的 Element未找到时为 nullconsole.log(allParagraphs);// NodeList代码说明getElementById()和querySelector()返回单个元素getElementsByTagName()、getElementsByClassName()、querySelectorAll()返回元素集合。前两种getElementsBy...返回的是动态HTMLCollectionDOM 改变时集合可能随之变化querySelectorAll()返回的是静态NodeList。// querySelectorAll 返回的 NodeList 可以直接使用 forEach 遍历document.querySelectorAll(#d1 p).forEach((paragraph){console.log(paragraph.textContent);});三、在 DOM 树中定位元素获得一个元素后可以根据它与其他节点的关系继续查找。使用带有Element的属性可以避开文本节点和注释节点使结果更符合“查找标签”的直觉。constsecondParagraphdocument.getElementById(p2);constcontainersecondParagraph.parentElement;console.log(container.id);// d1console.log(container.children);// p1、p2、p3 组成的 HTMLCollectionconsole.log(container.firstElementChild.id);// p1console.log(container.lastElementChild.id);// p3console.log(secondParagraph.previousElementSibling.id);// p1console.log(secondParagraph.nextElementSibling.id);// p3代码说明parentElement获取父元素children获取直接子元素previousElementSibling和nextElementSibling分别获取相邻的前一个和后一个兄弟元素。若使用childNodes、previousSibling等不带Element的属性换行产生的文本节点也会包含在结果中。四、创建、插入、替换与删除节点动态页面不应依赖大量字符串拼接。更稳妥的做法是使用document.createElement()创建元素再设置内容和属性。一次性插入多个节点时可借助DocumentFragment降低反复操作 DOM 的开销。constcontainerdocument.getElementById(d1);constnewParagraphdocument.createElement(p);newParagraph.textContent这是动态创建的段落;newParagraph.classList.add(notice);container.appendChild(newParagraph);// 添加到末尾constfirstParagraphcontainer.firstElementChild;container.insertBefore(newParagraph,firstParagraph);代码说明同一个节点不能同时存在于两个位置。上例第二次调用insertBefore()时不会复制newParagraph而是把它从末尾移动到第一个子元素之前。constcontainerdocument.getElementById(d1);constoldNodedocument.getElementById(p3);constreplacementdocument.createElement(div);replacement.textContent替换后的内容;container.replaceChild(replacement,oldNode);replacement.remove();// 现代写法从父节点中移除自身代码说明replaceChild(newNode, oldNode)使用新节点替换旧节点。删除节点时推荐element.remove()旧写法parent.removeChild(child)仍然有效但需要先取得父元素。使用 DocumentFragment 批量插入constcontainerdocument.getElementById(d1);constfragmentdocument.createDocumentFragment();[苹果,香蕉,橙子].forEach((name){constitemdocument.createElement(li);item.textContentname;fragment.appendChild(item);});constlistdocument.createElement(ul);list.appendChild(fragment);container.appendChild(list);代码说明文档片段本身不会显示在页面上当它被插入真实 DOM 时其中的所有子节点会一次性移动到目标位置。五、元素属性、类名与文本内容HTML 属性可通过getAttribute()、setAttribute()和removeAttribute()操作。对于常见标准属性也可直接使用对应的 DOM 属性例如image.src、input.value。样式类应优先通过classList操作而不是手动拆分class字符串。constimagedocument.createElement(img);image.setAttribute(src,./cover.png);image.setAttribute(alt,课程封面);console.log(image.getAttribute(src));image.removeAttribute(src);constcontainerdocument.getElementById(d1);container.classList.add(active);container.classList.remove(hidden);container.classList.toggle(selected);// 有则删除无则添加console.log(container.classList.contains(active));// true代码说明classList是专门管理 CSS 类名的接口能避免split( )、字符串拼接带来的重复类名或空格问题。innerText、textContent 与 innerHTML这三个属性都能读写内容但含义不同。textContent处理文本节点性能和行为更可预测innerText更接近用户在页面上看到的文本会受到 CSS 布局和隐藏元素影响innerHTML读写的是 HTML 字符串。constcontainerdocument.getElementById(d1);console.log(container.textContent);// 所有文本内容console.log(container.innerText);// 可见文本受样式影响console.log(container.innerHTML);// 内部标签结构和文本container.textContent只写入普通文本;// container.innerHTML strong加粗文本/strong; // 仅可信内容可使用代码说明将用户输入直接赋给innerHTML可能造成 XSS跨站脚本漏洞。展示不可信内容时应使用textContent。六、读取表单数据表单元素的当前输入值通常通过.value读取。复选框要结合.checked判断是否选中文件输入框通过.files获得File对象。前端校验能改善体验但重要规则必须由后端再次校验。inputidusernametypetextvaluedreamlabelinputclasshobbytypecheckboxvaluemusic音乐/labellabelinputclasshobbytypecheckboxvaluereading阅读/labelinputidfiletypefileconstusernamedocument.getElementById(username).value;console.log(username);// dreamconstselectedHobbies[...document.querySelectorAll(.hobby:checked)].map((checkbox)checkbox.value);console.log(selectedHobbies);constfileInputdocument.getElementById(file);fileInput.addEventListener(change,(){constfilefileInput.files[0];if(file){console.log(file.name,file.size,file.type);}});代码说明.value对应的是输入框当前值不一定等于 HTML 中最初写在value属性里的默认值。文件仅在用户选择后才会出现在files中且浏览器不会允许网页随意读取用户本地文件路径。七、事件与事件监听事件表示用户操作或浏览器状态变化例如点击、输入、聚焦、提交和页面加载。通过addEventListener()注册监听器可以让结构HTML、样式CSS与行为JavaScript分离是推荐方式。常见事件包括分类常用事件用途鼠标与指针click、mouseenter、mouseleave响应点击、进入和离开元素键盘keydown、keyup响应按键输入表单input、change、submit、focus、blur输入校验与提交处理文档与窗口DOMContentLoaded、load、resize页面或窗口状态变化inputidusernametypetextplaceholder请输入用户名constusernameInputdocument.getElementById(username);usernameInput.addEventListener(focus,(){usernameInput.classList.add(is-focused);});usernameInput.addEventListener(blur,(){usernameInput.classList.remove(is-focused);});usernameInput.addEventListener(input,(event){console.log(event.target.value);});代码说明事件回调中的event.target是实际触发事件的元素。相比将onfocus...直接写在 HTML 中addEventListener()可以为同一事件添加多个处理函数也更利于维护。阻止表单默认提交浏览器默认会在提交表单时重新加载或跳转页面。若要先在前端验证数据或用异步请求提交需要调用event.preventDefault()。formidlogin-forminputidlogin-namerequiredbuttontypesubmit提交/button/formdocument.getElementById(login-form).addEventListener(submit,(event){event.preventDefault();constnamedocument.getElementById(login-name).value.trim();if(!name){console.log(用户名不能为空);return;}console.log(可在这里发送请求,name);});八、练习常见交互的实现思路“开关灯”、输入框样式切换和二级菜单本质上都是监听事件后修改元素的 class。将视觉状态交给 CSSJavaScript 只管理状态会比直接反复写行内style更清晰。buttonidlight-switchtypebutton开关灯/buttondividlightclasslight is-off/div.light{width:48px;height:48px;border-radius:50%;}.light.is-off{background:#d33;}.light.is-on{background:#2a5;}constswitchButtondocument.getElementById(light-switch);constlightdocument.getElementById(light);switchButton.addEventListener(click,(){constturnedOnlight.classList.toggle(is-on);light.classList.toggle(is-off,!turnedOn);switchButton.textContentturnedOn?关灯:开灯;});代码说明classList.toggle(className, force)的第二个参数可明确控制类名是否存在。该示例用is-on和is-off表示两种互斥状态由 CSS 完成颜色变化。九、jQuery 简介与加载方式jQuery 是封装了 DOM 操作、事件、动画和 Ajax 的 JavaScript 类库其口号是 “Write less, do more”。在需要兼容旧项目或维护已有 jQuery 代码时它仍然很常见新项目通常优先采用原生 DOM API或使用 React、Vue 等框架管理复杂界面。要使用 jQuery需要先加载库文件且加载顺序必须在依赖$()的自定义脚本之前。!-- 使用完整版本必须在自己的脚本之前引入 --scriptsrchttps://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js/scriptscriptsrc./app.js/script代码说明CDN 加载方便但依赖网络将 jQuery 文件下载到项目中再用本地路径引入可减少外部网络的不确定性。slim版本不包含 Ajax 和 effects 模块使用前需确认项目需求。十、jQuery 选择器与筛选器jQuery 使用$()作为入口选择器大多遵循 CSS 语法。返回的是 jQuery 对象而不是原生 DOM 元素它可操作一组匹配元素也可用[0]或.get(0)取出其中的原生元素。// 以下示例需要先加载 jQueryconstbyId$(#d1);constbyClass$(.div_d);constbyTag$(div);console.log(byId.length);console.log(byId[0]);// 原生 DOM 元素console.log(byId.get(0));// 原生 DOM 元素属性与组合选择器// 选择具有指定属性或属性值的元素$([name]);$(input[nameusername]);$(img[src*image]);// src 包含 image$(a[href^https://]);// href 以 https:// 开头$(img[src$.jpg]);// src 以 .jpg 结尾// 多个选择器与结构选择器$(#d1, .p_d);// 并集$(#d1 p);// d1 内的所有后代 p$(#d1 p);// d1 的直接子元素 p$(#d1 p);// 紧邻 d1 的下一个 p$(#d1 ~ p);// d1 后面的所有同级 p代码说明jQuery 选择器与 CSS 选择器高度一致。若是只查询元素原生document.querySelectorAll()已能完成绝大多数任务jQuery 的价值更多体现在旧项目中统一的链式操作和兼容层。常用集合筛选jQuery 提供:first、:last、:even、:odd等筛选器。索引从0开始因此:even选中第 1、3、5 个匹配项:odd选中第 2、4、6 个匹配项。constitems$(#ul_li li);console.log(items.first());// 第一个匹配项console.log(items.last());// 最后一个匹配项console.log(items.eq(1));// 索引为 1 的第二项console.log(items.filter(:even));// 索引为 0、2、4 的项console.log(items.filter(:odd));// 索引为 1、3、5 的项console.log(items.filter(:gt(1)));// 索引大于 1 的项代码说明在新代码中优先使用标准 CSS 选择器、.filter()或原生数组方法。部分 jQuery 专用伪选择器不属于标准 CSS不能直接传给querySelectorAll()。
返回列表