整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          Java學(xué)科:ajax的常用參數(shù)介紹

          )url:

            要求為String類型的參數(shù),(默認(rèn)為當(dāng)前頁地址)發(fā)送請求的地址。

          2)type:

            要求為String類型的參數(shù),請求方式(post或get)默認(rèn)為get。注意其他http請求方法,例如put和delete也可以使用,但僅部分瀏覽器支持。

          3)timeout:

            要求為Number類型的參數(shù),設(shè)置請求超時時間(毫秒)。此設(shè)置將覆蓋$.ajaxSetup()方法的全局設(shè)置。

          4)async:

            要求為Boolean類型的參數(shù),默認(rèn)設(shè)置為true,所有請求均為異步請求。如果需要發(fā)送同步請求,請將此選項設(shè)置為false。

          注意,同步請求將鎖住瀏覽器,用戶其他操作必須等待請求完成才可以執(zhí)行。

          5)cache:

            要求為Boolean類型的參數(shù),默認(rèn)為true(當(dāng)dataType為script時,默認(rèn)為false),設(shè)置為false將不會從瀏覽器緩存中加載請求信息。

          6)data:

            要求為Object或String類型的參數(shù),發(fā)送到服務(wù)器的數(shù)據(jù)。如果已經(jīng)不是字符串,將自動轉(zhuǎn)換為字符串格式。get請求中將附加在url后。防止這種自動轉(zhuǎn)換,可以查看  processData(防止自動轉(zhuǎn)換)選項。對象必須為key/value格式,例如{foo1:"bar1",foo2:"bar2"}轉(zhuǎn)換為&foo1=bar1&foo2=bar2。如果是數(shù)組,JQuery將自動為不同值對應(yīng)同一個名稱。例如{foo:["bar1","bar2"]}轉(zhuǎn)換為&foo=bar1&foo=bar2。

          7)dataType:

            要求為String類型的參數(shù),預(yù)期服務(wù)器返回的數(shù)據(jù)類型。如果不指定,JQuery將自動根據(jù)http包mime信息返回responseXML或responseText,并作為回調(diào)函數(shù)參數(shù)傳遞。可用的類型如下:

            ● xml:返回XML文檔,可用JQuery處理。

            ● html:返回純文本HTML信息;包含的script標(biāo)簽會在插入DOM時執(zhí)行。

            ● script:返回純文本JavaScript代碼。不會自動緩存結(jié)果。除非設(shè)置了cache參數(shù)。注意在遠(yuǎn)程請求時(不在同一個域下),所有post請求都將轉(zhuǎn)為get請求。

            ● json:返回JSON數(shù)據(jù)。

            ● jsonp:JSONP格式。使用SONP形式調(diào)用函數(shù)時,例如myurl?callback=?,JQuery將自動替換后一個“?”為正確的函數(shù)名,以執(zhí)行回調(diào)函數(shù)。

            ● text:返回純文本字符串。

          8)beforeSend:

            這個參數(shù)主要是為了在向服務(wù)器發(fā)送請求前,執(zhí)行一些操作。要求為Function類型的參數(shù),發(fā)送請求前可以修改XMLHttpRequest對象的函數(shù),例如添加自定義HTTP頭。在beforeSend中如果返回false可以取消本次ajax請求。XMLHttpRequest對象是惟一的參數(shù)。

               function(XMLHttpRequest){
                  this;  //調(diào)用本次ajax請求時傳遞的options參數(shù)
                }

          9)complete:

            要求為Function類型的參數(shù),請求完成后調(diào)用的回調(diào)函數(shù)(請求成功或失敗時均調(diào)用)。參數(shù):XMLHttpRequest對象和一個描述成功請求類型的字符串。

               function(XMLHttpRequest, textStatus){
                 this;  //調(diào)用本次ajax請求時傳遞的options參數(shù)
               }

          10)success:

            要求為Function類型的參數(shù),請求成功后調(diào)用的回調(diào)函數(shù),有兩個參數(shù)。

          (1)由服務(wù)器返回,并根據(jù)dataType參數(shù)進(jìn)行處理后的數(shù)據(jù)。

          (2)描述狀態(tài)的字符串。

               function(data, textStatus){
                //data可能是xmlDoc、jsonObj、html、text等等
                this; //調(diào)用本次ajax請求時傳遞的options參數(shù)
               }

          11)error:

          要求為Function類型的參數(shù),請求失敗時被調(diào)用的函數(shù)。該函數(shù)有3個參數(shù),即XMLHttpRequest對象、錯誤信息、捕獲的錯誤對象(可選)。ajax事件函數(shù)如下:

              function(XMLHttpRequest, textStatus, errorThrown){
               //通常情況下textStatus和errorThrown只有其中一個包含信息
               this;  //調(diào)用本次ajax請求時傳遞的options參數(shù)
              }

          12)contentType:

          要求為String類型的參數(shù),當(dāng)發(fā)送信息至服務(wù)器時,內(nèi)容編碼類型默認(rèn)為"application/x-www-form-urlencoded"。該默認(rèn)值適合大多數(shù)應(yīng)用場合。

          13)dataFilter:

          要求為Function類型的參數(shù),給Ajax返回的原始數(shù)據(jù)進(jìn)行預(yù)處理的函數(shù)。提供data和type兩個參數(shù)。data是Ajax返回的原始數(shù)據(jù),type是調(diào)用jQuery.ajax時提供的dataType參數(shù)。函數(shù)返回的值將由jQuery進(jìn)一步處理。

                function(data, type){
                  //返回處理后的數(shù)據(jù)
                  return data;
                }

          14)dataFilter:

          要求為Function類型的參數(shù),給Ajax返回的原始數(shù)據(jù)進(jìn)行預(yù)處理的函數(shù)。提供data和type兩個參數(shù)。data是Ajax返回的原始數(shù)據(jù),type是調(diào)用jQuery.ajax時提供的dataType參數(shù)。函數(shù)返回的值將由jQuery進(jìn)一步處理。

             function(data, type){
                  //返回處理后的數(shù)據(jù)
                  return data;
                }

          15)global:

          要求為Boolean類型的參數(shù),默認(rèn)為true。表示是否觸發(fā)全局ajax事件。設(shè)置為false將不會觸發(fā)全局ajax事件,ajaxStart或ajaxStop可用于控制各種ajax事件。

          16)ifModified:

          要求為Boolean類型的參數(shù),默認(rèn)為false。僅在服務(wù)器數(shù)據(jù)改變時獲取新數(shù)據(jù)。服務(wù)器數(shù)據(jù)改變判斷的依據(jù)是Last-Modified頭信息。默認(rèn)值是false,即忽略頭信息。

          17)jsonp:

          要求為String類型的參數(shù),在一個jsonp請求中重寫回調(diào)函數(shù)的名字。該值用來替代在"callback=?"這種GET或POST請求中URL參數(shù)里的"callback"部分,例如{jsonp:'onJsonPLoad'}會導(dǎo)致將"onJsonPLoad=?"傳給服務(wù)器。

          18)username:

          要求為String類型的參數(shù),用于響應(yīng)HTTP訪問認(rèn)證請求的用戶名。

          19)password:

          要求為String類型的參數(shù),用于響應(yīng)HTTP訪問認(rèn)證請求的密碼。

          20)processData:

          要求為Boolean類型的參數(shù),默認(rèn)為true。默認(rèn)情況下,發(fā)送的數(shù)據(jù)將被轉(zhuǎn)換為對象(從技術(shù)角度來講并非字符串)以配合默認(rèn)內(nèi)容類型"application/x-www-form-urlencoded"。如果要發(fā)送DOM樹信息或者其他不希望轉(zhuǎn)換的信息,請設(shè)置為false。

          21)scriptCharset:

          要求為String類型的參數(shù),只有當(dāng)請求時dataType為"jsonp"或者"script",并且type是GET時才會用于強(qiáng)制修改字符集(charset)。通常在本地和遠(yuǎn)程的內(nèi)容編碼不同時使用。

          JAX學(xué)習(xí)筆記

          在現(xiàn)代的Web開發(fā)中,AJAX(Asynchronous JavaScript and XML)已經(jīng)成為不可或缺的一部分。它使我們能夠在不刷新整個頁面的情況下與服務(wù)器進(jìn)行通信,為用戶提供更流暢的體驗。然而,要真正掌握AJAX,我們需要了解JavaScript中的同步與異步編程、Promise對象以及如何使用強(qiáng)大的axios庫來簡化AJAX請求。在這篇推文中,我們將深入探討這些概念,幫助你更好地理解和利用AJAX的潛力。讓我們開始這段AJAX之旅吧!

          概念:

          定義:AJAX是異步的JavaScript與XML,使用XMLHttpRequest對象與服務(wù)器通信;

          一、axios的使用:

          Axios是一個基于promise構(gòu)建的一個網(wǎng)絡(luò)請求庫,可以用于瀏覽器和node.js

          1.引入axios.js

          <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

          2.使用axios函數(shù)

          (1)傳入配置對象

          (2)使用.then回調(diào)函數(shù)接收結(jié)果,并做后續(xù)處理

          axios({
           url:'目標(biāo)資源地址'
          }).then(result=>{
           // 對服務(wù)器返回的數(shù)據(jù)做后續(xù)處理
          })

          3.案例:獲取API中的省份列表,并在段落中顯示出來;

          <!doctype html>
          <html lang="zh-cmn-Hans">
          <head>
              <meta charset="utf-8">
          <link rel="icon" href="./img/favicon.ico">
              <title>axios使用</title>
              <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
          </head>
          <body>
               <p class="my-p"></p>
          </body>
          <script>
              axios({
                  url:'http://hmajax.itheima.net/api/province'
              }).then(result=>{
                  // 對服務(wù)器返回的數(shù)據(jù)做后續(xù)處理
                  console.log(result.data.list.join('<br>'));
                  // 把準(zhǔn)備好的省份列表插入到頁面
                  document.querySelector('.my-p').innerHTML = result.data.list.join('<br>');
              })
          </script>
          </html>

          二、URL統(tǒng)一資源定位符

          1.URL的概念

          url是什么?URL是統(tǒng)一資源定位符,用于訪問服務(wù)器上的資源;結(jié)構(gòu)由協(xié)議、域名、資源路徑組成;

          2.URL查詢參數(shù)

          url參數(shù)查詢語法:

          http://xxx.com/xxx/xxx?參數(shù)名1=值1&參數(shù)名2=值2

          3.axios查詢參數(shù)

          使用axios提供的params選項:

          axios({
              url:'目標(biāo)資源地址',
              params:{
                  參數(shù)名:值
              }
          }).then(result=>{
              // 對服務(wù)器返回的數(shù)據(jù)做后續(xù)處理
          })

          實(shí)際上axios在運(yùn)行時會把params中的內(nèi)容自動拼接到url?參數(shù)名=值上面;

          4.案例:地區(qū)查詢

          在ES6中如果屬性名和變量同名,可以只寫一個;

          通過省份和城市名查詢該城市的所有區(qū)縣;

          document.querySelector('.sel-btn').addEventListener('click',() => {
            let pname = document.querySelector('.province').value;
            let cname = document.querySelector('.city').value;
            // 基于axios獲取服務(wù)器數(shù)據(jù)
            axios({
              url: "http://hmajax.itheima.net/api/area",
              params: {
                pname,
                cname
              }
            }).then(result => {
              let list = result.data.list;
              // 利用map函數(shù)將list映射到新的列表中theLi中
              let theLi = list.map(areaName => `<li class="list-group-item">${areaName}</li>`).join('')
              console.log(theLi);
              //將結(jié)果插入到元素中顯示出來
              document.querySelector('.list-group').innerHTML = theLi;
            })
          })

          5.常用的請求方法

          axios配置請求方法怎么寫?

          GET方法是默認(rèn)的可以省略,在參數(shù)列表中,如果是get方法則用params,如果是post方法則用data;

          axios({
              url:'目標(biāo)資源地址',
              method:'請求方法',
              params:{
                  參數(shù)名:值
              }
          }).then(result=>{
              // 對服務(wù)器返回的數(shù)據(jù)做后續(xù)處理
          })

          6.axios錯誤處理

          在axios請求錯誤時,通過調(diào)用catch方法傳入回調(diào)函數(shù)并定義形參;例如在用戶注冊失敗時,通過彈窗提示用戶錯誤原因。

          axios({
            // 請求選項
          }).then(result=>{
            // 對服務(wù)器返回的數(shù)據(jù)做后續(xù)處理
          }).catch(error=>{
            // 處理錯誤
          })

          三、http協(xié)議

          1.請求報文

          Http協(xié)議:規(guī)定了瀏覽器發(fā)送以及服務(wù)器返回內(nèi)容的格式;

          請求報文:瀏覽器按照Http協(xié)議要求的格式,發(fā)送給服務(wù)器的內(nèi)容

          請求報文的組成部分有:

          • 請求行:請求方法、URL、協(xié)議
          • 請求頭:以鍵值對的格式攜帶附加的信息
          • 空行:分隔請求頭,空行之后是發(fā)送給服務(wù)器的資源、
          • 請求體:發(fā)送的資源

          在瀏覽器中怎么查看請求報文:

          在瀏覽器的瀏覽器開發(fā)者工具的網(wǎng)絡(luò)面板中,選擇Fetch/XHR中查看,

          請求行和請求頭在標(biāo)頭選項中,請求體在載荷選項中;

          在故障排查時可以查看請求報文的請求體內(nèi)容是否正確;

          2.響應(yīng)報文

          響應(yīng)報文的組成部分有:

          • 響應(yīng)行(狀態(tài)行):協(xié)議、HTTP響應(yīng)狀態(tài)碼、狀態(tài)信息
          • 響應(yīng)頭:以鍵值對的格式攜帶附加信息,比如:Content-Type
          • 空行:分隔響應(yīng)頭,空行之后是服務(wù)器返回的資源
          • 響應(yīng)體:返回的資源

          HTTP響應(yīng)狀態(tài)碼:用來表明請求是否成功,主要含義如下:

          四.接口文檔案例

          根據(jù)后端的接口文檔,前端使用ajax進(jìn)行調(diào)用;

          示例API文檔:https://apifox.com/apidoc/project-1937884/doc-1695440

          1.案例-用戶登錄

          • 點(diǎn)擊登錄時,判斷用戶名和密碼長度;
          • 提交數(shù)據(jù)和服務(wù)器通信
          • 提示消息
          // 點(diǎn)擊登錄時,用戶名和密碼長度判斷,并提交數(shù)據(jù)和服務(wù)器通信
          // 定義一個函數(shù)用于顯示提示框
          function showAlert(msg, isSuccess) {
          const alert = document.querySelector(".alert");
          let alertStyle = isSuccess ? "alert-success" : "alert-danger";
          alert.innerHTML = msg;
          alert.classList.add("show");
          alert.classList.add(alertStyle);
          // 設(shè)置一個定時器3s后隱藏提示框
          setTimeout(() => {
          alert.classList.remove("show");
          alert.classList.remove(alertStyle);
          }, 3000);
          }
          // 登錄點(diǎn)擊事件
          document
          .querySelector(".btn-login")
          .addEventListener("click", function () {
          // 獲取用戶名和密碼
          const username = document.querySelector(".username").value;
          const password = document.querySelector(".password").value;
          // 對長度做判斷
          if (username.length < 8) {
          console.log("用戶名長度不能低于8");
          showAlert("用戶名長度不能低于8", false);
          return;
          }
          if (password.length < 6) {
          console.log("密碼長度不能低于6");
          showAlert("密碼長度不能低于6", false);
          return;
          }
          axios({
          method: "post",
          url: "http://hmajax.itheima.net/api/login",
          data: {
              username,
              password,
          },
          })
          .then((result) => {
              console.log(result.data.message);
              showAlert(result.data.message, true);
          })
          .catch((error) => {
              console.log(error.response.data.message);
              showAlert(error.response.data.message, false);
          });
          });

          2.form-serialize插件

          使用form-serialize插件快速收集表單元素的值,獲取結(jié)果的鍵值對,根據(jù)表單元素中的name屬性獲取鍵;

          語法:

          const data = serialize(form, {hash: true, empty:true})
          /**
           * 使用serialize函數(shù),快速收集表單元素的值
           *  參數(shù)1:要獲取的表單名稱;
           *  參數(shù)2:配置對象 
           *       hash:設(shè)置獲取數(shù)據(jù)結(jié)構(gòu)
           *          - false:獲取到的是url查詢字符串
           *          - true:獲取到的是JS對象
           *       empty:設(shè)置是否獲取空值
           *          - false: 不獲取空值
           *          - true: 可以獲取到空值
          */

          使用方法:

          引入插件,調(diào)用serialize方法獲取到表單元素的值,表單元素的name屬性會成為返回對象的屬性名;

          將上面用戶登錄的案例利用form-serialize插件獲取表單的值,下面是實(shí)際的寫法:

          // 點(diǎn)擊登錄時,用戶名和密碼長度判斷,并提交數(shù)據(jù)和服務(wù)器通信
          // 定義一個函數(shù)用于顯示提示框
          function showAlert(msg, isSuccess) {
          const alert = document.querySelector(".alert");
          let alertStyle = isSuccess ? "alert-success" : "alert-danger";
          alert.innerHTML = msg;
          alert.classList.add("show");
          alert.classList.add(alertStyle);
          // 設(shè)置一個定時器3s后隱藏提示框
          setTimeout(() => {
          alert.classList.remove("show");
          alert.classList.remove(alertStyle);
          }, 3000);
          }
          // 登錄點(diǎn)擊事件
          document
          .querySelector(".btn-login")
          .addEventListener("click", function () {
          // 使用form-serialize插件
          const form = document.querySelector(".form-example");
          const data = serialize(form, { hash: true, empty: true });
          // 使用解構(gòu)賦值的方式獲取對象中用戶名和密碼
          const { username, password } = data;
          // 對長度做判斷
          if (username.length < 8) {
          console.log("用戶名長度不能低于8");
          showAlert("用戶名長度不能低于8", false);
          return;
          }
          if (password.length < 6) {
          console.log("密碼長度不能低于6");
          showAlert("密碼長度不能低于6", false);
          return;
          }
          axios({
          method: "post",
          url: "http://hmajax.itheima.net/api/login",
          data: {
              username,
              password,
          },
          })
          .then((result) => {
              console.log(result.data.message);
              showAlert(result.data.message, true);
          })
          .catch((error) => {
              console.log(error.response.data.message);
              showAlert(error.response.data.message, false);
          });
          });
          

          3.Bootstrap彈框

          功能:不離開當(dāng)前頁面,顯示單獨(dú)內(nèi)容,供用戶操作;調(diào)用彈窗可以通過兩種方式:屬性控制和JS控制;

          使用方法:

          (1)引入bootstrap.css與bootstrap.js

          (2)給啟動彈框的組件添加bootstrap屬性,顯示彈框需要兩個屬性,分別是data-bs-toggledata-bs-target

          <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target=".my-box">顯示彈框</button>
          

          (3)通過自定義屬性,控制彈框的顯示和隱藏,隱藏彈框需要設(shè)置屬性data-bs-dismiss="modal"

          通過屬性控制彈窗的顯示和隱藏具體寫法如下:

          <div class="container mt-3">
              <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target=".my-box">顯示彈框</button>
              <!-- 彈框標(biāo)簽 -->
              <div class="modal my-box" tabindex="-1">
                  <div class="modal-dialog">
                      <div class="modal-content">
                          <div class="modal-header">
                              <h5 class="modal-title">請輸入姓名</h5>
                              <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                          </div>
                          <div class="modal-body">
                              <span>姓名</span>
                              <input type="text" class="form-contorl" placeholder="默認(rèn)姓名">
                          </div>
                          <div class="modal-footer">
                              <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
                                  取消
                              </button>
                              <button type="button" class="btn btn-primary">
                                  保存
                              </button>
                          </div>
                      </div>
                  </div>
              </div>
          </div>
          

          通過JS控制,顯示或隱藏彈框:

          // 創(chuàng)建彈框?qū)ο?const modalDom = document.querySelector('.my-box');
          const modal = new bootstrap.Modal(modalDom);
          // 顯示彈框
          modal.show();
          // 隱藏彈框
          modal.hide();

          4.案例:圖書管理管理系統(tǒng)

          獲取圖書列表的的API地址http://hmajax.itheima.net/api/books

          a.獲取內(nèi)容并渲染到網(wǎng)頁上

          這里重點(diǎn)需要掌握的技巧是使用map將列表對象中的元素映射到html元素中,并進(jìn)行字符串拼接的過程。map函數(shù)可以傳入三個參數(shù)(element、index、array),具體用法可見:https://www.freecodecamp.org/chinese/news/javascript-map-how-to-use-the-js-map-function-array-method/

          window.addEventListener('load',()=>{
              const creator = '小雨';
              // 封裝一個函數(shù),獲取并渲染圖書列表
              function getBookList(){
                  axios({
                      url: 'http://hmajax.itheima.net/api/books',
                      params: {
                          creator,
                      }
                  }).then(result => {
                      const bookList = result.data.data;
                      console.log(bookList);
                      const bookItemHtml = bookList.map((item,index) => {
                          return `<tr>
                          <td>${index + 1}</td>
                          <td>${item.bookname}</td>
                          <td>${item.author}</td>
                          <td>${item.publisher}</td>
                          <td>
                              <span class="del">刪除</span>
                              <span class="edit">編輯</span>
                          </td>
                      </tr>`
                      }).join('');
                      document.querySelector('.list').innerHTML = bookItemHtml;
                  })
              }
              // 執(zhí)行函數(shù)
              getBookList()
          })

          b.添加圖書信息

          // 目標(biāo)2:添加圖書信息
              // 獲取彈窗信息
          const addModalDom = document.querySelector('.add-modal');
          const addModal = new bootstrap.Modal(addModalDom);
          document.querySelector('.add-btn').addEventListener('click',()=>{
              // 獲取表單信息
              const bookItemForm = document.querySelector('.add-form');
              const bookItem = serialize(bookItemForm,{hash:true,empty:true});
              // 提交表單信息
              axios({
                  url: 'http://hmajax.itheima.net/api/books',
                  method: 'post',
                  data:{
                      // 這里的...是對象展開運(yùn)算符
                      ...bookItem,
                      // 這里的creator是一個全局變量
                      creator
                  }
              }).then(result => {
                  // 添加成功后請求重新渲染頁面
                  getBookList();
                  // 重置表單,防止點(diǎn)擊添加按鈕后,上一次添加的內(nèi)容還在
                  bookItemForm.reset();
                  // 隱藏彈框
                  addModal.hide();
              })
          });

          c.刪除圖書信息

          思路:

          a.綁定點(diǎn)擊事件獲取圖書id

          b.調(diào)用刪除接口

          c.刷新圖書列表

          由于每一行圖書信息是動態(tài)生成的,如果給每一行圖書的刪除按鈕添加點(diǎn)擊事件,則需要委托其父級元素設(shè)置點(diǎn)擊事件。再定義一個判斷條件如果點(diǎn)擊的元素中含有del類,則獲取其父元素的id

          在渲染圖書列表時就給刪除按鈕的父級元素創(chuàng)建一個自定義屬性data-id,在點(diǎn)擊事件中,查詢父元素的id屬性即可通過AJAX刪除指定ID的元素列表;

          在接口文檔中看到需要提供PATH參數(shù),這是一種新的傳參方式(路徑傳參)

          將URL改為模板字符串即可。

          // 目標(biāo)3:刪除圖書信息
          document.querySelector('.list').addEventListener('click',function(e) {
              if(e.target.classList.contains('del')){
                  // 獲取圖書id
                  const id = e.target.parentNode.dataset.id;
                  console.log(id);
                  // 調(diào)用刪除接口
                  axios({
                      method: 'delete',
                      url: `http://hmajax.itheima.net/api/books/${id}`,
                  }).then(result =>{
                      // 刷新圖書列表
                      getBookList();
                  });
              }
          })

          d.編輯圖書信息

          實(shí)現(xiàn)該功能主要需要完成以下部分的內(nèi)容:

          編輯彈窗的顯示和隱藏;

          獲取當(dāng)前圖書的ID并通過查詢接口獲取圖書信息填充到彈窗中;

          點(diǎn)擊提交按鈕時,提交表單中的內(nèi)容到后臺,并重新渲染前端頁面內(nèi)容;

          // 目標(biāo)4:編輯圖書信息
          // 獲取編輯彈窗信息
          const editModalDom = document.querySelector('.edit-modal');
          const editModal = new bootstrap.Modal(editModalDom);
          document.querySelector('.list').addEventListener('click',function(e){
              if(e.target.classList.contains('edit')){
                  // 點(diǎn)擊編輯按鈕打開彈框
                  editModal.show();
                  // 獲取圖書id
                  const theId = e.target.parentNode.dataset.id;
                  // 獲取圖書詳情信息
                  axios({
                      url: `http://hmajax.itheima.net/api/books/${theId}`,
                  }).then(result => {
                      const bookObj = result.data.data;
                      const keys = Object.keys(bookObj);
                      console.log(keys);
                      keys.forEach(key => {
                          document.querySelector(`.edit-form .${key}`).value = bookObj[key];
                      });
                  });
              }
          })
          // 點(diǎn)擊修改按鈕后保存數(shù)據(jù)提交到服務(wù)器
          document.querySelector('.edit-btn').addEventListener('click',function(){
              // 獲取編輯表單信息
              const editForm = document.querySelector('.edit-form');
              // 保存修改后的表單內(nèi)容
              const {id,bookname,author,publisher} = serialize(editForm,{hash:true,empty:true});
              // 將表單中的內(nèi)容提交到服務(wù)器
              axios({
                      method: 'put',
                      url: `http://hmajax.itheima.net/api/books/${id}`,
                      data: {
                          id,
                          bookname,
                          author,
                          publisher,
                          creator
                      }
                  }).then(() => {
                      // 刷新頁面
                      getBookList();
                      // 隱藏彈窗
                      editModal.hide();
                  });
          })
          

          5.案例:圖片上傳

          圖片上傳的思路:

          (1)獲取圖片文件對象

          給input標(biāo)簽添加一個change事件;

          (2)使用FormData攜帶圖片文件

          const fd = new FormData()
          fd.append(參數(shù)名,值)
          

          (3)提交表單數(shù)據(jù)到服務(wù)器

          通過ajax將圖片提交到服務(wù)器,并拿到后端返回的圖片URL;

          document.querySelector('.upload').addEventListener('change',(e)=>{
              // 獲取圖片文件
              console.log(e.target.files[0]);
              // 使用FormData攜帶圖片文件
              const fd = new FormData();
              fd.append('img',e.target.files[0])
              // 提交到服務(wù)器
              axios({
                  url: 'http://hmajax.itheima.net/api/uploadimg',
                  method: 'POST',
                  data: fd
              }).then(result => {
                  console.log(result.data.data);
                  const imgurl = result.data.data.url;
                  document.querySelector('.my-img').src = imgurl;
              })
          })
          

          6.案例:更換網(wǎng)站背景

          實(shí)現(xiàn)一個案例,點(diǎn)擊按鈕上傳圖片,并替換網(wǎng)頁背景,頁面刷新后依然不變;

          思路:

          • 設(shè)置一個file類型的input標(biāo)簽,選中本地圖片后,添加一個change事件,將圖片以FormData的方式通過Ajax提交到后端服務(wù)器;
          • 獲取后端返回的url,給body標(biāo)簽賦予backgroundImage屬性,從而實(shí)現(xiàn)背景圖片的更換;
          • 上傳成功后保存url到本地存儲localStorage.setItem(key,value)
          window.addEventListener('load',() => {
              // 邏輯
              document.querySelector('.bg-ipt').addEventListener('change',e => {
                  console.log(e.target.files[0]);
                  const fd = new FormData();
                  fd.append('img',e.target.files[0])
                  // 通過Ajax將圖片傳給后端服務(wù)器
                  axios({
                      method: 'POST',
                      url:'http://hmajax.itheima.net/api/uploadimg',
                      data: fd,
                  }).then(result => {
                      console.log(result);
                      const imgURL = result.data.data.url;
                      console.log(imgURL);
                      document.querySelector('body').style.backgroundImage = `url(${imgURL})`;
                      // 將URL存到本地
                      localStorage.setItem('backImg',imgURL);
                  })
              })
              // 網(wǎng)頁運(yùn)行后獲取url地址
              const bgUrl = localStorage.getItem('backImg');
              bgUrl && (document.querySelector('body').style.backgroundImage = `url(${bgUrl})`);
          })
          

          7.案例:個人信息設(shè)置

          實(shí)現(xiàn)效果:

          該案例可以分為四個主要步驟:

          a.信息渲染

          const creator = "xiaoyu";
          function getProfile() {
              axios({
                  url: 'http://hmajax.itheima.net/api/settings',
                  params:{
                      creator
                  }
              }).then(result => {
                  // 獲取個人信息
                  const profile = result.data.data;
                  // 遍歷個人信息屬性并顯示到頁面中
                  Object.keys(profile).forEach(key => {
                      // 對于性別和頭像需要特殊處理
                      if(key === 'avatar'){
                          document.querySelector('.prew').src = profile.avatar;
                      }else if(key === 'gender'){
                          const genderList = document.querySelectorAll('.gender');
                          genderList[profile.gender].checked = true;
                      }else{
                          document.querySelector(`.${key}`).value = profile[key];
                      }
                  });
              });
          }
          

          b.頭像修改

          在做的這一步的時候,總是提交出錯,原因是沒有看清api文檔中的參數(shù)要求

          需要在整個FormData對象里append兩個對象avatar和creator;

          document.querySelector('.upload').addEventListener('change',(e) => {
              const fd = new FormData();
              fd.append('avatar',e.target.files[0]);
              fd.append('creator',creator);
              axios({
                  url: "http://hmajax.itheima.net/api/avatar",
                  method: "PUT",
                  data:fd,
              }).then(result => {
                  document.querySelector('.prew').src = result.data.data.avatar;
              });
          });

          c.提交表單

          這里需要注意給要提交的的對象添加一個屬性,以及將字符串型的“0”轉(zhuǎn)為整型的“0”

          document.querySelector('.submit').addEventListener('click',() => {
              const form = document.querySelector('.user-form');
              const newProfile = serialize(form,{hash:true,empty:true});
              // 對象可以通過賦值的方式添加屬性
              newProfile.creator = creator;
              // 將字符串型的“0”轉(zhuǎn)為整型的“0”
              newProfile.gender = +newProfile.gender;
             
              axios({
                  url: 'http://hmajax.itheima.net/api/settings',
                  method: 'put',
                  data:{
                      ...newProfile,
                  }
              }).then(result => {
                  console.log(result);
              });
          });

          d.結(jié)果提示

          這里需要將提交成功的toast顯示出來,如何使用Bootstrap顯示提示框呢?

          <div class="toast" data-bs-delay="1500">
            提示框內(nèi)容
          </div>
          const toastDom = document.querySelector('css選擇器');
          // 創(chuàng)建提示框?qū)ο?const toast = new bootstrap.Toast(toastDom);
          // 顯示提示框
          toast.show()

          實(shí)際寫法:

          <!-- toast提示框 -->
          <div class="toast my-toast" data-bs-delay="1500">
              <div class="toast-body">
                  <div class="alert alert-success info-box">
                      操作成功
                  </div>
              </div>
          </div>
          const toastDom = this.document.querySelector('.my-toast');
          const toast = new bootstrap.Toast(toastDom);
          toast.show()

          五、XMLHttpRequest

          定義:XMLHttpRequest(XHR)對象用于與服務(wù)器交互,通過XMLHttpRequest可以在不刷新頁面的情況下請求特定URL,獲取數(shù)據(jù),這允許網(wǎng)頁在不影響用戶操作的情況下,更新頁面的布局內(nèi)容。在AJAX編程中被大量使用;

          使用XMLHttpRequest的方法:

          // 創(chuàng)建xhr對象
          const xhr = new XMLHttpRequest()
          xhr.open('請求方法','url網(wǎng)址')
          xhr.addEventListener('loadend',() => {
            // 輸出響應(yīng)結(jié)果
            console.log(xhr.response)
          })
          // 正式發(fā)送請求
          xhr.send()

          使用axios返回的結(jié)果是對象,而原生的XHR返回的是JSON字符串,如果需要將JSON字符串轉(zhuǎn)化為對象可以使用JSON.parse()的方式;

          XHR如果需要攜帶查詢參數(shù)則直接在URL里設(shè)置;

          1. 案例:使用XHR獲取并展示所有省份的名字

          document.querySelector('.my-btn').addEventListener('click',() => {
              const xhr = new XMLHttpRequest();
              xhr.open('get','http://hmajax.itheima.net/api/province');
              xhr.addEventListener('loadend',() =>{
                  const data = JSON.parse(xhr.response);
                  console.log(xhr.response);
                  document.querySelector('.res').innerHTML = data.list.join('</br>');
              });
              xhr.send();
          })

          2.案例:使用XHR獲取并展示制定城市的地區(qū)列表

          知識拓展:對于多參數(shù)查詢字符串,是可以根據(jù)對象名生成的。

          // 創(chuàng)建URLSearchParams對象
          const paramsObj = new URLSearchParams({
            參數(shù)名1:值1,
            參數(shù)名2:值2
          })
          // 生成指定格式的查詢字符串
          const queryString = paramsObj.toString()
          // 結(jié)果:參數(shù)名1=值1&參數(shù)名2=值2
          document.querySelector('.my-btn').addEventListener('click',() => {
              const formDom = document.querySelector('.user-form');
              const form = serialize(formDom,{hash:true,empty:true});
              const pname = form.province;
              const cname = form.city;
              // 獲取xhr查詢參數(shù)
              const paramsObj = new URLSearchParams({
                      pname:pname,
                      cname:cname
                  }
              );
              const queryURL = paramsObj.toString();
              const xhr = new XMLHttpRequest();
              xhr.open('get',`http://hmajax.itheima.net/api/area/?${queryURL}`);
              xhr.addEventListener('loadend',()=>{
                  // JSON.parse()將JSON字符串轉(zhuǎn)為JS對象
                  const resObj = JSON.parse(xhr.response);
                  const resItem = resObj.list.map(function (areaName) {
                      return `<li class="list-group-item">${areaName}</li>`
                  }).join('');
                  console.log(resItem); 
                  document.querySelector('.list-group-item').innerHTML = resItem;
              });
              xhr.send();
          })

          3.案例:使用XHR完成數(shù)據(jù)提交的功能

          使用方法:

          // 告訴服務(wù)器需要傳遞的內(nèi)容類型是JSON字符串
          xhr.setRequestHeader('Content-Type','application/json')
          // JSON.stringify將JS對象轉(zhuǎn)為JSON字符串
          const user = {key1:value1,key2:value2};
          const userStr = JSON.stringify(user);
          // 發(fā)送請求體數(shù)據(jù)
          xhr.send(userStr)

          實(shí)際用法:

          document.querySelector('.my-btn').addEventListener('click',() => {
              const formDom = document.querySelector('.user-form');
              const form = serialize(formDom,{hash:true,empty:true});
              const pname = form.province;
              const cname = form.city;
              // 獲取xhr查詢參數(shù)
              const paramsObj = new URLSearchParams({
                      pname:pname,
                      cname:cname
                  }
              );
              const queryURL = paramsObj.toString();
              const xhr = new XMLHttpRequest();
              xhr.open('get',`http://hmajax.itheima.net/api/area/?${queryURL}`);
              xhr.addEventListener('loadend',()=>{
                  const resItem = JSON.parse(xhr.response).list.map(function (areaName) {
                      return `<li class="list-group-item">${areaName}</li>`
                  }).join('');
                  console.log(resItem); 
                  document.querySelector('.list-group-item').innerHTML = resItem;
              });
              xhr.send();
          })

          六、Promise對象

          定義:Promise對象用于表示一個異步操作的最終結(jié)果值;

          使用Promise的好處:

          可以鏈?zhǔn)秸{(diào)用

          用法

          // 1.創(chuàng)建Promise對象
          const p = new Promise((resove,reject) => {
            // 2.執(zhí)行異步任務(wù),并傳遞結(jié)果
            setTimeout(() => {
              // resove('模擬成功結(jié)果');
              // reject(new Error('模擬失敗結(jié)果'))
            },2000);
          })
          p.then(result => {
            // 成功
            console.log(result);
          }).catch(error => {
            // 失敗
            console.log(error);
          })

          1. Promise的三種狀態(tài)

          2.案例:使用Promise+XHR獲取省份列表

          需求:使用Promise管理XHR獲取省份列表,并展示到頁面上

          實(shí)現(xiàn):

          // 1.創(chuàng)建Promise對象
          const p = new Promise((resolve,reject) => {
              // 2.執(zhí)行XHR異步代碼,獲得省份列表
              const xhr = new XMLHttpRequest();
              xhr.open('get','http://hmajax.itheima.net/api/province');
              xhr.addEventListener('loadend',() => {
                  // 根據(jù)XHR返回的結(jié)果,轉(zhuǎn)為對象分別給resolve和reject函數(shù)作為參數(shù)傳進(jìn)去
                  if(xhr.status >= 200 && xhr.status < 300){
                      resolve(JSON.parse(xhr.response));
                  }else{
                      reject(new Error(xhr.response));
                  }
              });
              xhr.send();
          });
          // 3.關(guān)聯(lián)成功或失敗函數(shù)做后續(xù)處理,result和error為上面?zhèn)魅氲膮?shù)對象
          p.then(result => {
              document.querySelector('.my-p').innerHTML = result.list.join('</br>');
          }).catch(error => {
              console.dir(error);
              document.querySelector('.my-p').innerHTML = error.message;
          })
          

          3.使用XHR與Promise封裝自定義的axios

          案例1:實(shí)現(xiàn)獲取省份列表

          需求:通過Promise和XHR實(shí)現(xiàn)對axios的自定義封裝,完成返回省份列表的獲取;

          思路:

          Step1:封裝myAxios函數(shù),傳入config配置對象,返回Promise對象;

          Step2:發(fā)起xhr請求,定義默認(rèn)方法為get,定義接收URL參數(shù);

          Step3:定義成功或失敗請求的處理程序,將傳入結(jié)果對象

          Step4:實(shí)際調(diào)用自封裝的函數(shù),檢查效果

          function myAxios(config) {
              // 1. 定義myAxios函數(shù),接受配置對象,返回Promise對象
              const p = new Promise((resolve,reject) => {
                  // 2.發(fā)起xhr請求
                  const xhr = new XMLHttpRequest();
                  xhr.open(config.method || 'get',config.url);
                  xhr.addEventListener('loadend',() => {
                      // 3.判斷響應(yīng)結(jié)果
                      if(xhr.status >= 200 && xhr.status < 300){
                          return resolve(JSON.parse(xhr.response));
                      }else{
                          return reject(new Error(xhr.response));
                      }
                  });
                  xhr.send();
              });
              return p;   
          }
          // 4.調(diào)用自封裝的my-axios
          myAxios({
              url: 'http://hmajax.itheima.net/api/province',
          }).then(result => {
              document.querySelector('.my-p').innerHTML = result.list.join('</br>');
          }).catch(error => {
              document.querySelector('.my-p').innerHTML = error.message;
          })

          案例2:實(shí)現(xiàn)獲取地區(qū)列表

          需求:修改myAxios函數(shù),支持傳遞params參數(shù),完成地區(qū)列表的查詢

          思路:需要考慮自定義的axios對傳入的params參數(shù)的支持,可以借助URLSearchParams實(shí)現(xiàn)將params參數(shù)轉(zhuǎn)為URL連接;

          function myAxios(config) {
              // 1. 定義myAxios函數(shù),接受配置對象,返回Promise對象
              return new Promise((resolve,reject) => {
                  // 2.對params進(jìn)行處理,前提是有params參數(shù)
                  if(config.params){
                      const paramsObj = new URLSearchParams(config.params);
                      const queryString = paramsObj.toString();
                      config.url += `?${queryString}`;
                  }
                  // 3.發(fā)起xhr請求
                  const xhr = new XMLHttpRequest();
                  xhr.open(config.method || 'get',config.url);
                  xhr.addEventListener('loadend',() => {
                      // 4.判斷響應(yīng)結(jié)果
                      if(xhr.status >= 200 && xhr.status < 300){
                          return resolve(JSON.parse(xhr.response));
                      }else{
                          return reject(new Error(xhr.response));
                      }
                  });
                  xhr.send();
              });         
          }
          

          案例3:實(shí)現(xiàn)注冊用戶功能

          需求:修改myAxios函數(shù),支持傳遞請求體數(shù)據(jù),完成用戶注冊功能;

          思路:

          Step1:myAxios函數(shù)調(diào)用后,判斷data選項

          Step2:轉(zhuǎn)換數(shù)據(jù)類型,在send方法中發(fā)送

          Step3:使用自己封裝的myAxios完成用戶注冊功能

          實(shí)現(xiàn):

          function myAxios(config) {
              // 1. 定義myAxios函數(shù),接受配置對象,返回Promise對象
              return new Promise((resolve,reject) => {
                  // 2.對params進(jìn)行處理,前提是有params參數(shù)
                  if(config.params){
                      const paramsObj = new URLSearchParams(config.params);
                      const queryString = paramsObj.toString();
                      config.url += `?${queryString}`;
                  }
                  
                  // 3.發(fā)起xhr請求
                  const xhr = new XMLHttpRequest();
                  xhr.open(config.method || 'get',config.url);
                  xhr.addEventListener('loadend',() => {
                      // 4.判斷響應(yīng)結(jié)果
                      if(xhr.status >= 200 && xhr.status < 300){
                          return resolve(JSON.parse(xhr.response));
                      }else{
                          return reject(new Error(xhr.response));
                      }
                  });
                  // 對data進(jìn)行處理
                  if(config.data){
                      const jsonString = JSON.stringify(config.data);
                      xhr.setRequestHeader('Content-Type','application/json')
                      xhr.send(jsonString);
                  }else{
                      xhr.send();
                  }
              });         
          }
          document.querySelector('.my-btn').addEventListener('click',() => {
              // 5.調(diào)用自封裝的my-axios
              myAxios({
                  url: 'http://hmajax.itheima.net/api/register',
                  method: 'post',
                  data: {
                      username: 'xiaoyu1927',
                      password: '7654321'
                  }
              }).then(result => {
                  console.log(result);
                  alert(result.message);
              }).catch(error => {
                  console.dir(error);
                  alert(error.message);
              })
          })

          4.案例:天氣預(yù)報

          步驟:

          Step1:默認(rèn)獲取北京市天氣數(shù)據(jù),并展示;

          這一步其實(shí)就是通過axios獲取后端數(shù)據(jù),并顯示到html頁面中,${}將網(wǎng)頁中的元素替換為JS對象屬性值,對于需要批量操作的內(nèi)容,可以使用map進(jìn)行映射操作;

          Step2:搜索城市列表,展示;

          同樣是調(diào)用axios,需要給搜索框設(shè)置對input事件的監(jiān)聽

          const searchInput = document.querySelector('.search-city');
          searchInput.addEventListener('input',() => {
              // 獲取輸入框中輸入的內(nèi)容
              const searchName = searchInput.value;
              // 通過axios獲取城市列表
              myAxios({
                  url: 'http://hmajax.itheima.net/api/weather/city',
                  params:{
                      city:searchName,
                  }
              }).then(result => {
                  console.log(result);
                  const cityList = result.data;
                  const cityListStr = cityList.map(item => {
                      return `<li class="city-item">${item.name}</li>`;
                  }).join('');
                  document.querySelector('.search-list').innerHTML = cityListStr;
              });
          });

          Step3:點(diǎn)擊城市,顯示對應(yīng)天氣數(shù)據(jù)

          對搜索到的城市列表添加一個點(diǎn)擊事件,獲取該城市的cityCode,調(diào)用前面的方法將結(jié)果渲染到頁面中;

          由于城市列表是動態(tài)生成的,如果需要綁定點(diǎn)擊事件則需要通過事件委托(綁定父元素并通過e.target.classList.contains來獲取元素)

          在Step2中添加的城市列表city-item也要添加自定義屬性data-code=${item.code}

          return `<li class="city-item" data-code="${item.code}">${item.name}</li>`;
          document.querySelector('.search-list').addEventListener('click',(e) => {
              // 通過事件委托,判斷點(diǎn)擊的是否是城市item
              if(e.target.classList.contains('city-item')){
                  const cityCode = e.target.dataset.code;
                  getWeather(cityCode)
              }
          })

          最終效果:

          七、同步與異步

          同步:逐行執(zhí)行,需要原地等待結(jié)果后,才繼續(xù)向下執(zhí)行;

          異步:不必等待任務(wù)完成,在將來完成后觸發(fā)一個回調(diào)函數(shù);

          1.回調(diào)函數(shù)地獄問題:

          概念:在回調(diào)函數(shù)中嵌套回調(diào)函數(shù),一直嵌套下去就形成了回調(diào)函數(shù)地獄;

          缺點(diǎn):耦合性嚴(yán)重,異常無法捕獲,可讀性差;

          通過一個案例,理解回調(diào)函數(shù)地獄問題:

          //根據(jù)省名稱獲取城市名稱,再根據(jù)省名稱和城市名稱獲取地區(qū)名稱,axios模擬回調(diào)函數(shù)地獄問題
          axios({url:'http://hmajax.itheima.net/api/province'}).then(result => {
              const pname = result.data.list[0]
              document.querySelector('.province').innerHTML = pname;
              axios({url:'http://hmajax.itheima.net/api/city',params:{pname}}).then(result => {
                  const cname = result.data.list[0];
                  document.querySelector('.city').innerHTML = cname;
                  axios({url:'http://hmajax.itheima.net/api/area',params:{pname,cname}}).then(result =>{
                      const areaname = result.data.list[0];
                      document.querySelector('.area').innerHTML = areaname;
                  })
              })
          })

          這種嵌套問題,出現(xiàn)異常是無法捕獲的;

          2.Promise鏈?zhǔn)秸{(diào)用問題

          依靠then()方法會返回一個新生成的Promise對象的特性,繼續(xù)串聯(lián)下一環(huán)任務(wù),直到結(jié)束;

          // 將省份變量pname定義為全局變量
          let pname = '';
          axios({url:'http://hmajax.itheima.net/api/province'}).then(result => {
              pname = result.data.list[0];
              document.querySelector('.province').innerHTML = pname;
             // 關(guān)鍵點(diǎn)是axios結(jié)尾返回一個新的Promise對象,這樣就可以鏈?zhǔn)秸{(diào)用了
              return axios({url:'http://hmajax.itheima.net/api/city',params:{pname}})
          }).then(result => {
              const cname = result.data.list[0];
              document.querySelector('.city').innerHTML = cname;
             // 由于這里的pname是在兄弟作用域中,所以將pname定義為全局變量;
              return axios({url:'http://hmajax.itheima.net/api/area',params:{pname,cname}})
          }).then(result => {
              const area = result.data.list[0];
              document.querySelector('.area').innerHTML = area;
          })

          3. 異步編程的終極解決方案-async、await

          使用async和await關(guān)鍵字后,可以更簡潔的寫出基于Promise的異步行為,不需要刻意地鏈?zhǔn)秸{(diào)用Promise;

          //獲取默認(rèn)省市區(qū)
          async function getDefaultArea(){
              const pObj = await axios({url:'http://hmajax.itheima.net/api/province'});
              const pname = pObj.data.list[0];
              const cObj = await axios({url:'http://hmajax.itheima.net/api/city',params:{pname}});
              const cname = cObj.data.list[0];
              const aObj = await axios({url:'http://hmajax.itheima.net/api/area',params:{pname,cname}});
              const aname = aObj.data.list[0];
              // 賦予到頁面上
              document.querySelector('.province').innerHTML = pname;
              document.querySelector('.city').innerHTML = cname;
              document.querySelector('.area').innerHTML = aname;
          }
          getDefaultArea();

          async修飾函數(shù)名表明該函數(shù)為異步函數(shù),await表明該任務(wù)為異步任務(wù),會原地等待后續(xù)執(zhí)行完畢后將結(jié)果返回,替代then回調(diào)函數(shù)的功能;

          在使用async函數(shù)和await關(guān)鍵字時,如何捕獲錯誤?答案是使用try...catch關(guān)鍵字;

          //獲取默認(rèn)省市區(qū)
          async function getDefaultArea() {
              try {
                  const pObj = await axios({ url: 'http://hmajax.itheima.net/api/province' });
                  const pname = pObj.data.list[0];
                  const cObj = await axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } });
                  const cname = cObj.data.list[0];
                  const aObj = await axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } });
                  const aname = aObj.data.list[0];
                  // 賦予到頁面上
                  document.querySelector('.province').innerHTML = pname;
                  document.querySelector('.city').innerHTML = cname;
                  document.querySelector('.area').innerHTML = aname;
              } catch (error) {
                  console.dir(error);
              }
          }
          getDefaultArea();

          4.事件循環(huán)EventLoop

          Javascript 單線程為了讓耗時代碼不阻塞其他代碼運(yùn)行,設(shè)計了事件循環(huán)模型;

          執(zhí)行代碼和收集異步任務(wù),在調(diào)用棧空閑時,反復(fù)調(diào)用任務(wù)隊列里回調(diào)函數(shù)執(zhí)行機(jī)制;

          為什么要有事件循環(huán)?

          因為JavaScript是單線程的,為了不阻塞JavaScript引擎,而設(shè)計執(zhí)行的代碼模型

          事件循環(huán)的過程:

          a.執(zhí)行同步代碼,遇到異步代碼交給宿主瀏覽器環(huán)境執(zhí)行;

          b.異步有了結(jié)果后,把回調(diào)函數(shù)放入任務(wù)隊列排隊;

          c.當(dāng)調(diào)用棧空閑后,返回調(diào)用任務(wù)隊列里的回調(diào)函數(shù);

          5.宏任務(wù)與微任務(wù)

          ES6之后引入了promise對象,讓JS引擎也能發(fā)起異步任務(wù):

          宏任務(wù):由瀏覽器環(huán)境執(zhí)行的異步代碼,例如JS腳本事件、定時器、AJAX、用戶交互事件

          微任務(wù):由JS引擎環(huán)境執(zhí)行的異步代碼,例如Promise對象.then()回調(diào);

          Promise.then()屬于微任務(wù)隊列,優(yōu)先級高于宏任務(wù)隊列;

          事件循環(huán)經(jīng)典面試題:

          // 回答代碼執(zhí)行順序
          console.log(1);
          setTimeout(() => {
              console.log(2);
              const p = new Promise(resolve => resolve(3));
              p.then(result => console.log(result))
          },0);
          const p = new Promise(resolve => {
              setTimeout(() => {
                  console.log(4);
              },0);
              resolve(5);
          });
          p.then(result => console.log(result));
          const p2 = new Promise(resolve => resolve(6));
          p2.then(result => console.log(result));
          console.log(7);

          答案:1 7 5 6 2 3 4

          6.Promise.all靜態(tài)方法

          語法:

          const p = Promise.all([Promise對象,Promise對象,...])
          p.then(result => {
          // result結(jié)果:[Promise對象成功結(jié)果,Promise對象成功結(jié)果,...]
          }).catch(error => {
          // 第一個失敗的Promise對象,拋出的異常
          })

          案例1:同時獲取北上廣深四個城市的天氣信息

          const bjPromise = axios({url:'http://hmajax.itheima.net/api/weather',params:{city:'110100'}})
          const shPromise = axios({url:'http://hmajax.itheima.net/api/weather',params:{city:'310100'}})
          const gzPromise = axios({url:'http://hmajax.itheima.net/api/weather',params:{city:'440100'}})
          const szPromise = axios({url:'http://hmajax.itheima.net/api/weather',params:{city:'440300'}})
          const p = Promise.all([bjPromise,shPromise,gzPromise,szPromise]);
          p.then(result => {
              console.log(result);
              const weathers = result.map(item => {
                  return `<li>${item.data.data.area}---${item.data.data.weather}</li>`;
              }).join('');
              document.querySelector('.my-ul').innerHTML = weathers
              
          }).catch(error => {
              console.dir(error);
          })

          案例2:展示商品到分類頁面上

          思路:遍歷所有的一級分類數(shù)據(jù);遍歷id,創(chuàng)建獲取二級分類請求;合并所有二級分類Promise對象;等待同時成功,開始渲染頁面。

          axios({ url: 'http://hmajax.itheima.net/api/category/top' }).then(result => {
                      console.log(result.data.data);
                      // 獲取二級列表的Promise對象
                      const subPromise = result.data.data.map(itemTop => {
                          return axios({ url: 'http://hmajax.itheima.net/api/category/sub', params: { id: itemTop.id } });
                      })
                      // 合并二級Promise對象
                      const promiseAll = Promise.all(subPromise).then(result => {
                          console.log(result);
                          const showStr = result.map(item => {
                              const subObj = item.data.data;
                              return `<div class="item">
                                      <h3>${subObj.name}
                                      <ul>
                                          ${subObj.children.map(item => {
                                          return `<li>
                                                      <a href="javascript:;">
                                                      <img src=${item.picture}/>
                                                      </a>
                                                      <p>${item.name}</p>
                                                  </li>`
                                          }).join('')
                                      }
                                      </ul>
                                      </h3>
                                      </div>`
                                      }).join('');
                          document.querySelector('.sub-list').innerHTML = showStr;
                      })
                  })

          案例3:學(xué)習(xí)反饋-省市區(qū)切換

          // 1.1 設(shè)置省份下拉菜單數(shù)據(jù)
          // 創(chuàng)建一個全局變量
          let pname = '';
          axios({ url: 'http://hmajax.itheima.net/api/province' }).then(provinceList => {
              const proinceListStr = provinceList.data.list.map(pname => {
                  return `<option value=${pname}>${pname}</option>`
              }).join('');
              document.querySelector('.province').innerHTML = `<option value="">省份</option>` + proinceListStr;
          })
          
          // 1.2 切換省份
          document.querySelector('.province').addEventListener('change', async e => {
              // 用戶選中的省份
              pname = e.target.value;
              const cityList = await axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname: e.target.value } });
              console.log(cityList.data.list);
              const cityListStr = cityList.data.list.map(cname => {
                  return `<option value=${cname}>${cname}</option>`
              }).join('');
              document.querySelector('.city').innerHTML = `<option value="">城市</option>` + cityListStr;
              document.querySelector('.area').innerHTML = `<option value="">地區(qū)</option>`
          })
          
          // 1.3 切換城市
          document.querySelector('.city').addEventListener('change', async e => {
              // 用戶選擇的城市
              const areaList = await axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname: pname, cname: e.target.value }});
              console.log(areaList.data.list);
              const areaListStr = areaList.data.list.map(aname => {
                  return `<option value=${aname}>${aname}</option>`
              }).join('');
              document.querySelector('.area').innerHTML = `<option value="">地區(qū)</option>` + areaListStr;
          })
          
          // 2.收集數(shù)據(jù)并提交保存到后端
          document.querySelector('.submit').addEventListener('click', async () => {
              // 獲取表單中的內(nèi)容
              try{
                  const form = document.querySelector('.info-form')
                  const formRes = serialize(form, { hash: true, empty: true });
                  const res = await axios({ url: 'http://hmajax.itheima.net/api/feedback', method: 'post', data: { ...formRes } });
                  console.log(res);
                  alert(res.data.message)
              }catch (error){
                  console.dir(error);
                  alert(error.response.data.message);
              }
          })

          至此,關(guān)于JavaScript AJAX相關(guān)知識就介紹到這里,感謝你的閱讀~

          本文配套源碼以及圖片資源可見:https://gitee.com/yushengtan/jscode/tree/main/AJAX

          篇文章給大家?guī)淼膬?nèi)容是關(guān)于Vue封裝ajax的代碼示例詳解,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

          HTML文件:

          <!DOCTYPE html>

          <html>

          <head>

          <meta charset="UTF-8">

          <title>Document</title>

          </head>

          <body>

          <div id="app">

          <button @click="getInfo">點(diǎn)擊獲取信息</button>

          <span>{{ msg }}</span>

          </div>

          <script src="vue.js"></script>

          <script src="vue-ajax.js"></script>

          <script>

          var vm=new Vue({

          el: "#app",

          data: {

          msg: "",

          },

          methods: {

          getInfo: function (){

          var self=this;

          this.ajax.get("1.json",{

          tel: 123456,

          address: "杭州"

          },function (data){

          self.msg=data[1].name

          },"json");

          }

          }

          })

          </script>

          </body>

          </html>

          JS文件:

          /*

          * ajax封裝:

          * 1. 引入文件

          * 2. new Vue().ajax.get(url,data,fn,ojson), 或 new Vue().ajax.post(url,data,fn,ojson)

          * url: 需要獲取數(shù)據(jù)的文件地址 (string)

          * data: 需要發(fā)送的信息 (可省略) (obj)

          * fn: 獲取信息后的回調(diào)函數(shù),接收到的返回值為data (function)

          * ojson: 是否需要轉(zhuǎn)換為json格式 (可省略) (設(shè)置為 "json")

          *

          * 3. new Vue().ajax.get().cancel(): 取消異步請求

          * 4. new Vue().ajax.json(str): 可轉(zhuǎn)化json格式字符串

          **/

          Vue.prototype.ajax={

          //添加url傳送信息

          addUrl: function (url,obj){

          //如果省略url,則為post請求,令obj為url,令url為null

          if(arguments.length==1){

          obj=url;

          url=null;

          }

          //url不為空(get請求: 設(shè)置url信息)

          if(!!url){

          for(var k in obj){

          url += (url.indexOf("?")==-1 ? "?" : "&");

          url+=encodeURIComponent(k)+ "=" +encodeURIComponent(obj[k]);

          }

          }else{

          //post請求(設(shè)置data信息)

          url="";

          for(var k in obj){

          url+=encodeURIComponent(k)+ "=" +encodeURIComponent(obj[k]);

          url+="&";

          }

          //刪除最后一個&

          var arr=url.split("");

          arr.pop();

          url=arr.join("");

          }

          //返回拼接好的信息

          return url;

          },

          get: function (url,data,fn,ojson){

          this.xhr=new XMLHttpRequest();

          //省略data時,即不發(fā)送數(shù)據(jù)

          if(typeof data =="function"){

          ojson=fn;

          fn=data;

          data={};

          }

          //合并url和data信息

          url=this.addUrl(url,data)

          //是否異步發(fā)送

          this.xhr.open("get",url,true);

          this.xhr.send(null);

          //當(dāng)請求完成之后調(diào)用回調(diào)函數(shù)返回數(shù)據(jù)

          this.success(fn,ojson);

          //鏈?zhǔn)骄幊?/p>

          return this;

          },

          post: function (url,data,fn,ojson){

          this.xhr=new XMLHttpRequest();

          //省略data時,即不發(fā)送數(shù)據(jù)

          if(typeof data =="function"){

          ojson=fn;

          fn=data;

          data={};

          }

          //合并data信息

          data=this.addUrl(data);

          //是否異步發(fā)送

          this.xhr.open("post",url,true);

          this.xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

          this.xhr.send(data);

          //當(dāng)請求完成之后調(diào)用回調(diào)函數(shù)返回數(shù)據(jù)

          this.success(fn,ojson);

          //鏈?zhǔn)骄幊?/p>

          return this;

          },

          //字符串轉(zhuǎn)換json

          json: function (str){

          return (new Function("return " + str))();

          },

          success: function (fn,ojson){

          //當(dāng)請求完成之后調(diào)用回調(diào)函數(shù)返回數(shù)據(jù)

          var self=this;

          this.xhr.onreadystatechange=function (){

          var odata;

          if(self.xhr.readyState == 4){

          if((self.xhr.status>=200 && self.xhr.status<300) || self.xhr.status == 304){

          odata=self.xhr.responseText;

          //若為json則轉(zhuǎn)化json格式

          if(ojson==="json"){

          odata=self.json(odata);

          }

          fn(odata);

          }else{

          odata="request was unsuccessful: "+self.xhr.status;

          fn(odata);

          }

          }

          }

          },

          //取消異步請求

          cancel: function (){

          this.xhr.abort();

          return this;

          }

          }

          后臺獲取或者前端構(gòu)造的數(shù)據(jù)結(jié)構(gòu):

          [

          {

          "name": "張三",

          "age": 18,

          "sex": "man"

          },

          {

          "name": "李四",

          "age": 20,

          "sex": "woman"

          },

          {

          "name": "王五",

          "age": 22,

          "sex": "man"

          }

          ]

          以上就是Vue封裝ajax的代碼示例詳解的詳細(xì)內(nèi)容,更多請關(guān)注其它相關(guān)文章!

          更多技巧請《轉(zhuǎn)發(fā) + 關(guān)注》哦!


          主站蜘蛛池模板: 日本精品3d动漫一区二区| 一区二区三区久久精品| 亚洲AV无码一区二区三区久久精品 | 精品少妇一区二区三区在线| 精品一区二区三区在线观看l| 日本在线不卡一区| 精品人妻AV一区二区三区 | 国产日产久久高清欧美一区| 精品午夜福利无人区乱码一区| 精品爆乳一区二区三区无码av| 国产Av一区二区精品久久| 国产91精品一区二区麻豆亚洲| 色噜噜AV亚洲色一区二区| 精品一区二区三区在线观看视频| 国产成人av一区二区三区在线观看| 精品国产一区二区三区在线观看| 一区二区三区免费看| 免费无码AV一区二区| 亚洲国产精品自在线一区二区 | 伊人精品视频一区二区三区| 夜夜爽一区二区三区精品| 日韩一区二区在线免费观看| 波多野结衣免费一区视频| 国产乱码精品一区二区三区| www一区二区三区| 亚洲一区二区三区免费视频| 精品欧洲av无码一区二区14| 一区二区三区福利| 免费无码一区二区| 国产裸体舞一区二区三区| 久久亚洲AV午夜福利精品一区| 夜夜添无码一区二区三区| 国产在线精品一区免费香蕉 | 白丝爆浆18禁一区二区三区| 中文字幕亚洲一区| 91精品福利一区二区| 国产精品 一区 在线| 精品少妇一区二区三区视频| 狠狠综合久久AV一区二区三区 | 亚洲av无码片vr一区二区三区 | 午夜影视日本亚洲欧洲精品一区|