第 2 章 · jQuery DOM 操作与链式编程
本章目标:掌握 html / text / val / attr / css / addClass 等读写 API;熟练使用 append / prepend / after / before / remove / empty 操作节点;理解 链式调用原理;建立 jQuery 与 原生 DOM API 对照表;在 admin-demo 商品列表区动态渲染表格行。
学时建议:4~5 小时(含 1.5 小时跟练)
前置:jquery-layui ch01;frontend-web ch04(DOM 基础)。
2.1 内容与属性读写
2.1.1 html()、text()、val()
// 读取
var html = $('#content').html(); // 含子标签 HTML 字符串
var text = $('#page-title').text(); // 纯文本,自动转义
var name = $('input[name="keyword"]').val(); // 表单值
// 写入
$('#content').html('<p class="tip">加载中…</p>');
$('#page-title').text('商品管理'); // 防 XSS,用户输入用 text
$('input[name="keyword"]').val('示例商品');
| 方法 | 对象 | 写入时转义 | 典型场景 |
|---|---|---|---|
.html() | 元素内部 HTML | 否(慎用用户输入) | 渲染模板片段 |
.text() | 文本节点 | 是 | 标题、统计数字 |
.val() | input/select/textarea | — | 搜索框、下拉框 |
2.1.2 attr() 与 data()
$('img.product-thumb').attr('src', '/static/img/placeholder.png');
$('img.product-thumb').attr('alt', '商品主图');
// HTML5 data-* 推荐用 .data()(会尝试类型转换)
$('li[data-page]').data('page'); // 读取 data-page
$(li).data('page', 'products'); // 写入内存,不改 DOM 属性
// 需要持久到 DOM 时
$(li).attr('data-page', 'products');
| 方法 | 持久化 | 类型 |
|---|---|---|
.attr('data-x') | 改 DOM 属性 | 字符串 |
.data('x') | 内存缓存为主 | 可自动转 number/boolean |
2.2 样式与类名
$('#content .stat-card')
.css('background', '#fff')
.css({ borderRadius: '8px', padding: '16px' });
$('.sidebar__menu li.is-active')
.addClass('is-active')
.removeClass('is-disabled')
.toggleClass('is-collapsed');
// 判断
if ($('#export-btn').hasClass('is-loading')) { /* ... */ }
行业常见约定:状态类名用 is-* 前缀(is-active、is-loading、is-disabled),与 Element Plus 习惯对齐,便于日后迁移。
.btn-primary.is-loading { opacity: 0.6; pointer-events: none; }
.stat-card.is-highlight { border-left: 4px solid #e91e8c; }
2.3 节点增删与位置
var $row = $('<tr><td>SKU-001</td><td>示例礼盒</td><td>¥128</td></tr>');
$('#product-tbody').append($row); // 末尾插入
$('#product-tbody').prepend($row.clone()); // 开头插入
$('.toolbar').after('<div class="filter-bar"></div>'); // 后兄弟
$('.toolbar').before('<nav class="breadcrumb"></nav>'); // 前兄弟
$('#product-tbody tr.is-empty').remove(); // 删除匹配节点
$('#product-tbody').empty(); // 清空子节点,保留 tbody
| 方法 | 作用 | 注意 |
|---|---|---|
append | 成为最后一个子节点 | 可传 HTML 字符串或 jQuery 对象 |
prepend | 成为第一个子节点 | 同上 |
after / before | 兄弟节点 | 不在父元素内部 |
remove | 移除自身 | 含事件与数据 |
detach | 移除但保留数据 | 临时隐藏可复用 |
empty | 清空子节点 | 保留容器 |
2.4 链式调用原理
jQuery 大部分 DOM 方法返回 jQuery 对象本身(或新的 jQuery 集合),从而连续打点调用。
$('#page-title')
.text('商品管理')
.addClass('fade-in')
.css('color', '#e91e8c')
.attr('data-updated', Date.now());
链式原理(简化)
$('div').addClass('a')
↓ 返回 $('div') 集合
.text('hi')
↓ 仍返回同一集合
.on('click', fn) // 部分方法返回新集合,如 .end() 回退
中断链的场景:
var title = $('#page-title').text(); // 返回字符串,不能再链式
var len = $('.sidebar__menu li').length; // 返回数字
// .end() 回到上一层选择
$('.content')
.find('.stat-card')
.addClass('active')
.end()
.find('.tip')
.hide();
| 返回 jQuery 对象 | 返回非 jQuery(链断裂) |
|---|---|
.addClass、.css、.append | .text() 无参、.html() 无参 |
.on、.show | .length、.index() |
.filter、.find | .get(0) 取 DOM |
2.5 与原生 DOM API 对照表
| 需求 | jQuery | 原生 DOM |
|---|---|---|
| 查询单个 | $('#id') | document.getElementById('id') |
| 查询多个 | $('.item') | document.querySelectorAll('.item') |
| 设置 HTML | .html(str) | .innerHTML = str |
| 设置文本 | .text(str) | .textContent = str |
| 取值 | .val() | .value |
| 属性 | .attr('src', url) | .setAttribute('src', url) |
| 样式 | .css('color', 'red') | .style.color = 'red' |
| 类名 | .addClass('on') | .classList.add('on') |
| 追加子节点 | .append(el) | .appendChild(el) |
| 删除 | .remove() | .remove() |
| 事件 | .on('click', fn) | .addEventListener('click', fn) |
何时用原生:性能热点、无 jQuery 的微页面、Web Component 内部。admin-demo 教学统一 jQuery,与 Layui 章节衔接。
2.6 admin-demo:动态商品表格
2.6.1 HTML 骨架
在 #content 内加入:
<div class="product-panel">
<div class="toolbar">
<input type="text" name="keyword" placeholder="搜索商品名称" class="input">
<button type="button" id="btn-search" class="btn btn-primary">搜索</button>
<button type="button" id="btn-add-row" class="btn">添加演示行</button>
</div>
<table class="data-table">
<thead>
<tr>
<th>SKU</th>
<th>商品名称</th>
<th>价格</th>
<th>操作</th>
</tr>
</thead>
<tbody id="product-tbody"></tbody>
</table>
</div>