jQuery最详细的入门教程(原理+知识清单+案例)Ⅱ

248 阅读10分钟
没有太晚的开始,不如就从今天行动。总有一天,那个一点一点可见的未来,会在你心里,也在你的脚下慢慢清透。生活,从不亏待每一个努力向上的人。

第二期主要内容

  1. 查找
  2. 修改
  3. 按节点间关系查找
  4. 添加/删除/替换/克隆
  5. 事件绑定

一. 查找: jQuery新增选择器

  1. 内容过滤选择器:

    (1). 什么是: 根据元素的内容中包含的关键词来匹配元素

    (2). 何时: 如果用其它选择器很难区分元素时,就可以尝试用元素的内容不同来选择元素

    (3). 包含: 4种:

    a. :contains(关键词) 匹配元素内容中包含指定"关键词"的元素

    b. :has(选择器) 匹配子元素中包含符合选择器要求的元素 的父元素 根据孩子特征,选爹

    c. :parent 匹配所有内容不为空的元素

    d. :empty 匹配内容为空的元素

     强调: 空元素: 连空字符内容都不能有!
    

    (4). 示例: 使用内容过滤选择器选择指定元素

    <!DOCTYPE html>
    

jQuery中的选择器——内容过滤选择器

<button>提交订单</button>
<button>Submit注册信息</button>
<button>马上提交</button>
<button>清空重填</button>

<hr />
<div class="alert" id="alert1">
  第一个警告框
</div>
<div class="alert" id="alert2">
  <span class="close">×</span>
  第一个警告框
</div>
<div class="alert" style="height:30px"></div>
运行结果:
```

  1. 可见性过滤:

    (1). 什么是: 根据元素是否可见来选择元素

    (2). 包括:

    a. :visible 专门匹配可见的元素

    b. :hidden 专门匹配不可见的元素

     坑: 只能选择display:none和type="hidden"隐藏的元素
     	无法选择visibility:hidden和opacity:0的元素
    

    (4). 示例: 使用:hidden查找隐藏的元素

    <!DOCTYPE html>
    

可见性选择器

<div id="d1" style="display: none">lorem</div>
<div id="d2" style="visibility: hidden">lorem</div>
<div id="d3" style="opacity: 0">lorem</div>
<input id="d4" type="hidden" name="aa" value="bb" />
运行结果:
```

  1. 表单元素过滤选择器:

    (1). :input 专门选择所有表单元素(input 、button、textarea 、select)

     vs  input  只是一个普通的元素选择器,只能选择input元素。不能选择其他类型的表单元素
    

    (2). 问题: input元素就有很多种类,如何精确的只选择其中一种种类的input呢?

    (3). 解决: 其实,input元素的每种type值,都对应着一个专门的选择器,比如:

    a. :text 专门选择<input type="text"

    b. :password 专门选择<input type="password"

    c. :radio 专门选择<input type="radio"

    ... ...

    (4). 示例: 点同意,启用表单元素;不同意,就禁用表单元素

<!DOCTYPE html>
<html>

<head>
  <title>.....</title>
  <meta charset="utf-8" />
  <style>
  </style>
</head>

<body>
  <form>
    用户名:<input disabled></br>
    密码:<input type="password" disabled></br>
    <input type="checkbox">我同意本站的使用条款<br>
    <input type="submit" value="提交注册信息" disabled />
  </form>
  <script src="js/jquery-1.11.3.js"></script>
  <script>
    //DOM 4步
    //1. 查找触发事件的元素
    //本例中: 用户点type=checkbox的复选框触发启用禁用状态的改变
    //应该查找type=checkbox的一个复选框
    $(":checkbox")
    //2. 绑定事件处理函数
    //本例中:单击复选框触发变化
    .click(function(){
      //3. 查找要修改的元素
      //本例中: 点了复选框要修改除当前复选框之外其余所有表单元素
      var $others=$(":input:not(:checkbox)")
      //4. 修改元素
      //获得当前checkbox的选中状态
      //错误: jQuery是函数库,不能用属性方式
      //var checked=$(this).checked;
      //           当前复选框 获取 checked属性的值
      var checked=$(this).prop("checked");
      //因为checked属性值只是一个bool值,不是jQuery家子对象
      //所以变量名不加$

      //如果checkbox是选中的
      if(checked==true){
        //其它表单元素启用
        //修改其他表单元素的disabled属性值为false
        $others.prop("disabled",false);
      }else{//否则如果checkbox是未选中的
        //其它表单元素禁用
        //修改其他表单元素的disabled属性值为true
        $others.prop("disabled",true);
      }
      //基础好的同学,必须改为1句话!
      //如果选中(checked为true),则其它元素启用(disabled为false)
      //否则如果未选中(checked为false),则其它元素禁用(disabled为true)
      //所以,只要让其他元素的disabled值和checked的值相反就行!不用三目!
    })
  </script>
</body>

</html>
运行结果: 


二. 修改: 3种东西

  1. 内容: 3种:

修改元素的内容(有扩展)

(1). 原始的HTML内容:
a. DOM中: 元素.innerHTML
b. jq中: $元素.html("新内容")
(2). 纯文本内容: 
a. DOM中: 元素.textContent
b. jq中: $元素.text("新内容")
(3). 表单元素的值:
a. DOM中: 元素.value
b. jq中: $元素.val("新值")
(4). 示例: 通过修改元素内容,实现表单验证
<!DOCTYPE html>
<html>

<head>
  <title> new document </title>
  <meta charset="utf-8">
</head>

<body>
  <h1>操作元素的内容和值</h1>
  <form action="">
    用户名:<input name="uname">
    <span></span><br>
    密码:<input type="password" name="upwd">
    <span></span><br>
    <input type="submit" value="提交注册信息">
  </form>
  <script src="js/jquery-1.11.3.js"></script>
  <script>
    //正确时,使用图片:"<img src='img/ok.png'>"
    //姓名错误时: "<img src='img/err.png'>用户名必须介于3~9位之间!"
    //密码错误时: "<img src='img/err.png'>密码必须介于6~8位之间!"
    //DOM 4步
    //1. 查找触发事件的元素
    //本例中: 当姓名文本框失去焦点时,触发验证和变化
    //应该找文本框: 
    $(":text")
    //2. 绑定事件处理函数
    //本例中: 失去焦点触发验证和变化
    .blur(function(){
      var $txt=$(this);
      //3. 查找要修改的元素
      //本例中: 不管验证通过还是未通过,都要修改文本框旁边的下一个span
      var $span=$txt.next();
      //4. 修改元素
      //获得文本框中内容去掉空字符后的长度
      var length=$txt.val().trim().length;
      //如果长度介于3~9位字符之间,就验证通过
      if(length>=3&&length<=9){
        //就设置span的内容为<img src='img/ok.png'>
        $span.html(`<img src='img/ok.png'>`)
      }else{//否则如果验证不通过
        //就设置span的内容为<img src='img/err.png'>用户名必须介于3~9位之间!
        $span.html(`<img src='img/err.png'>用户名必须介于3~9位之间!`);
      }
    });
    //自己模仿我的姓名文本框,制作密码框验证
  </script>
</body>

</html>
运行结果: 


  1. 属性: 3种:

    (1). 字符串类型的HTML标准属性:

    a. DOM中: 2种:

     1). 核心DOM 4个函数: 元素.getAttribute()  setAttribute() ...
     2). HTML DOM: 元素.属性名
    

    b. jq中: 2种:

     1). $元素.attr("属性名", "新值") 代替元素.getAttribute()  setAttribute() ...
     	attribute指 HTML中开始标签中的属性
     	一个函数两用
     2).问题: jQuery是函数库,不能用".属性名"方式访问
       解决: jQuery中封装了一个新函数.prop("属性名", "新值"),专门代替".属性名"方式来获取或修改元素的属性值
     	property 指 内存中元素对象上的属性
     	一个函数两用
    

    (2). bool类型的HTML标准属性

    a. DOM中: 元素.属性名, 不能用核心DOM getAttribute()和setAttribute()

    d. 如何: $元素.prop("属性名", bool) 代替".属性名"

    c. 因为在DOM中不能用getAttribute()和setAttribute(),所以在jq中也不能用attr()

    (3). 自定义扩展属性:

    a. DOM中: 2种:

     1). 核心DOM4个函数:  元素.getAttribute()  元素.setAttribute()
     2). HTML5: 元素.dataset.自定义属性名
    

    b. jq中: 1种: $元素.attr() 代替 元素.getAttribute() 元素.setAttribute()

    c. 强调: 因为自定义属性在DOM中就不能用".属性名"方式访问,所以jq中自然也就不能用.prop()来访问!因为prop()代替的就是".属性名"

    (4). 示例: 点击图片切换下一张

<!DOCTYPE html>
<html>

<head>
  <title> new document </title>
  <meta charset="utf-8">
</head>

<body>
  <h1>操作元素的属性</h1>
  <img src="img/1.jpg" alt="1">
  <script src="js/jquery-1.11.3.js"></script>
  <script>
    //单击图片,切换下一张
    //DOM 4步
    //1. 查找触发事件的元素
    //本例中: 用户点img触发变化
    $("img")
    //2. 绑定事件处理函数
    //本例中: 单击触发变化
    .click(function(){
      //3. 查找要修改的元素
      //本例中: 就是要修改当前img自己
      var $img=$(this);
      //4. 修改元素
      //本例中: 
      //先获取当前img中alt属性的值转为整数
      var i=parseInt($img.attr("alt"));
      //                 .prop("alt")
      if(i<4){//如果alt值<4,则alt+1
        i++;
      }else{//否则如果alt值==4,则alt=1
        i=1;
      }
      //最后将alt的值拼成新的src路径,设置到img的src属性上,同时,将alt值再放回img的alt属性中,为下次点击做准备
      //$img.attr("src",`img/${i}.jpg`);
      //  .prop()
      //$img.attr("alt",i);
      //  .prop()
      $img.attr({ src:`img/${i}.jpg`, alt:i })
      //  .prop()
    })

  </script>
</body>

</html>
运行结果: 

(5). 示例: 点击小图片,切换大图片

<!DOCTYPE html>
<html>

<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    body {
      text-align: center;
    }
  </style>
</head>

<body>

  <img src="img/1.jpg" data-target="img/1-l.jpg" class="my-small">
  <img src="img/2.jpg" data-target="img/2-l.jpg" class="my-small">
  <img src="img/3.jpg" data-target="img/3-l.jpg" class="my-small">
  <img src="img/4.jpg" data-target="img/4-l.jpg" class="my-small">
  <hr />
  <img src="img/1-l.jpg" class="my-big">

  <script src="js/jquery-1.11.3.js"></script>
  <script>
  //点击小图片,下方my-big中显示大图片
  //DOM 4步
  //1. 查找触发事件的元素
  //本例中: 用户点class为my-small的img元素触发变化
  $(".my-small")
  //2. 绑定事件处理函数
  //本例中: 单击触发变化
  .click(function(){
    //3. 查找要修改的元素
    //本例中: 要修改class为my-big的img
    $(".my-big")
    //4. 修改元素
    //本例中: 要修改my-big的src属性为当前点击的小图片上的data-target属性值!
    //          当前小图片 获取 data-target属性值
    .attr("src",$(this).attr("data-target"))
    //.prop()          不能改.prop()
  })
  </script>
</body>

</html>
运行结果:

  1. 样式:

    (1). DOM中:

    a. 如果只修改一个css属性: 元素.style.css属性=值

    b. 获取一个元素的css属性: var style=getComputedStyle(元素)

    c. 如果批量修改一个元素的多个css属性: 元素.className="class名"

    (2). jq中:

    a. 将修改css属性和获取css属性统一为一个: $元素.css("css属性名","属性值")

     一个函数两用: 
     如果没传入新属性值,则自动执行读取旧属性值的操作,相当于getComputedStyle
     如果传入新属性值,则自动切换为执行修改属性值的操作,相当于元素.style.css属性
    

    b. 如果批量修改一个元素的多个css属性,依然使用class的方式。

     1). 问题: DOM中的className如果只想操作一个class名而不影响当前元素上其它class名,非常不方便!因为className是一个完整的字符串,只能整体替换所有class。
     2). 解决: jq定义两个4个函数,专门对class执行不同的操作: 
     i. $元素.addClass("class名")
     	  添加class
     ii. $元素.removeClass("class名")
     	  移除class
     iii. var bool=$元素.hasClass("class名")
     	   判断是否包含某个class
     iv. $元素.toggleClass("class名")
     	    切换有没有一个class
     	    ①等效于: 
     	if(有这个class hasClass()){
     		就移除class removeClass()
     	}else{
     		就添加class addClass()
     	}
     	②问题: 能不能用toggleClass完全代替前边的addClass和removeClass
     		答: 不能!addClass永远是添加class, removeClass永远是移除class,但是toggleClass没准: 一次添加,一次移除,再一次才是添加,再一次又是移除!
     	③总结: 只有确实在有和没有一个class之间来回切换时,才用toggleClass
    

    (3). 示例: 双态按钮

    <!DOCTYPE html>
    

双态按钮

运行结果:
```

简写: .attr()/.prop()/.css() 其实都可以一句话修改多个属性值
$元素.attr或prop或css({
  属性名: 属性值,
      ... : ...
})

三. 按节点间关系查找:

  1. 父子关系:

    (1). 获得一个元素的父元素: $元素.parent() 代替 元素.parentElement

    (2). 获得一个元素下所有直接子元素: $元素.children() 代替 元素.children

    a. 问题: children默认只能选择所有直接子元素,无法只选择个别想要的子元素

      解决: $元素.children(选择器), 意为可以有选择的挑选部分符合条件的元素
    

    b. 问题: children默认只能在直接子元素中查找!无法在所有后代中查找

      解决: $元素.find(选择器)  在所有后代元素中查找符合要求的元素
    

    (3). 获得一个元素下第一个直接子元素: 元素.firstElementChild

     $元素.children(":first-child");
    

    (4). 获得一个元素下最后一个直接子元素: 元素.lastElementChild

     $元素.children(":last-child");
    
  2. 兄弟关系:

    (1). 前一个兄弟:

    a. DOM中: 元素.previousElementSibling

    b. jq中: $元素.prev()

    c. 问题: 有时,不止找前一个元素,想找之前所有元素

    解决: $元素.prevAll(选择器)
    

    (2). 下一个兄弟:

    a. DOM中: 元素.nextElementSibling

    b. jq中: $元素.next();

    c. 问题: 有时,不止找下一个元素,想找之后所有元素

    解决: $元素.nextAll(选择器)
    

(3). 问题: 有时,我们希望获得除当前元素之外其余所有兄弟元素(不论前后)!

	解决: $元素.siblings("选择器")

  1. 示例: 使用按节点间关系查找,选择指定的元素
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <title>...</title>
  <script>
  </script>
</head>

<body>
  <!--    ul.top>(li.parent>ul>li.child*3)*2 -->
  <ul class="top">
    <li class="parent1">parent1
      <ul>
        <li class="child">child1</li>
        <li class="child">child2</li>
        <li class="child">child3</li>
      </ul>
    </li>
    <li class="parent2">parent2
      <ul>
        <li class="child">child1</li>
        <li class="child">child2</li>
        <li class="child">child3</li>
      </ul>
    </li>
  </ul>
  <script src="js/jquery-1.11.3.js"></script>
  <script>
    //修改class为top的ul的所有直接子元素
    $("ul.top").children().css("border","1px solid red")
    //修改class为top的ul的所有后代li
    $("ul.top").find("li").css("box-shadow","0 0 5px green")
    //为class为child的li绑定单击事件
    $("li.child").click(function(){
      //选择当前元素的下一个元素/前一个元素/之前所有/之后所有/除自己之外所有
      $(this).siblings()//.nextAll()//.prevAll()//.prev()//.next()
      .css("background-color","yellow");
    })
  </script>
</body>

</html>
运行结果: 

  1. 示例: 标签页效果

<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <style>
    .tabs {
      list-style: none;
      padding: 0
    }

    .tabs a {
      text-decoration: none;
      color: #000;
      padding: 6px 12px;
      display: inline-block;
    }

    .tabs>li {
      float: left;
      border-bottom: 1px solid #000;
    }

    .tabs>.active {
      border: 1px solid #000;
      border-bottom: 0;
    }
  </style>
</head>

<body>
  <h1>使用属性选择器实现标签页头的切换</h1>
  <ul class="tabs">
    <li class="active"><a data-toggle="tab" href="#">十元套餐</a></li>
    <li><a data-toggle="tab" href="#">二十元套餐</a></li>
    <li><a data-toggle="tab" href="#">三十元套餐</a></li>
  </ul>
  <script src="js/jquery-1.11.3.js"></script>
  <script>
    //DOM 4步
    //1 查找触发事件的元素
    //本例中: 用户点有data-toggle属性,且属性值为tab的元素触发变化
    $("[data-toggle=tab]")
    //2. 绑定事件处理函数
    //本例中: 单击触发变化
    .click(function(){
      //3. 查找要修改的元素
      //4. 修改元素
      //本例中: 先给当前a的父元素li加active class,再去掉当前a的父元素里的兄弟身上的active class
      $(this).parent()
      //  a   当前li    
              .addClass("active")//本来不需要返回值
      //jQuery要求addClass必须返回.前的主语
      //return $当前li
      //addClass的返回值,刚巧和下一个操作的.前的主语一致!
              .siblings().removeClass("active");
      //        其它li
      //jquery链式操作!
    })
  </script>
</body>

</html>
运行结果:

四. 添加/删除/替换/克隆:

  1. 添加: (1). 回顾: DOM中: 3步:

    a. 创建新元素: var 新元素=document.createElement("标签名")

    b. 设置关键属性: 元素.属性名=属性值

    c. 将新元素添加到DOM树: 3种:

     1).  父元素末尾追加新元素: 父元素.appendChild(新元素)
     2). 插入到父元素下一个现有子元素之前: 父元素.insertBefore(新元素, 现有子元素)
     3). 替换父元素下一个现有子元素: 父元素.replaceChild(新元素, 现有子元素)
    

    (2). jq中: 2步:

    a. 用一段HTML片段创建一个或多个元素:

    var $新元素=$(`HTML代码片段`);

    问题: 依然是在内存中游离的,没有在DOM树上!所以,页面上暂时看不到

    解决: 挂载

    b. 将新元素添加到DOM树: 5种情况,10个函数

     1). 父元素末尾追加新元素: 
     $父元素.append($新元素) 代替 父元素.appendChild(新元素)
    
     兄弟函数: $新元素.appendTo($父元素)
     2). 父元素开头插入新元素: 
     新增: $父元素.prepend($新元素)
    
     兄弟函数: $新元素.prependTo($父元素)
     3). 插入到一个现有子元素之前: 
     $现有元素.before($新元素) 代替 父元素.insertBefore(新元素, 现有子元素)
    
     兄弟函数: $新元素.insertBefore($现有元素)
     4). 插入到一个现有子元素之后: 
     新增:  $现有元素.after($新元素) 
    
     兄弟函数: $新元素.insertAfter($现有元素)
     5). 替换父元素下一个现有子元素: 
     $现有元素.replaceWith($新元素) 父元素.replaceChild(新元素, 现有子元素)
    
     兄弟函数: $新元素.replaceAll($现有元素)
    

为什么每个函数又多出一个功能一模一样,只是主语和宾语颠倒位置的新函数?

因为主语不同,则函数返回的jquery对象不用。则后续可连接的链式操作也就不同!

如果希望在追加一个新元素后,继续对新元素执行下一步操作:

不好的做法: $父元素.append($新元素)

            return $父元素,下一步用不了!
         $新元素.下一步操作

好的做法: $新元素.appendTo($父元素).下一步操作()

            return $新元素  下一步可继续使用

  1. 删除: $元素.remove()

  2. 示例: 点按钮,添加方块,点x删除方块

<!DOCTYPE html>
<html>

<head>
  <title> new document </title>
  <meta charset="utf-8">
  <style>
    .container {
      border: 1px solid #aaa;
      overflow: hidden;
    }

    .block {
      float: left;
      margin: 10px;
      border: 1px solid #aaa;
      background: #faa;
      width: 150px;
      height: 150px;
    }

    .block:hover {
      box-shadow: 0 5px 6px #000;
    }

    .close {
      float: right;
      padding: 5px;
      font-weight: bold;
      opacity: .2;
      cursor: pointer;
    }

    .close:hover {
      opacity: .5;
    }
  </style>
</head>

<body>
  <h1>添加/删除节点</h1>
  <button id="add-block">添加区块</button>

  <div class="container">
    <!-- <div class="block">
      <span class="close">×</span>
    </div> -->
  </div>

  <script src="js/jquery-1.11.3.js"></script>
  <script>
  //DOM 4步
  //1. 查找触发事件的元素
  //本例中: 点击按钮添加方块
  $("#add-block")
  //2. 绑定事件处理函数
  .click(function(){
    // //3. 查找要修改的元素
    // //本例中: 向class="container"的div开头插入一个新方块div元素
    // var $container=$(".container");
    // //4. 修改元素
    // //本例中: 
    // //先创建一个新的方块元素对象
    // var $block=$(`<div class="block">
    //  <span class="close">×</span>
    // </div>`);
    // //设置方块的随机背景色
    // $block.css("background-color",`rgb(${
    //  parseInt(Math.random()*256)
    // },${
    //  parseInt(Math.random()*256)
    // },${
    //  parseInt(Math.random()*256)
    // })`);
    // //最后将方块插入到$container开头
    // $container.prepend($block);

    //创建一个新方块
    $(`<div class="block">
        <span class="close">×</span>
    </div>`)
    //设置方块的随机背景色
    .css("background-color",`rgb(${
      parseInt(Math.random()*256)
    },${
      parseInt(Math.random()*256)
    },${
      parseInt(Math.random()*256)
    })`)
    //return 新方块
    //将方块插入到父元素开头
    //.prependTo($(".container"))
    //简写: 不用自己找.container,直接把选择器给prependTo,prependTo会自动查找选择器所指的父元素
    .prependTo(".container");
  })
  
  //实现点x按钮删除当前方块
  //DOM 4步
  //1. 查找触发事件的元素 
  //本例中: 因为多个x都可单击,所以应该用事件委托优化——复习事件委托
  //事件应该只绑定在父元素上一份即可
  $(".container")
  //2. 绑定事件处理函数
  //本例中: 应该先获得事件对象e,才能用e.target获得目标元素x
  .click(function(e){
    //获得当前点击的元素
    var $target=$(e.target);
    //判断当前实际点的元素是否是想要的
    //本例中: 只有点在class为close的span元素上,才能删除
    if($target.hasClass("close")){ //说明我们点的是x
      //3. 查找要修改的元素
      //本例中: 点x,其实是要删除x的父元素div
      $target.parent()
      //4. 修改元素
      //本例中: 删除父元素div
             .remove();
    }
  })
  
  </script>

</body>

</html>
运行结果: