JavaScript中Dom0713

JavaScript中Dom

1.基本概念

1.1 什么是window?
  • window:是一個全局對象, 代表瀏覽器中一個打開的窗口, 每個窗口都是一個window對象(整個窗口哦)
1.2 什么是document?
  • document是window的一個屬性, 這個屬性是一個對象
  • document: 代表當前窗口中的整個網頁
  • document對象保存了網頁上所有的內容, 通過document對象就可以操作網頁上的內容

1.3 什么是DOM?

  • DOM 定義了訪問和操作 HTML文檔(網頁)的標準方法,所以學習DOM就是學習如何通過document對象操作網頁上的內容

2.獲取dom元素==(注意理解節(jié)點的概念)==

在JavaScript中HTML標簽也稱之為DOM元素,使用document的時候前面不用加window

2.1通過id獲取
  • document.getElementById("box");
  • 由于id不可以重復, 所以找到了就會將找到的標簽包裝成一個對象返回給我們, 找不到就返回Null
  • 注意點: DOM操作返回的是一個對象, 這個對象是宿主類型對象(瀏覽器提供的對象)
2.2 通過class名稱獲取
  • document.getElementsByClassName("father");
  • 由于class可以重復, 所以找到了就返回一個存儲了標簽對象的數(shù)組, 找不到就返回一個空數(shù)組
2.3 通過name名稱獲取
  • <form>
            <input type="text" name="test">
            <input type="password" name="test">
    </form>
    let oDivs = document.getElementsByName("test");
    console.log(oDivs);
    
  • 由于name可以重復, 所以找到了就返回一個存儲了標簽對象的數(shù)組, 找不到就返回一個空數(shù)組

  • getElementsByName 在不同的瀏覽器其中工作方式不同。在IE和Opera中, getElementsByName() 方法還會返回那些 id 為指定值的元素

2.4 通過標簽名稱獲取
  • document.getElementsByTagName("div");
  • 由于標簽名稱可以重復, 所以找到了就返回一個存儲了標簽對象的數(shù)組, 找不到就返回一個空數(shù)組
2.5 通過選擇器獲取(重點)
  • let oDiv = document.querySelector(".box");
  • querySelector只會返回根據(jù)指定選擇器找到的第一個元素
2.6 通過選擇器獲取2(重點)
  • let oDivs = document.querySelectorAll(".father");
  • querySelectorAll會返回指定選擇器找到的所有元素
2.7 獲取元素中所有子元素或子節(jié)點
  • 首先了解一下什么是節(jié)點

    • DOM對象(document), 這個對象以樹的形式保存了界面上所有的內容,HTML頁面每一部分都是由節(jié)點(標簽(元素),文本,屬性)
    • 節(jié)點樹.png
  • let oDiv = document.querySelector("div");
    // children屬性獲取到的是指定元素中所有的子元素
    console.log(oDiv.children);
    // childNodes屬性獲取到的是指定元素中所有的節(jié)點
     console.log(oDiv.childNodes);
    for(let node of oDiv.childNodes){
       console.log(node.nodeType); 
        if(node.nodeType === Node.ELEMENT_NODE){  //判斷節(jié)點類型
            console.log(node);
        }
    }
    
2.8獲取指定節(jié)點第一個或最后一個子節(jié)點或子元素
  • let oDiv = document.querySelector("div");
    //第一個子節(jié)點
    console.log(oDiv.firstChild);
    //獲取指定元素中的第一個子元素
    console.log(oDiv.firstElementChild);
    
    //獲取指定節(jié)點中最后一個子節(jié)點
    console.log(oDiv.lastChild);
    // 獲取指定元素中最后一個子元素
    console.log(oDiv.lastElementChild);
    
2.9 獲取子元素獲取父節(jié)點或度元素
  • let item = document.querySelector(".item");
    //其實獲取的一樣,只不過由于火狐瀏覽器以前不支持parentNode,所以才有了兩個
    console.log(item.parentElement);
    console.log(item.parentNode);
    let parentEle = item.parentElement || item.parentNode;//兼容性寫法
    console.log(parentEle);
    
2.10 獲取相鄰上一個節(jié)點或元素/下一個節(jié)點或元素
  • //獲取相鄰上一個節(jié)點
    console.log(item.previousSibling);
    //獲取相鄰上一個元素
    console.log(item.previousElementSibling);
    //獲取相鄰下一個節(jié)點
    console.log(item.nextSibling);
    //獲取相鄰下一個元素
    console.log(item.nextElementSibling);
    

3.節(jié)點增刪改查

首先我們有這樣一個結構

  • <div>
        <h1>我是標題</h1>
        <p>我是段落</p>
    </div>
    

然后我們創(chuàng)建一個節(jié)點

  • let oSpan = document.createElement("span");
    // console.log(oSpan);
    // console.log(typeof oSpan);  是一個對象類型
    

然后將這個節(jié)點添加進去

  • // 注意點: appendChild方法會將指定的元素添加到最后
    let oDiv = document.querySelector("div");
    oDiv.appendChild(oSpan)
    

那么如果我想添加在指定的地方怎么辦

  • let oDiv = document.querySelector("div");
    let oH1 = document.querySelector("h1");
    let oP = document.querySelector("p");
    oDiv.insertBefore(oSpan, oH1); //我就把oSpan插到了oH1前面
    oDiv.insertBefore(oSpan, oP);
    
    

該怎么刪除呢

  • // 注意點: 在js中如果想要刪除某一個元素, 只能通過對應的父元素來刪除,元素是不能夠自殺的
    console.log(oSpan.parentNode);
    oSpan.parentNode.removeChild(oSpan);
    oDiv.parentNode.removeChild(oDiv);
    
    

再看一下如何克隆一個節(jié)點

  • // 注意點: cloneNode方法默認不會克隆子元素, 如果想克隆子元素需要傳遞一個true
    let oDiv = document.querySelector("div");
    let newDiv =  oDiv.cloneNode();//只克隆自己,不可隆子元素
    let newDiv =  oDiv.cloneNode(true);
    console.log(newDiv);
    
    

4.元素屬性的增刪改查

4.1 基本概念
  • 無論是通過document創(chuàng)建還是查詢出來的標簽,系統(tǒng)都會將元素包裝成一個對象返回給我們,系統(tǒng)在包裝這個對象的時候會自動將元素的屬性都包裝到這個對象中,所以只要拿到這個對象就可以拿到標簽屬性,操作標簽屬性.
4.2 如何獲取元素屬性
  • <img src="images/1.jpg" alt="我是alt222" title="我是title" nj="666">
    let oImg = document.querySelector("img");
    console.log(oImg.alt);
    console.log(oImg.getAttribute("alt"));
    //注意點: 通過對象.屬性名稱的方式無法獲取到自定義屬性的取值
    //通過getAttribute方法可以獲取到自定義屬性的取值
    console.log(oImg.nj);//獲取不到
    console.log(oImg.getAttribute("nj"))
    
    
4.3 如何修改元素屬性
  • oImg.title = "新的title";
    oImg.setAttribute("title", "新的title222"); //給屬性名為title的內容設為新的title222
     //注意點和獲取元素屬性一樣
    oImg.nj = "123";
    oImg.setAttribute("nj", "123");
    
    
4.4 如何新增元素屬性
  • // 注意點: setAttribute方法如果屬性不存在就是新增, 如果屬性存在就是修改
    oImg.setAttribute("it666", "itzb");
    
    
4.5 如何刪除元素屬性
  • oImg.removeAttribute("alt");
    // 注意點和獲取元素屬性一樣
    oImg.nj = "";
    oImg.removeAttribute("nj");
    
    

5.元素內容操作

5.1 獲取元素內容
  • /*
    1.innerHTML獲取的內容包含標簽, innerText/textContent獲取的內容不包含標簽
    2.innerHTML/textContent獲取的內容不會去除兩端的空格, innerText獲取的內容會去除兩端的空格
    */
    let oDiv = document.querySelector("div");
    console.log(oDiv.innerHTML);
    console.log(oDiv.innerText);
    console.log(oDiv.textContent);
    
    
5.2 設置元素內容
  • /*
       特點:
       無論通過innerHTML/innerText/textContent設置內容, 新的內容都會覆蓋原有的內容
       區(qū)別:
       如果通過innerHTML設置數(shù)據(jù), 數(shù)據(jù)中包含標簽, 會轉換成標簽之后再添加
       如果通過innerText/textContent設置數(shù)據(jù), 數(shù)據(jù)中包含標簽, 不會轉換成標簽, 會當做一個字符串直接設置
    */
     let oDiv = document.querySelector("div");
    // oDiv.innerHTML = "123";
    // oDiv.innerText = "456";
    // oDiv.textContent = "789";
    //  oDiv.innerHTML = "<span>我是span</span>";
    //  oDiv.innerText = "<span>我是span</span>";
    //  oDiv.textContent = "<span>我是span</span>";
    
     setText(oDiv, "www.it666.com");
    //為了解決兼容性問題,企業(yè)開發(fā)中textContent和innerText是結合起來使用的
     function setText(obj, text) {
         if("textContent" in obj){   //如果有這個屬性
             obj.textContent = text;
         }else{
             obj.innerText = text;
         }
     }
    
    

6.元素樣式操作

6.1 設置元素樣式
  • <style>
         .box{
             width: 200px;
             height: 200px;
             background-color: red;
         }
    </style>
    let oDiv = document.querySelector("div");
    // 第一種方式
    // 注意點: 由于class在JS中是一個關鍵字, 所以叫做className
    oDiv.className = "box";
    // 第二種方式
    // 注意點: 過去CSS中通過-連接的樣式, 在JS中都是駝峰命名
    // 注意點: 通過JS添加的樣式都是行內樣式, 會覆蓋掉同名的CSS樣式
    oDiv.style.width = "300px";
    oDiv.style.height = "300px";
    oDiv.style.backgroundColor = "blue";
    
    
6.2 獲取元素樣式
  • let oDiv = document.querySelector("div");
    oDiv.style.width = "300px";
    // 注意點: 通過style屬性只能過去到行內樣式的屬性值, 獲取不到CSS設置的屬性值
    console.log(oDiv.style.width);
    // 注意點: 如果想獲取到CSS設置的屬性值, 必須通過getComputedStyle方法來獲取
    // getComputedStyle方法接收一個參數(shù), 這個參數(shù)就是要獲取的元素對象
    // getComputedStyle方法返回一個對象, 這個對象中就保存了CSS設置的樣式和屬性值
    let style = window.getComputedStyle(oDiv);
    console.log(style.width);
    
    

7. 點擊事件

如何給元素綁定事件?

  • 在JavaScript中所有的HTML標簽都可以添加事件,元素.事件名稱 = function(){},當對應事件被觸發(fā)時候就會自動執(zhí)行function中的代碼.

  • <button>我是按鈕</button>
    <a >我是a標簽</a>
    
    
    let oBtn = document.querySelector("button");
    oBtn.onclick = function () {
        alert("按鈕被點擊了");
    }
    // 注意點: 如果給元素添加了和系統(tǒng)同名的事件, 我們添加的事件不會覆蓋系統(tǒng)添加的事件,只不過會先執(zhí)行我們添加的,在執(zhí)行系統(tǒng)的.想要覆蓋就寫一句return false
    let oA = document.querySelector("a");
    oA.onclick = function () {
        alert("a標簽被點擊了");
        // 以下代碼的含義: 用我們添加的事件覆蓋掉系統(tǒng)同名的事件
        return false;
    }
    
    

8. 定時器

8.1重復執(zhí)行的定時器
  • setInterval

  • //有兩個按鈕
    <button id="start">開始</button>
    <button id="close">結束</button>
    //定時器會返回一個唯一的標識,我們用id來接收,方便關閉
    let startBtn = document.querySelector("#start");
    let id = null;
    startBtn.onclick = function () {
        id = setInterval(function () {
            console.log("隨便寫點");
        }, 1000);
    }
    let closeBtn = document.querySelector("#close");
    closeBtn.onclick = function () {
        clearInterval(id);
    }
    
    
8.2 只執(zhí)行一次的
  • setTimeout

  • let startBtn = document.querySelector("#start");
    let closeBtn = document.querySelector("#close");
    let id = null;
    startBtn.onclick = function () {
        id = window.setTimeout(function () {
            console.log("隨便寫點");
        }, 5000);
    }
    closeBtn.onclick = function () {
        clearTimeout(id);
    }
    
    

9.做兩個小游戲

9.1 消除鬼魂

9.2貪吃蛇

10.移入移出事件

  • // 1.移入事件
    oDiv.onmouseover = function () {
        console.log("移入事件");
    }
    // 注意點: 對于初學者來說, 為了避免未知的一些BUG, 建議使用onmouseenter
    oDiv.onmouseenter = function () {
        console.log("移入事件");
    }
     
    // 2.移出事件
    oDiv.onmouseout = function () {
        console.log("移出事件");
    }
    // 注意點: 對于初學者來說, 為了避免未知的一些BUG, 建議使用onmouseleave
    oDiv.onmouseleave = function () {
        console.log("移出事件");
    }
    // 3.移動事件
    oDiv.onmousemove = function () {
        console.log("移動事件");
    }
     
    
    
  • 移入移出表單 商品展示

11 表單事件(注意實時獲取修改后的數(shù)據(jù))

  • let oInput = document.querySelector("input");
       // 1.監(jiān)聽input獲取焦點
        oInput.onfocus = function () {
            console.log("獲取到了焦點");
        }
       // 2.監(jiān)聽input失去焦點
        oInput.onblur = function () {
            console.log("失去了焦點");
        }
       // 3.監(jiān)聽input內容改變
       // 注意點: onchange事件只有表單失去焦點的時候, 才能拿到修改之后的數(shù)據(jù)
       oInput.onchange = function () {
           console.log(this.value);
       }
       // oninput事件可以時時獲取到用戶修改之后的數(shù)據(jù), 只要用戶修改了數(shù)據(jù)就會調用(執(zhí)行)
       // 注意點: oninput事件只有在IE9以及IE9以上的瀏覽器才能使用
       // 在IE9以下, 如果想時時的獲取到用戶修改之后的數(shù)據(jù), 可以通過onpropertychange事件來實現(xiàn)
       // 通過代碼修改value不會觸發(fā)input事件
       oInput.oninput = function () {
           console.log(this.value);
      }
     
    
    
   
* 表單校驗   以及輸入框有內容才能點擊按鈕

   * 讓當前提交按鈕不能點擊用disabled ,當不能點擊時,disabled為true

#### 12 tab選項卡

* ```JavaScript
  <body>
  <div class="box">
      <ul class="top">
          <li class="current">新聞</li>
          <li>視頻</li>
          <li>音樂</li>
          <li>軍事</li>
          <li>財經</li>
      </ul>
      <div class="bottom">
          <div class="content">新聞的內容</div>
          <div class="content">視頻的內容</div>
          <div class="content">音樂的內容</div>
          <div class="content">軍事的內容</div>
          <div class="content">財經的內容</div>
      </div>
  </div>
  <script>
      // 1.拿到需要操作的元素
      let oItems = document.querySelectorAll("li");
      let oDivs = document.querySelectorAll(".content");
      // 定義變量保存上一次設置的索引
      let previousIndex = 0;
      // 2.給所有的選項卡添加點擊事件
      for(let i = 0; i < oItems.length; i++){
          let item = oItems[i];
          // item.setAttribute("index", i);
          item.onclick = function() {
              // 清空上一次對應的元素對應的樣式
              let preItem = oItems[previousIndex];
              preItem.className = "";
              let preDiv = oDivs[previousIndex];
              preDiv.style.display = "none";
  
              // 設置當前這一次的元素對應的樣式
              // let index = this.getAttribute("index");
              this.className = "current";
              let oDiv = oDivs[i];
              oDiv.style.display = "block";
  
              // 保存當前這一次的索引
              previousIndex = i;
          };
      }
  </script>
  </body>
  

  • 在上面的代碼中,為什么i直接就能用,為什么用let定義的for循環(huán)就行,var就不行,我們先引出閉包的概念

  • 12.1 閉包
    • /*
      1.什么是閉包(closure)?
      閉包是一種特殊的函數(shù)。
      
      2.如何生成一個閉包?
      當一個內部函數(shù)引用了外部函數(shù)的數(shù)據(jù)(變量/函數(shù))時, 那么內部的函數(shù)就是閉包
      所以只要滿足"是函數(shù)嵌套"、"內部函數(shù)引用外部函數(shù)數(shù)據(jù)"
      
      3.閉包特點:
      只要閉包還在使用外部函數(shù)的數(shù)據(jù), 那么外部的數(shù)據(jù)就一直不會被釋放
      也就是說可以延長外部函數(shù)數(shù)據(jù)的生命周期
      
      4.閉包注意點:
      當后續(xù)不需要使用閉包時候, 一定要手動將閉包設置為null, 否則會出現(xiàn)內存泄漏
      */
      function test() {
          var i = 666; // 局部變量
      } // 只要代碼執(zhí)行到了大括號結束, i這個變量就會自動釋放
      console.log(i); // i is not defined
      //下面開啟閉包
      function test() {
          var i = 666;
          // 由于demo函數(shù)滿足閉包的兩個條件, 所以demo函數(shù)就是閉包
          return function demo() {
              console.log(i);
          }
      }
      let fn = test();
      fn(); // 666
      
      
12.2 循環(huán)索引同步(var的情況)
  • /*
    默認情況下是順序結構, 代碼會從上之下的執(zhí)行, 前面的沒執(zhí)行完后面的不能執(zhí)行
    默認情況下通過var定義的變量, 只要不是定義在函數(shù)中都是全局變量
    */
    
    for(var i = 0; i < 3; i++){ // 0 1 2 3
        function test() {
            console.log(i); // 3
        }
    }
    // console.log(i); // 3
    test();
    //想要輸出當前索引,有如下方式
    for(var i = 0; i < 3; i++){ // 0 1 2 3
        function test() {
            console.log(i); // 0 1 2
        }
        test();
    }
     
    for(var i = 0; i < 3; i++){ // 0 1 2 3
        (function test() {
            console.log(i); // 0 1 2
        })();
    }
     
    for(var i = 0; i < 3; i++){ // 0 1 2 3
        // function test(index) { // var index = i;
        //     console.log(index); // 0 1 2
        // }
        // test(i);  可以簡寫為如下
        (function test(index) {
            console.log(index); // 0 1 2
        })(i);
    }
     
    
    
  • 做一個練習,定義三個按鈕,點擊每一個輸出對應的索引

    • //不能同步,因為等循環(huán)執(zhí)行完才執(zhí)行函數(shù)
      let oBtns = document.querySelectorAll("button");
      for(var i = 0; i < oBtns.length; i++){
          let btn = oBtns[i];
          btn.onclick = function () {
              console.log(i); // 3
          }
      }
      
      
    • //能同步
      let oBtns = document.querySelectorAll("button");
      for(var i = 0; i < oBtns.length; i++) {
          let btn = oBtns[i];
          (function test(index) { // var index = i;
              // console.log(index); // 0 1 2
            // 注意點: onclick對應的方法由于滿足了閉包的條件, 所以onclick對應的方法也是一個閉包
             //所以index不會被立即釋放,我們就能訪問了
              btn.onclick = function () {
                  console.log(index);
              }
          })(i);
      }
      
      
    • 看一下上面那個函數(shù)執(zhí)行完在內存里面的情況

    • 循環(huán)索引同步.png
12.2 循環(huán)索引同步(let的情況)
  • /*let list = [];
     // 這里的i是局部變量
     // 注意點: 由于i是局部變量, 所以每次執(zhí)行完循環(huán)體都會重新定義一個i變量
     for(let i = 0; i < 3; i++){ // 0 1 2 3
         let fn = function test() {
             console.log(i); // 3
         }
         list.push(fn);
     }
     // console.log(i); // i is not defined
     // 以下會依次輸出1,2,3
     list[0]();
     list[1]();
     list[2]();
     */
     for(let i = 0; i < 3; i++){ // 0 1 2 3
         // 注意點: 在ES6中由于{}是塊級作用域, 所以只要在塊級作用域中定義了一個函數(shù)
         //         并且這個函數(shù)中用到了塊級作用域中的數(shù)據(jù), 那么這個函數(shù)就是閉包
         function test() {
             console.log(i); 
         }
     }
     test(); // 2
    
    
    
  • 上面的代碼內存中情況如下

  • 循環(huán)索引同步let.png

? 這就是為什么通過let定義在for循環(huán)中后通過點擊事件可以取得當前的i值,因為是閉包

12.3 排他思想
  • /*
    1.什么是排它思想?
    清除其它非選中元素的樣式, 只設置當前選中元素樣式
    */
    let oItems = document.querySelectorAll("li");
    let previousIndex = 0;
    
     // es6之后
    for(let i = 0; i < oItems.length; i++){
        let item = oItems[i];
        item.onclick = function () {
            // 排它
            // for(let j = 0; j < oItems.length; j++){
            //     let li = oItems[j];
            //     li.className = "";
            // }
            // 通過一個索引實現(xiàn)排他
            let preItem = oItems[previousIndex];
            preItem.className = "";
    
            this.className = "current";
            previousIndex = i;
        }
    }
    //es6之前
    for(var i = 0; i < oItems.length; i++) {
        var item = oItems[i];
        (function (index) {
            item.onclick = function () {
                // 排它
                var preItem = oItems[previousIndex];
                preItem.className = "";
    
                this.className = "current";
                previousIndex = index;
            }
        })(i);
    }
    
    

13 時鐘對象

  • // 1.獲取當前時間
       let date = new Date();
       console.log(date);
       // 2.獲取當前時間距離1970年1月1日(世界標準時間)起的毫秒
        console.log(Date.now());
        let date = new Date();
        console.log(date.valueOf());
     
       // 3.創(chuàng)建指定時間
        let date1 = new Date("2019-11-11 09:08:07");
        console.log(date1);
       // 注意點: 在創(chuàng)建指定時間的時候, 如果月份是單獨傳入的, 那么會多一個月
       let date2 = new Date(2019, 10, 11, 9, 8, 7);
        console.log(date2);
     
       // 4.獲取指定時間年月日時分秒
       let date = new Date();
       console.log(date);
       console.log(date.getFullYear());
       // 注意點; 通過getMonth方法獲取到的月份會少一個月
        console.log(date.getMonth() + 1);
        console.log(date.getDate());
        console.log(date.getHours());
        console.log(date.getMinutes());
        console.log(date.getSeconds());
     
       // 5.時間格式化
       let date = new Date();
       let res = formartDate(date);
       console.log(res);
       // console.log(date);
       // 2019-4-19 18:17:06
       function formartDate(date) {
           return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}                        ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
       }
     
    
    
  • 獲取時間差
  • // 1000毫秒 = 1秒   60秒 = 1分鐘  60分鐘 = 1小時  24小時 = 1天
    // 以下兩個時間相差值 10天1小時29分40秒
    let curDate = new Date("2020-4-19 22:30:20");
    let remDate = new Date("2020-4-30 00:00:00");
    // 1.得到兩個時間之間的差值(毫秒)
    let differTime = remDate - curDate;
    // let differTime = remDate.valueOf() - curDate.valueOf();
    // 2.得到兩個時間之間的差值(秒)
    let differSecond = differTime / 1000;
    // 3.利用相差的總秒數(shù) / 每一天的秒數(shù) = 相差的天數(shù)
    let day = Math.floor(differSecond / (60 * 60 * 24));
    console.log(day);
    // 4.利用相差的總秒數(shù) / 小時 % 24;
    let hour = Math.floor(differSecond / (60 * 60) % 24);
    console.log(hour);
    // 5.利用相差的總秒數(shù) / 分鐘 % 60;
    let minute = Math.floor(differSecond / 60 % 60);
    console.log(minute);
    // 6.利用相差的總秒數(shù) % 秒數(shù)
    let second = differSecond % 60;
    console.log(second);
    
    
    
  • 秒殺效果 時鐘效果

14 勻速動畫和緩動動畫

14.1 勻速動畫
  • function linearAnimation(ele, target) {
        //關掉定時器,防止定時器的疊加
       clearInterval(timerId);
       timerId = setInterval(function () {
           // 1.拿到元素當前的位置
           let begin = parseInt(ele.style.marginLeft) || 0;
           // 2.定義變量記錄步長
           //         0  -  500 = -500    13
           //         500 -  200 = 300    -13
           let step = (begin - target) > 0 ? -13 : 13;
           // 3.計算新的位置
           begin += step;
           console.log(Math.abs(target - begin), Math.abs(step));
           //當由小往大走時,不夠一個步長說明就快到終點了,往小同理
           if(Math.abs(target - begin) <= Math.abs(step)){
               clearInterval(timerId);
               begin = target;
           }
     
           // 4.重新設置元素的位置
           ele.style.marginLeft = begin + "px";
       }, 100);
    }
    
    
14.2 緩動動畫
  • function easeAnimation(ele, target) {
       clearInterval(timerId);
       timerId = setInterval(function () {
           // 1.拿到元素當前的位置
           let begin = parseInt(ele.style.marginLeft) || 0;
           // 2.定義變量記錄步長
           // 公式: (結束位置 - 開始位置) * 緩動系數(shù)(0 ~1)
           let step = (target - begin) * 0.3;
           console.log(step);
           // 3.計算新的位置
           begin += step;
           //結束條件
           if(Math.abs(Math.floor(step)) <= 1){
               clearInterval(timerId);
               begin = target;
           }
           // 4.重新設置元素的位置
           ele.style.marginLeft = begin + "px";
       }, 100);
    }
    
    

    無限自動輪播

14.3 勻速動畫的封裝
  • 對前面代碼的優(yōu)化,可以實現(xiàn)多個動畫一起執(zhí)行

  • linearAnimation(oDiv, {"marginTop":500, "marginLeft": 300}, function () {
         alert("動畫執(zhí)行完畢之后執(zhí)行的其它的操作");
     });
    
    function linearAnimation(ele, obj, fn) {
        clearInterval(timerId);
        timerId = setInterval(function () {
            // flag變量用于標記是否所有的屬性都執(zhí)行完了動畫
            let flag = true;
            for(let key in obj){
                let attr = key;
                let target = obj[key];
    
                // 1.拿到元素當前的位置
                // let begin = parseInt(ele.style.width) || 0;
                let style = getComputedStyle(ele);
                // let begin = parseInt(style.width) || 0;
                let begin = parseInt(style[attr]) || 0;
                // 2.定義變量記錄步長
                let step = (begin - target) > 0 ? -13 : 13;
                // 3.計算新的位置
                begin += step;
                if(Math.abs(target - begin) > Math.abs(step)){
                    flag = false;
                }else{
                    begin = target;
                }
                // 4.重新設置元素的位置
                // ele.style.width = begin + "px";
                ele.style[attr] = begin + "px";
            }
            if(flag){
                clearInterval(timerId);
                // if(fn){
                //     fn();
                // }
                fn && fn();
            }
        }, 100);
    
    

15 事件

15.1 添加事件的三種方式
  • /*
    方式一:
    1.通過onxxx的方式來添加
    注意點: 由于是給屬性賦值, 所以后賦值的會覆蓋先賦值
    */
    oBtn.onclick = function () {
        alert("666");
    }
    oBtn.onclick = function () {
        alert("777");
    }
    let obj = {};
    obj.say = function () {
        console.log("123");
    }
    obj.say = function () {
        console.log("456");
    }
    obj.say();
    
    
  • /*
     方式二:
     2.通過addEventListener方法添加
     注意點:
     1.事件名稱不需要添加on
     2.后添加的不會覆蓋先添加的  下面會輸出兩次
     3.只支持最新的瀏覽器IE9
     */
     oBtn.addEventListener("click", function () {
         alert("666");
     });
     oBtn.addEventListener("click", function () {
         alert("777");
     });
    
    
    
  • /*
     方式三
     3.通過attachEvent方法添加
     注意點:
     1.事件名稱必須加上on
     2.后添加的不會覆蓋先添加的
     3.只支持低版本的瀏覽器
     */
     oBtn.attachEvent("onclick", function () {
         alert("666");
     });
     oBtn.attachEvent("onclick", function () {
         alert("777");
     });
    
    
    
  • 以下為兼容寫法

    • function addEvent(ele, name, fn) {
          if(ele.attachEvent){
              ele.attachEvent("on"+name, fn);
          }else{
              ele.addEventListener(name, fn);
          }
      }
      
      
15.2 事件對象以及阻止默認行為
  • /*
    1.什么是事件對象?
    事件對象就是一個系統(tǒng)自動創(chuàng)建的一個對象
    當注冊的事件被觸發(fā)的時候, 系統(tǒng)就會自動創(chuàng)建事件對象
    */
    /*
    2.事件對象的注意點:
    在高級版本的瀏覽器中, 會自動將事件對象傳遞給回到函數(shù)
    在低級版本的瀏覽器中, 不會自動將事件對象傳遞給回調函數(shù)
    在低級版本的瀏覽器中, 需要通過window.event來獲取事件對象
     */
    let oA = document.querySelector("a");
     oA.onclick = function (event) {
         // 兼容性的寫法
         event = event || window.event;
    
         alert("666");
         // 阻止默認行為
         return false; // 企業(yè)開發(fā)推薦
    
         // 注意點: preventDefault方法只支持高級版本的瀏覽器
         // event.preventDefault();
         // event.returnValue = false; // IE9以下的瀏覽器
     }
    
    
    
  • 事件的三個階段
  • <body>
    <div class="father">
        <div class="son"></div>
    </div>
    <script>
        /*
        1.事件的三個階段
        1.1.捕獲階段(從外向內的傳遞事件)
        1.2.當前目標階段
        1.3.冒泡的階段(從內向外的傳遞事件)
    
        2.注意點:
        三個階段只有兩個會被同時執(zhí)行
        要么捕獲和當前, 要么當前和冒泡
    
        3.為什么要么只能是捕獲和當前, 要么只能是當前和冒泡?
        這是JS處理事件的歷史問題
        早期各大瀏覽器廠商為占領市場, 以及對事件的理解不同
        后續(xù)W3C為了兼容, 將兩種方式都納入標準
        */
        /*
        1.如何設置事件到底是捕獲還是冒泡?
        通過addEventListener方法, 這個方法接收三個參數(shù)
        第一個參數(shù): 事件的名稱
        第二個參數(shù): 回調函數(shù)
        第三個參數(shù): false冒泡  / true 捕獲
    
        注意點:
        onXxx的屬性, 不接收任何參數(shù), 所以默認就是冒泡
        attachEvent方法, 只能接收兩個參數(shù), 所以默認就是冒泡
        */
        let oFDiv = document.querySelector(".father");
        let oSDiv = document.querySelector(".son");
        /*
        以下會先輸出son,然后father
        oFDiv.addEventListener("click", function () {
            console.log("father");
        }, false);
        oSDiv.addEventListener("click", function () {
            console.log("son");
        }, false);
        */
        oFDiv.onclick = function () {
            console.log("father");
        }
        oSDiv.onclick = function () {
            console.log("son");
        }
        /*
        IE 6.0:
        div -> body -> html -> document
        其他瀏覽器:
        div -> body -> html -> document -> window
        注意:
        不是所有的事件都能冒泡,以下事件不冒泡:blur、focus、load、unload
        */
    </script>
    </body>
    
    
    
  • 下圖可以很好地理解冒泡和捕獲

-
捕獲和冒泡.png
15.3 阻止事件冒泡
  • 由上面我們知道,當事件發(fā)生后,事件冒泡就是一個事件開始傳播(從里到外或者從外向里)。為什么要傳播呢?因為事件源本身(可能)并沒有處理事件的能力,即處理事件的函數(shù)(方法)并未綁定在該事件源上。例如我們點擊一個按鈕時,就會產生一個click事件,但這個按鈕本身可能不能處理這個事件,事件必須從這個按鈕傳播出去,從而到達能夠處理這個事件的代碼中(例如我們給按鈕的onclick屬性賦一個函數(shù)的名字,就是讓這個函數(shù)去處理該按鈕的click事件),或者按鈕的父級綁定有事件函數(shù),當該點擊事件發(fā)生在按鈕上,按鈕本身并無處理事件函數(shù),則傳播到父級去處理。

  • 如何阻止

    • // 1.拿到需要操作的元素
      var oFDiv = document.getElementById("father");
      var oSDiv = document.getElementById("son");
      
      // 2.注冊事件監(jiān)聽
      oFDiv.onclick = function () {
          console.log("father");
      }
      oSDiv.onclick = function (event) {
          event = event || window.event;
          // 注意點: stopPropagation方法只支持高級瀏覽器
          // event.stopPropagation();
          // event.cancelBubble = true; // 低級瀏覽器
          if(event.cancelBubble){
              event.cancelBubble = true;
          }else{
              event.stopPropagation();
          }
          console.log("son");
      }
      
      
15.4 移入移出事件區(qū)別
15.5 事件位置獲取
  • /*
    offsetX/offsetY: 事件觸發(fā)相對于當前元素自身的位置
    clientX/clientY: 事件觸發(fā)相對于瀏覽器可視區(qū)域的位置
    注意點: 可視區(qū)域是不包括滾動出去的范圍的
    pageX/pageY:     事件觸發(fā)相對于整個網頁的位置
    主要點: 整個網頁包括滾動出去的范圍的
    screenX/screenY: 事件觸發(fā)相對于屏幕的位置(電腦屏幕)
    */
    
    

16 正則表達式

  • /*
     1.什么是正則表達式?
     正則表達式就是對字符串操作的一種邏輯公式
      
     2.正則表達式的作用?
     1.在字符串"查找"是否包含指定子串
     2.從字符串中"提取"指定子串
     3.對字符串中指定的內容進行"替換"
      */
     // 1.字符串查找
     /*
     let str = "123abc456";
     let index = str.indexOf("abc");
     let index = str.lastIndexOf("abc");
     let flag = str.includes("abc");
      */
     // 2.字符串提取
     /*
     let str = "123abc456";
     let startIndex = str.indexOf("a");
     console.log(str.substr(startIndex, "abc".length));
      */
     // 3.字符串替換
     /*
     let str = "123abc456";
     str.replace("abc", "it666");
      */
      
     // 1.利用正則表達式匹配(查找)
    
     let str = "123abc456";
     // 1.創(chuàng)建一個正則表達式對象
     // 2.指定匹配的規(guī)則
     // 注意點: 默認情況下在正則表達式中是區(qū)分大小寫的,當給構造函數(shù)中傳遞一個i時,代表不區(qū)分大小寫. 
     let reg = new RegExp("A", "i");
     let res = reg.test(str);
     console.log(res);
     
     
     let str = "abc2020-1-11def";
     // 通過構造函數(shù)創(chuàng)建正則表達式對象,注意轉義字符
     // let reg = new RegExp("\\d{4}-\\d{1,2}-\\d{1,2}");
     // 通過字面量來創(chuàng)建正則表達式對象
     let reg = /\d{4}-\d{1,2}-\d{1,2}/;
     let res = reg.test(str);
     console.log(res);
      
      
     // 2.通過正則表達式提取符合規(guī)則的字符串
     
     let str = "abc2020-1-11def2019-11-11fdjsklf";
     // 注意點: 默認情況下在正則表達式中一旦匹配就會停止查找,后面寫個g代表全局查找
     let reg = /\d{4}-\d{1,2}-\d{1,2}/g;
     let res = str.match(reg);
     console.log(res);
     console.log(res[0]);
     console.log(res[1]);
      
      
     // 3.通過正則表達式替換符合規(guī)則的字符串
     let str = "abc2020-1-11def2019-11-11fdjsklf";
     let reg = /\d{4}-\d{1,2}-\d{1,2}/g;
     let newStr = str.replace(reg, "it666");
     console.log(str);
     console.log(newStr);
    </script>
    /*
    常用正則表達式合集:
    驗證數(shù)字:^[0-9]*$
    驗證n位的數(shù)字:^\d{n}$
    驗證至少n位數(shù)字:^\d{n,}$
    驗證m-n位的數(shù)字:^\d{m,n}$
    驗證零和非零開頭的數(shù)字:^(0|[1-9][0-9]*)$
    驗證有兩位小數(shù)的正實數(shù):^[0-9]+(.[0-9]{2})?$
    驗證有1-3位小數(shù)的正實數(shù):^[0-9]+(.[0-9]{1,3})?$
    驗證非零的正整數(shù):^\+?[1-9][0-9]*$
    驗證非零的負整數(shù):^\-[1-9][0-9]*$
    驗證非負整數(shù)(正整數(shù) + 0)  ^\d+$
    驗證非正整數(shù)(負整數(shù) + 0)  ^((-\d+)|(0+))$
    驗證長度為3的字符:^.{3}$
    驗證由26個英文字母組成的字符串:^[A-Za-z]+$
    驗證由26個大寫英文字母組成的字符串:^[A-Z]+$
    驗證由26個小寫英文字母組成的字符串:^[a-z]+$
    驗證由數(shù)字和26個英文字母組成的字符串:^[A-Za-z0-9]+$
    驗證由數(shù)字、26個英文字母或者下劃線組成的字符串:^\w+$
    
    驗證用戶密碼:^[a-zA-Z]\w{5,17}$ 正確格式為:以字母開頭,長度在6-18之間,只能包含字符、數(shù)字和下劃線。
    驗證是否含有 ^%&',;=?$\" 等字符:[^%&',;=?$\x22]+
    驗證漢字:^[\u4e00-\u9fa5],{0,}$
    驗證Email地址:^\w+[-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
    驗證InternetURL:^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$ ;^[a-zA-z]+://(w+(-w+)*)(.(w+(-w+)*))*(?S*)?$
    驗證電話號碼:^(\d3,4|\d{3,4}-)?\d{7,8}$:--正確格式為:XXXX-XXXXXXX,XXXX-XXXXXXXX,XXX-XXXXXXX,XXX-XXXXXXXX,XXXXXXX,XXXXXXXX。
    驗證身份證號(15位或18位數(shù)字):^\d{15}|\d{}18$
    驗證一年的12個月:^(0?[1-9]|1[0-2])$ 正確格式為:“01”-“09”和“1”“12”
    驗證一個月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$    正確格式為:01、09和1、31。
    整數(shù):^-?\d+$
    非負浮點數(shù)(正浮點數(shù) + 0):^\d+(\.\d+)?$
    正浮點數(shù)   ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
    非正浮點數(shù)(負浮點數(shù) + 0) ^((-\d+(\.\d+)?)|(0+(\.0+)?))$
    負浮點數(shù)  ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
    浮點數(shù)  ^(-?\d+)(\.\d+)?$
    */
    
    
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • DOM 什么是window? window是一個全局對象 指瀏覽器中的每個窗口就是window對象 什么是doc...
    風暴java之靈閱讀 479評論 0 1
  • 經過前幾篇文章的學習,對DOM有一定的了解。但這僅僅是DOM一些基礎性的知識,如果要對DOM更了解,需要更深入地了...
    一個敲代碼的前端妹子閱讀 1,265評論 0 0
  • 第3章 基本概念 3.1 語法 3.2 關鍵字和保留字 3.3 變量 3.4 數(shù)據(jù)類型 5種簡單數(shù)據(jù)類型:Unde...
    RickCole閱讀 5,489評論 0 21
  • 收集于網絡,特此整理。 多看看API,總是沒壞處~ 一、節(jié)點 1.1 節(jié)點屬性 Node.nodeName //...
    前端程序猿阿旭閱讀 5,507評論 1 1
  • 當沈慕雪踏出教導處時,走到學校一個幾乎沒有人的園子中,翹著二郎腿坐在石凳子上。這個園子空氣十分新鮮,有許多準備凋零...
    馮敏琪閱讀 608評論 3 1

友情鏈接更多精彩內容