jQuery 练习题(10 题)

这一页给 10 道 jQuery 练习题,覆盖引入与 ready、选择器、事件、文本/HTML、CSS 类、DOM 增删改、动画、AJAX、遍历、实战这些最核心的知识点。每题都有题目描述、提示、可折叠的参考答案。

使用建议:先自己动手写,卡住了再看提示,实在写不出再对照答案。jQuery 虽然 React/Vue 时代用得少了,但它是「操作 DOM」的最直白范式,理解了它,前端的基础概念就稳了。

基础(5 题):引入 / 选择器 / 事件 / 文本 / CSS

第 1 题:引入 jQuery 与 $(document).ready

题目:用 CDN 方式引入 jQuery 3.x,写一段在 DOM 就绪后执行的代码,打印 jQuery 版本号,并把某个元素文本改成 hello jQuery。同时给出 $(document).ready(fn) 的简写形式。

提示:$.fn.jquery 可读版本;ready 比 window.onload 早触发(后者要等图片等资源);简写直接 $(fn)。脚本最好放 body 结束前,或用 defer。

参考答案
<!-- 通过 CDN 引入 jQuery(放 body 结束前,不阻塞首屏) -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
  // 等待 DOM 树构建完再执行,避免脚本拿不到元素
  $(document).ready(function () {
    console.log('DOM 就绪');
    console.log('jQuery 版本:', $.fn.jquery);
  });

  // 简写形式(推荐):等价于 $(document).ready(...)
  $(function () {
    $('#title').text('hello jQuery');
  });
</script>
<!-- 知识点:
  - ready 触发时机:DOM 解析完即可,不等待图片/CSS/iframe
  - window.onload 是等所有资源加载完,晚得多
  - 现代写法:$(fn) 或 $(() => { ... }) -->

第 2 题:选择器

题目:用 jQuery 选择器实现以下需求:(a) 选中 id 为 logo 的元素;(b) 选中所有 class 含 item 的元素;(c) 选中 ul.nav 下所有 li(任意层级)和直接子 li;(d) 同时选 h2 和 h3;(e) 选第一个和索引为 2 的 li;(f) 选当前可见的元素和被勾选的复选框。

提示:基础选择器 $('#id')、$('.cls')、$('tag');后代空格、子代 >、多选逗号;过滤伪类 :first、:eq(n)、:odd、:visible、:checked。坑:选择器永远返回 jQuery 对象,即使没匹配也不会是 null——要用 .length 判断。

参考答案
$(function () {
  // 基础选择器(返回的是 jQuery 对象,不是原生 DOM)
  $('#logo')           // id 选择器:页面里唯一
  $('.item')           // class 选择器:可多个
  $('div')             // 标签选择器
  $('*')               // 全选(慎用,慢)

  // 组合
  $('ul.nav li')       // 后代:nav 下的所有 li(任意层级)
  $('ul.nav > li')     // 子代:仅直接子元素
  $('h2, h3')          // 多选:逗号分隔

  // 位置与可见性过滤
  $('li:first')        // 第一个
  $('li:eq(2)')        // 索引为 2 的(第 3 个,从 0 计)
  $('li:odd')          // 索引为奇数(注意是从 0 计,视觉上是偶数行)
  $('li:visible')      // 当前可见的
  $('input:checked')   // 选中的复选框/单选
});

第 3 题:事件处理

题目:写一个按钮点击事件,在回调里拿到事件对象和触发元素;再用 .hover() 实现鼠标进入加类、离开移除类;再用事件委托给一个 ul 里的 li 绑点击(li 是动态生成的);最后实现「只触发一次」的点击。

提示:.on('click', fn) 是推荐写法;this 在回调里是原生 DOM,要包 $(this) 才能用 jQuery 方法;事件委托用 .on(event, selector, fn) 三参形式,父元素监听子元素冒泡上来的事件——这是处理动态元素的标准做法。

参考答案
$(function () {
  // 基本点击
  $('#btn').on('click', function (e) {
    console.log('点了', this);     // this 是触发事件的原生 DOM
    console.log('事件对象', e.type);
  });

  // hover 实际是 mouseenter + mouseleave 的语法糖
  $('#box').hover(
    function () { $(this).addClass('hot'); },   // 进入
    function () { $(this).removeClass('hot'); } // 离开
  );

  // 事件委托:子元素是动态生成的,父元素上委托
  $('#list').on('click', 'li', function (e) {
    console.log('点到的是 li,内容:', $(this).text());
  });

  // 只触发一次
  $('#once').one('click', function () {
    alert('只触发这一次');
  });

  // 取消绑定
  // $('#btn').off('click');
});

第 4 题:操作文本与 HTML

题目:分别读取和设置某元素的纯文本、HTML 内容、表单值。再用「传函数」的方式,把某个数字元素的文本自增 1。

提示:.text() 纯文本(标签会被转义),.html() 含 HTML(会解析),.val() 表单值;三者都支持「传函数」形式 fn(i, oldValue)。安全警告:用户输入直接 .html() 会触发 XSS——必须先转义或用 .text()。

参考答案
$(function () {
  // 读取
  $('#title').text();              // 纯文本(不含 HTML 标签)
  $('#box').html();                // 含 HTML 标签
  $('#name').val();                // 表单值(input/textarea/select)

  // 写入
  $('#title').text('新标题');       // 转义 HTML,原样显示
  $('#box').html('<strong>加粗</strong>');  // 当作 HTML 解析
  $('#name').val('张三');

  // 传函数:基于旧值计算新值(对应元素的索引、旧值)
  $('#count').text(function (i, old) {
    return Number(old) + 1;          // 自增
  });

  // 注意:.text() 读到的标签会被转义显示,
  // .html() 才会按 HTML 渲染。安全警告:用户输入直接 .html() 会 XSS。
});

第 5 题:操作 CSS 类与样式

题目:给元素加、删、切换 active 类,判断是否含此类;再用对象形式一次性设置 color/background/font-size 三条样式;最后读取元素的计算后 font-size。

提示:.addClass/.removeClass/.toggleClass/.hasClass 四件套;多条样式用 .css({ key: val, ... }),带连字符的 key 要加引号;原则:批量改样式优先用 class(性能好、易维护),.css 用于动态值。

参考答案
$(function () {
  // 类操作(批量改样式优先用 class,而不是逐条 .css)
  $('#box').addClass('active');          // 添加
  $('#box').removeClass('active');       // 移除
  $('#box').toggleClass('active');       // 切换
  $('#box').hasClass('active');          // 判断:返回 boolean

  // 多类空格分隔
  $('#box').addClass('a b c');

  // 行内样式
  $('#box').css('color', 'red');         // 单个
  $('#box').css({                        // 多个(对象)
    color: '#fff',
    background: '#000',
    'font-size': '14px'
  });
  $('#box').css('font-size');            // 读取计算后的样式值
});

进阶(5 题):DOM / 动画 / AJAX / 遍历 / 实战

第 6 题:DOM 增删改

题目:创建一个新的 <li> 追加到列表末尾;把一个 <hr> 插到某元素后面;读取并设置图片的 src/alt;移除一个属性;最后清空一个元素的所有子节点但保留自身。

提示:$('HTML 字符串') 创建元素;.appendTo/.prepend/.after/.before 四个插入位置;.attr 操作任意属性,.prop 操作布尔属性(checked/disabled 等,读实时状态而非 HTML 初始值);.remove() 连自身删,.empty() 只删后代。

参考答案
$(function () {
  // 增
  $('<li>新项</li>').appendTo('#list');   // 创建后追加到末尾
  $('#list').prepend('<li>置顶</li>');     // 插到开头
  $('#list').after('<hr>');                // 作为兄弟插到自己后面
  $('#list').before('<h3>标题</h3>');      // 作为兄弟插到自己前面

  // 改属性
  $('#pic').attr('src', 'cat.jpg');        // 设置
  $('#pic').attr('alt');                   // 读取
  $('#pic').removeAttr('alt');             // 删除属性

  // prop vs attr:布尔属性(checked/disabled)用 prop
  $('#cb').prop('checked', true);
  $('#cb').prop('checked');                // true(读实时状态)
  $('#cb').attr('checked');                // 'checked'(读初始 HTML)

  // 删
  $('#item').remove();       // 连自身一起从 DOM 删掉
  $('#list').empty();        // 只清空后代,保留自身
});

第 7 题:显示隐藏动画

题目:实现四个按钮:(a) 显隐切换;(b) 淡出后再淡入;(c) 滑动展开/收起;(d) 用 .animate() 把宽度增加 50px 同时透明度变 0.5。每段动画都要带回调。

提示:.show/.hide/.toggle 同时动宽高+透明度;.fadeIn/.fadeOut/.fadeToggle 只动透明度;.slideDown/.slideUp/.slideToggle 只动高度;动画时长第一个参数(毫秒或 'slow'/'fast'),第二个是回调。注意:jQuery 内置不支持颜色动画,需要 jQuery UI 或插件。

参考答案
$(function () {
  $('#btnShow').on('click', function () {
    $('#box').show();                // 立即显示
    $('#box').show(400);             // 400ms 过渡(宽高+透明度)
  });

  $('#btnHide').on('click', function () {
    $('#box').hide(400);
  });

  $('#btnToggle').on('click', function () {
    $('#box').toggle(400);           // 切换显隐
  });

  // 淡入淡出(只动透明度)
  $('#fadeBtn').on('click', function () {
    $('#box').fadeOut(300, function () {
      // 动画完成的回调,this 是 DOM
      $(this).fadeIn(300);
    });
  });

  // 滑动(只动高度)
  $('#slideBtn').on('click', function () {
    $('#box').slideToggle(300);
  });

  // 自定义动画(注意:颜色动画要插件)
  $('#box').animate({ width: '+=50', opacity: 0.5 }, 400);
});

第 8 题:AJAX 请求

题目:分别用 (a) $.get 带 page 参数请求 JSON;(b) $.post 提交登录表单;(c) $.ajax 做 PUT 请求,用 .done/.fail/.always 处理三种结果,并设置 5 秒超时。

提示:简写 $.get/post(url, data, successCb, dataType);$.ajax 最全;dataType: 'json' 让 jQuery 自动解析;跨域需后端配 CORS。坑:旧版的 .success/.error 已废弃,务必用 .done/.fail 或 Promise 风格。

参考答案
$(function () {
  // 简写:GET
  $.get('/api/users', { page: 1 }, function (data) {
    console.log('用户列表', data);
  }, 'json');

  // 简写:POST
  $.post('/api/login', { user: 'a', pwd: 'b' }, function (resp) {
    console.log('登录结果', resp);
  }, 'json');

  // 通用 $.ajax(功能最全,支持 Promise)
  $.ajax({
    url: '/api/user/12',
    method: 'PUT',
    data: { name: '张三', age: 28 },
    dataType: 'json',
    timeout: 5000
  })
    .done(function (data) { console.log('成功', data); })
    .fail(function (xhr, status, err) { console.log('失败', err); })
    .always(function () { console.log('不管成败都执行'); });
});
<!-- 知识点:
  - dataType 让 jQuery 自动解析响应(json/html/text)
  - 跨域需后端配 CORS,或服务端用 JSONP(jq 已支持)
  - jq 3+ 推荐 .done/.fail,旧版 .success 已废弃 -->

第 9 题:遍历

题目:遍历所有 li 打印索引和文本;从一个元素出发,分别用 .find/.children/.parent/.parents/.closest/.siblings/.next/.prev;最后写一条链式调用,给第一个 li 加 hl 类并给它的所有兄弟移除 hl。

提示:.each(fn) 里 this 是原生 DOM;.find 找后代,.children 只找直接子;.parents 向上找所有祖先,.closest 向上找第一个匹配(最常用);.filter/.not/.eq 在当前集合里筛选。链式调用能工作的原因:每步都返回新的 jQuery 对象。

参考答案
$(function () {
  // 遍历集合(this 是原生 DOM)
  $('li').each(function (i, el) {
    console.log(i, $(this).text());
  });

  // 查子代 / 后代
  $('#box').find('.tag');           // 所有匹配 .tag 的后代
  $('#box').children();             // 仅直接子元素
  $('#box').children('.item');      // 直接子元素里再过滤

  // 找父级 / 兄弟
  $('li').parent();                 // 直接父
  $('li').parents('.list');         // 向上找所有祖先中匹配 .list 的
  $('li').closest('.item');         // 向上最近的匹配(常用)
  $('li').siblings();               // 兄弟(不含自己)
  $('li').next();                   // 下一个兄弟
  $('li').prev();                   // 上一个
  $('li').nextAll();                // 后面所有兄弟

  // 链式调用:每步都返回 jQuery 对象
  $('li').first().addClass('hl').siblings().removeClass('hl');

  // 过滤
  $('li').filter('.active');        // 保留匹配的
  $('li').not('.active');           // 排除匹配的
  $('li').eq(2);                    // 取索引 2 的
});

第 10 题:实战:待办清单

题目:实现一个完整的 todo list:输入框 + 添加按钮(回车也能添加);点击「完成」按钮给该项加删除线样式(再次点击取消);点击「删」按钮先淡出再移除。要求用事件委托处理动态生成的 li。

提示:这是 jQuery 最经典的应用场景。关键点:(1) 用字符串拼接构造 <li> 后 .append;(2) $('#list').on('click', '.done', fn) 三参形式做事件委托;(3) $(this).closest('.todo') 从按钮向上找到 li;(4) .fadeOut(cb) 在回调里 .remove(),注意回调里 this 已变,要在外层缓存 $li。

参考答案
<!-- HTML -->
<input id="todo-input" placeholder="输入任务,回车添加">
<button id="add-btn">添加</button>
<ul id="todo-list"></ul>

<style>
  .completed .text { text-decoration: line-through; color: #aaa; }
</style>

<script>
$(function () {
  // 添加(支持点击和回车两种方式)
  function addTodo() {
    var txt = $('#todo-input').val().trim();
    if (!txt) return;
    // 动态拼接 li,带"完成"和"删"按钮
    var $li = $(
      '<li class="todo">' +
      '  <span class="text">' + txt + '</span>' +
      '  <button class="done">完成</button>' +
      '  <button class="del">删</button>' +
      '</li>'
    );
    $('#todo-list').append($li);
    $('#todo-input').val('').focus();
  }
  $('#add-btn').on('click', addTodo);
  $('#todo-input').on('keydown', function (e) {
    if (e.key === 'Enter') addTodo();
  });

  // 完成切换:用事件委托,因为 li 是动态生成的
  $('#todo-list').on('click', '.done', function () {
    $(this).closest('.todo').toggleClass('completed');
  });

  // 删除:淡出后再 remove
  $('#todo-list').on('click', '.del', function () {
    var $li = $(this).closest('.todo');
    $li.fadeOut(200, function () { $li.remove(); });
  });
});
</script>
<!-- 知识点:
  - 动态生成的元素,直接 $('#todo-list .done').on(...) 绑不上
  - 用事件委托:父元素监听,第二个参数过滤目标
  - closest(selector) 是从触发点向上找最近的祖先匹配,极常用 -->

练习建议

jQuery 的核心就一句话:「选元素,然后做事」。掌握选择器(基础+过滤)、事件(尤其事件委托)、DOM 操作(增删改)、链式调用,90% 的需求都能搞定。动画和 AJAX 是锦上添花。

做完这 10 题,试着把第 10 题扩展一下:加「编辑」按钮(双击 li 进入编辑态)、用 localStorage 持久化、加「全选/反选」——把这些组合起来,就是一个完整的前端小项目了。

← 上一篇 jQuery 插件

返回 jQuery 教程目录

✈️💬