Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
用AJAX實(shí)現(xiàn)的PHP RSS閱讀器示例
示例代碼:
```html
<!DOCTYPE html>
<html>
<head>
<title>AJAX RSS閱讀器</title>
<script>
function loadRSS(url) {
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById("rssFeed").innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("GET", "read_rss.php?url=" + url, true);
xmlhttp.send();
}
</script>
</head>
<body>
<h2>RSS閱讀器示例</h2>
<form>
<select onchange="loadRSS(this.value)">
<option value="">選擇一個(gè)RSS源</option>
<option value="https://example.com/rss1">RSS源1</option>
<option value="https://example.com/rss2">RSS源2</option>
<option value="https://example.com/rss3">RSS源3</option>
</select>
</form>
<div id="rssFeed"></div>
</body>
</html>
```
使用心得:
在開發(fā)過程中,我發(fā)現(xiàn)使用AJAX實(shí)現(xiàn)的PHP RSS閱讀器可以方便地從不同的RSS源中獲取并展示內(nèi)容。
1. 在示例代碼中,我使用了一個(gè)下拉菜單來選擇不同的RSS源。當(dāng)用戶選擇一個(gè)RSS源時(shí),就會(huì)調(diào)用`loadRSS()`函數(shù),將選中的URL作為參數(shù)傳遞給服務(wù)器端的讀取腳本。
2. 通過AJAX,可以將選中的URL發(fā)送到服務(wù)器端,并接收服務(wù)器返回的RSS內(nèi)容。在示例代碼中,我使用了`XMLHttpRequest`對(duì)象來實(shí)現(xiàn)異步通信,并通過`responseText`屬性獲取服務(wù)器返回的RSS內(nèi)容。
3. 在示例代碼中,我將獲取到的RSS內(nèi)容展示在頁面上的`rssFeed`元素中。用戶可以通過選擇不同的RSS源,實(shí)時(shí)獲取并查看對(duì)應(yīng)的內(nèi)容。
在開發(fā)過程中遇到的問題和解決的bug:
在使用AJAX實(shí)現(xiàn)的PHP RSS閱讀器的過程中,我曾遇到過一些問題和bug。其中一次遇到的問題是無法正確解析RSS內(nèi)容。這可能是由于RSS源的格式不正確或解析代碼有誤導(dǎo)致的。解決這個(gè)問題的方法是檢查RSS源的格式,并確保解析代碼正確地處理和展示內(nèi)容。
另外,我還遇到過一些其他的問題,比如RSS源無法訪問、RSS內(nèi)容顯示不全等。這些問題通??梢酝ㄟ^檢查RSS源鏈接、優(yōu)化解析代碼等方式來解決。
總結(jié):
使用AJAX實(shí)現(xiàn)的PHP RSS閱讀器可以方便地從不同的RSS源中獲取并展示內(nèi)容。在開發(fā)過程中,需要注意RSS源的格式和解析代碼的正確性。在遇到問題時(shí),可以通過檢查RSS源鏈接、優(yōu)化解析代碼等方式來解決。
(注:以上內(nèi)容為筆記,非官方文檔)
我是永不低頭的熊,喜歡美食、健身,當(dāng)然也喜歡寫代碼,每天不定時(shí)更新各類編程相關(guān)的文章,希望你在碼農(nóng)這條路上不再孤單!
在現(xiàn)代的Web開發(fā)中,AJAX(Asynchronous JavaScript and XML)已經(jīng)成為不可或缺的一部分。它使我們能夠在不刷新整個(gè)頁面的情況下與服務(wù)器進(jìn)行通信,為用戶提供更流暢的體驗(yàn)。然而,要真正掌握AJAX,我們需要了解JavaScript中的同步與異步編程、Promise對(duì)象以及如何使用強(qiáng)大的axios庫來簡(jiǎn)化AJAX請(qǐng)求。在這篇推文中,我們將深入探討這些概念,幫助你更好地理解和利用AJAX的潛力。讓我們開始這段AJAX之旅吧!
定義:AJAX是異步的JavaScript與XML,使用XMLHttpRequest對(duì)象與服務(wù)器通信;
Axios是一個(gè)基于promise構(gòu)建的一個(gè)網(wǎng)絡(luò)請(qǐng)求庫,可以用于瀏覽器和node.js
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
(1)傳入配置對(duì)象
(2)使用.then回調(diào)函數(shù)接收結(jié)果,并做后續(xù)處理
axios({
url:'目標(biāo)資源地址'
}).then(result=>{
// 對(duì)服務(wù)器返回的數(shù)據(jù)做后續(xù)處理
})
<!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=>{
// 對(duì)服務(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是什么?URL是統(tǒng)一資源定位符,用于訪問服務(wù)器上的資源;結(jié)構(gòu)由協(xié)議、域名、資源路徑組成;
url參數(shù)查詢語法:
http://xxx.com/xxx/xxx?參數(shù)名1=值1&參數(shù)名2=值2
使用axios提供的params選項(xiàng):
axios({
url:'目標(biāo)資源地址',
params:{
參數(shù)名:值
}
}).then(result=>{
// 對(duì)服務(wù)器返回的數(shù)據(jù)做后續(xù)處理
})
實(shí)際上axios在運(yùn)行時(shí)會(huì)把params中的內(nèi)容自動(dòng)拼接到url?參數(shù)名=值上面;
在ES6中如果屬性名和變量同名,可以只寫一個(gè);
通過省份和城市名查詢?cè)摮鞘械乃袇^(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;
})
})
axios配置請(qǐng)求方法怎么寫?
GET方法是默認(rèn)的可以省略,在參數(shù)列表中,如果是get方法則用params,如果是post方法則用data;
axios({
url:'目標(biāo)資源地址',
method:'請(qǐng)求方法',
params:{
參數(shù)名:值
}
}).then(result=>{
// 對(duì)服務(wù)器返回的數(shù)據(jù)做后續(xù)處理
})
在axios請(qǐng)求錯(cuò)誤時(shí),通過調(diào)用catch方法傳入回調(diào)函數(shù)并定義形參;例如在用戶注冊(cè)失敗時(shí),通過彈窗提示用戶錯(cuò)誤原因。
axios({
// 請(qǐng)求選項(xiàng)
}).then(result=>{
// 對(duì)服務(wù)器返回的數(shù)據(jù)做后續(xù)處理
}).catch(error=>{
// 處理錯(cuò)誤
})
Http協(xié)議:規(guī)定了瀏覽器發(fā)送以及服務(wù)器返回內(nèi)容的格式;
請(qǐng)求報(bào)文:瀏覽器按照Http協(xié)議要求的格式,發(fā)送給服務(wù)器的內(nèi)容
請(qǐng)求報(bào)文的組成部分有:
在瀏覽器中怎么查看請(qǐng)求報(bào)文:
在瀏覽器的瀏覽器開發(fā)者工具的網(wǎng)絡(luò)面板中,選擇Fetch/XHR中查看,
請(qǐng)求行和請(qǐng)求頭在標(biāo)頭選項(xiàng)中,請(qǐng)求體在載荷選項(xiàng)中;
在故障排查時(shí)可以查看請(qǐng)求報(bào)文的請(qǐng)求體內(nèi)容是否正確;
響應(yīng)報(bào)文的組成部分有:
HTTP響應(yīng)狀態(tài)碼:用來表明請(qǐng)求是否成功,主要含義如下:
根據(jù)后端的接口文檔,前端使用ajax進(jìn)行調(diào)用;
示例API文檔:https://apifox.com/apidoc/project-1937884/doc-1695440
// 點(diǎn)擊登錄時(shí),用戶名和密碼長(zhǎng)度判斷,并提交數(shù)據(jù)和服務(wù)器通信
// 定義一個(gè)函數(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è)置一個(gè)定時(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;
// 對(duì)長(zhǎng)度做判斷
if (username.length < 8) {
console.log("用戶名長(zhǎng)度不能低于8");
showAlert("用戶名長(zhǎng)度不能低于8", false);
return;
}
if (password.length < 6) {
console.log("密碼長(zhǎng)度不能低于6");
showAlert("密碼長(zhǎng)度不能低于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);
});
});
使用form-serialize插件快速收集表單元素的值,獲取結(jié)果的鍵值對(duì),根據(jù)表單元素中的name屬性獲取鍵;
語法:
const data = serialize(form, {hash: true, empty:true})
/**
* 使用serialize函數(shù),快速收集表單元素的值
* 參數(shù)1:要獲取的表單名稱;
* 參數(shù)2:配置對(duì)象
* hash:設(shè)置獲取數(shù)據(jù)結(jié)構(gòu)
* - false:獲取到的是url查詢字符串
* - true:獲取到的是JS對(duì)象
* empty:設(shè)置是否獲取空值
* - false: 不獲取空值
* - true: 可以獲取到空值
*/
使用方法:
引入插件,調(diào)用serialize方法獲取到表單元素的值,表單元素的name屬性會(huì)成為返回對(duì)象的屬性名;
將上面用戶登錄的案例利用form-serialize插件獲取表單的值,下面是實(shí)際的寫法:
// 點(diǎn)擊登錄時(shí),用戶名和密碼長(zhǎng)度判斷,并提交數(shù)據(jù)和服務(wù)器通信
// 定義一個(gè)函數(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è)置一個(gè)定時(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)賦值的方式獲取對(duì)象中用戶名和密碼
const { username, password } = data;
// 對(duì)長(zhǎng)度做判斷
if (username.length < 8) {
console.log("用戶名長(zhǎng)度不能低于8");
showAlert("用戶名長(zhǎng)度不能低于8", false);
return;
}
if (password.length < 6) {
console.log("密碼長(zhǎng)度不能低于6");
showAlert("密碼長(zhǎng)度不能低于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);
});
});
功能:不離開當(dāng)前頁面,顯示單獨(dú)內(nèi)容,供用戶操作;調(diào)用彈窗可以通過兩種方式:屬性控制和JS控制;
使用方法:
(1)引入bootstrap.css與bootstrap.js
(2)給啟動(dòng)彈框的組件添加bootstrap屬性,顯示彈框需要兩個(gè)屬性,分別是data-bs-toggle和data-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">請(qǐng)輸入姓名</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();
獲取圖書列表的的API地址http://hmajax.itheima.net/api/books
這里重點(diǎn)需要掌握的技巧是使用map將列表對(duì)象中的元素映射到html元素中,并進(jìn)行字符串拼接的過程。map函數(shù)可以傳入三個(gè)參數(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 = '小雨';
// 封裝一個(gè)函數(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()
})
// 目標(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:{
// 這里的...是對(duì)象展開運(yùn)算符
...bookItem,
// 這里的creator是一個(gè)全局變量
creator
}
}).then(result => {
// 添加成功后請(qǐng)求重新渲染頁面
getBookList();
// 重置表單,防止點(diǎn)擊添加按鈕后,上一次添加的內(nèi)容還在
bookItemForm.reset();
// 隱藏彈框
addModal.hide();
})
});
思路:
a.綁定點(diǎn)擊事件獲取圖書id
b.調(diào)用刪除接口
c.刷新圖書列表
由于每一行圖書信息是動(dòng)態(tài)生成的,如果給每一行圖書的刪除按鈕添加點(diǎn)擊事件,則需要委托其父級(jí)元素設(shè)置點(diǎn)擊事件。再定義一個(gè)判斷條件如果點(diǎn)擊的元素中含有del類,則獲取其父元素的id。
在渲染圖書列表時(shí)就給刪除按鈕的父級(jí)元素創(chuàng)建一個(gè)自定義屬性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();
});
}
})
實(shí)現(xiàn)該功能主要需要完成以下部分的內(nèi)容:
編輯彈窗的顯示和隱藏;
獲取當(dāng)前圖書的ID并通過查詢接口獲取圖書信息填充到彈窗中;
點(diǎn)擊提交按鈕時(shí),提交表單中的內(nèi)容到后臺(tá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();
});
})
圖片上傳的思路:
(1)獲取圖片文件對(duì)象
給input標(biāo)簽添加一個(gè)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;
})
})
實(shí)現(xiàn)一個(gè)案例,點(diǎn)擊按鈕上傳圖片,并替換網(wǎng)頁背景,頁面刷新后依然不變;
思路:
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})`);
})
實(shí)現(xiàn)效果:
該案例可以分為四個(gè)主要步驟:
const creator = "xiaoyu";
function getProfile() {
axios({
url: 'http://hmajax.itheima.net/api/settings',
params:{
creator
}
}).then(result => {
// 獲取個(gè)人信息
const profile = result.data.data;
// 遍歷個(gè)人信息屬性并顯示到頁面中
Object.keys(profile).forEach(key => {
// 對(duì)于性別和頭像需要特殊處理
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];
}
});
});
}
在做的這一步的時(shí)候,總是提交出錯(cuò),原因是沒有看清api文檔中的參數(shù)要求
需要在整個(gè)FormData對(duì)象里append兩個(gè)對(duì)象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;
});
});
這里需要注意給要提交的的對(duì)象添加一個(gè)屬性,以及將字符串型的“0”轉(zhuǎn)為整型的“0”
document.querySelector('.submit').addEventListener('click',() => {
const form = document.querySelector('.user-form');
const newProfile = serialize(form,{hash:true,empty:true});
// 對(duì)象可以通過賦值的方式添加屬性
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);
});
});
這里需要將提交成功的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(XHR)對(duì)象用于與服務(wù)器交互,通過XMLHttpRequest可以在不刷新頁面的情況下請(qǐng)求特定URL,獲取數(shù)據(jù),這允許網(wǎng)頁在不影響用戶操作的情況下,更新頁面的布局內(nèi)容。在AJAX編程中被大量使用;
使用XMLHttpRequest的方法:
// 創(chuàng)建xhr對(duì)象
const xhr = new XMLHttpRequest()
xhr.open('請(qǐng)求方法','url網(wǎng)址')
xhr.addEventListener('loadend',() => {
// 輸出響應(yīng)結(jié)果
console.log(xhr.response)
})
// 正式發(fā)送請(qǐng)求
xhr.send()
使用axios返回的結(jié)果是對(duì)象,而原生的XHR返回的是JSON字符串,如果需要將JSON字符串轉(zhuǎn)化為對(duì)象可以使用JSON.parse()的方式;
XHR如果需要攜帶查詢參數(shù)則直接在URL里設(shè)置;
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();
})
知識(shí)拓展:對(duì)于多參數(shù)查詢字符串,是可以根據(jù)對(duì)象名生成的。
// 創(chuàng)建URLSearchParams對(duì)象
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對(duì)象
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();
})
使用方法:
// 告訴服務(wù)器需要傳遞的內(nèi)容類型是JSON字符串
xhr.setRequestHeader('Content-Type','application/json')
// JSON.stringify將JS對(duì)象轉(zhuǎn)為JSON字符串
const user = {key1:value1,key2:value2};
const userStr = JSON.stringify(user);
// 發(fā)送請(qǐng)求體數(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對(duì)象用于表示一個(gè)異步操作的最終結(jié)果值;
使用Promise的好處:
可以鏈?zhǔn)秸{(diào)用
用法:
// 1.創(chuàng)建Promise對(duì)象
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);
})
需求:使用Promise管理XHR獲取省份列表,并展示到頁面上
實(shí)現(xiàn):
// 1.創(chuàng)建Promise對(duì)象
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)為對(duì)象分別給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ù)對(duì)象
p.then(result => {
document.querySelector('.my-p').innerHTML = result.list.join('</br>');
}).catch(error => {
console.dir(error);
document.querySelector('.my-p').innerHTML = error.message;
})
需求:通過Promise和XHR實(shí)現(xiàn)對(duì)axios的自定義封裝,完成返回省份列表的獲?。?/span>
思路:
Step1:封裝myAxios函數(shù),傳入config配置對(duì)象,返回Promise對(duì)象;
Step2:發(fā)起xhr請(qǐng)求,定義默認(rèn)方法為get,定義接收URL參數(shù);
Step3:定義成功或失敗請(qǐng)求的處理程序,將傳入結(jié)果對(duì)象
Step4:實(shí)際調(diào)用自封裝的函數(shù),檢查效果
function myAxios(config) {
// 1. 定義myAxios函數(shù),接受配置對(duì)象,返回Promise對(duì)象
const p = new Promise((resolve,reject) => {
// 2.發(fā)起xhr請(qǐng)求
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;
})
需求:修改myAxios函數(shù),支持傳遞params參數(shù),完成地區(qū)列表的查詢
思路:需要考慮自定義的axios對(duì)傳入的params參數(shù)的支持,可以借助URLSearchParams實(shí)現(xiàn)將params參數(shù)轉(zhuǎn)為URL連接;
function myAxios(config) {
// 1. 定義myAxios函數(shù),接受配置對(duì)象,返回Promise對(duì)象
return new Promise((resolve,reject) => {
// 2.對(duì)params進(jìn)行處理,前提是有params參數(shù)
if(config.params){
const paramsObj = new URLSearchParams(config.params);
const queryString = paramsObj.toString();
config.url += `?${queryString}`;
}
// 3.發(fā)起xhr請(qǐng)求
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();
});
}
需求:修改myAxios函數(shù),支持傳遞請(qǐng)求體數(shù)據(jù),完成用戶注冊(cè)功能;
思路:
Step1:myAxios函數(shù)調(diào)用后,判斷data選項(xiàng)
Step2:轉(zhuǎn)換數(shù)據(jù)類型,在send方法中發(fā)送
Step3:使用自己封裝的myAxios完成用戶注冊(cè)功能
實(shí)現(xiàn):
function myAxios(config) {
// 1. 定義myAxios函數(shù),接受配置對(duì)象,返回Promise對(duì)象
return new Promise((resolve,reject) => {
// 2.對(duì)params進(jìn)行處理,前提是有params參數(shù)
if(config.params){
const paramsObj = new URLSearchParams(config.params);
const queryString = paramsObj.toString();
config.url += `?${queryString}`;
}
// 3.發(fā)起xhr請(qǐng)求
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));
}
});
// 對(duì)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);
})
})
步驟:
Step1:默認(rèn)獲取北京市天氣數(shù)據(jù),并展示;
這一步其實(shí)就是通過axios獲取后端數(shù)據(jù),并顯示到html頁面中,${}將網(wǎng)頁中的元素替換為JS對(duì)象屬性值,對(duì)于需要批量操作的內(nèi)容,可以使用map進(jìn)行映射操作;
Step2:搜索城市列表,展示;
同樣是調(diào)用axios,需要給搜索框設(shè)置對(duì)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)擊城市,顯示對(duì)應(yīng)天氣數(shù)據(jù)
對(duì)搜索到的城市列表添加一個(gè)點(diǎn)擊事件,獲取該城市的cityCode,調(diào)用前面的方法將結(jié)果渲染到頁面中;
由于城市列表是動(dòng)態(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ā)一個(gè)回調(diào)函數(shù);
概念:在回調(diào)函數(shù)中嵌套回調(diào)函數(shù),一直嵌套下去就形成了回調(diào)函數(shù)地獄;
缺點(diǎn):耦合性嚴(yán)重,異常無法捕獲,可讀性差;
通過一個(gè)案例,理解回調(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)異常是無法捕獲的;
依靠then()方法會(huì)返回一個(gè)新生成的Promise對(duì)象的特性,繼續(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é)尾返回一個(gè)新的Promise對(duì)象,這樣就可以鏈?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;
})
使用async和await關(guān)鍵字后,可以更簡(jiǎ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ù),會(huì)原地等待后續(xù)執(zhí)行完畢后將結(jié)果返回,替代then回調(diào)函數(shù)的功能;
在使用async函數(shù)和await關(guān)鍵字時(shí),如何捕獲錯(cuò)誤?答案是使用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();
Javascript 單線程為了讓耗時(shí)代碼不阻塞其他代碼運(yùn)行,設(shè)計(jì)了事件循環(huán)模型;
執(zhí)行代碼和收集異步任務(wù),在調(diào)用??臻e時(shí),反復(fù)調(diào)用任務(wù)隊(duì)列里回調(diào)函數(shù)執(zhí)行機(jī)制;
為什么要有事件循環(huán)?
因?yàn)镴avaScript是單線程的,為了不阻塞JavaScript引擎,而設(shè)計(jì)執(zhí)行的代碼模型
事件循環(huán)的過程:
a.執(zhí)行同步代碼,遇到異步代碼交給宿主瀏覽器環(huán)境執(zhí)行;
b.異步有了結(jié)果后,把回調(diào)函數(shù)放入任務(wù)隊(duì)列排隊(duì);
c.當(dāng)調(diào)用??臻e后,返回調(diào)用任務(wù)隊(duì)列里的回調(diào)函數(shù);
ES6之后引入了promise對(duì)象,讓JS引擎也能發(fā)起異步任務(wù):
宏任務(wù):由瀏覽器環(huán)境執(zhí)行的異步代碼,例如JS腳本事件、定時(shí)器、AJAX、用戶交互事件
微任務(wù):由JS引擎環(huán)境執(zhí)行的異步代碼,例如Promise對(duì)象.then()回調(diào);
Promise.then()屬于微任務(wù)隊(duì)列,優(yōu)先級(jí)高于宏任務(wù)隊(duì)列;
// 回答代碼執(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
語法:
const p = Promise.all([Promise對(duì)象,Promise對(duì)象,...])
p.then(result => {
// result結(jié)果:[Promise對(duì)象成功結(jié)果,Promise對(duì)象成功結(jié)果,...]
}).catch(error => {
// 第一個(gè)失敗的Promise對(duì)象,拋出的異常
})
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);
})
思路:遍歷所有的一級(jí)分類數(shù)據(jù);遍歷id,創(chuàng)建獲取二級(jí)分類請(qǐng)求;合并所有二級(jí)分類Promise對(duì)象;等待同時(shí)成功,開始渲染頁面。
axios({ url: 'http://hmajax.itheima.net/api/category/top' }).then(result => {
console.log(result.data.data);
// 獲取二級(jí)列表的Promise對(duì)象
const subPromise = result.data.data.map(itemTop => {
return axios({ url: 'http://hmajax.itheima.net/api/category/sub', params: { id: itemTop.id } });
})
// 合并二級(jí)Promise對(duì)象
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;
})
})
// 1.1 設(shè)置省份下拉菜單數(shù)據(jù)
// 創(chuàng)建一個(gè)全局變量
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)知識(shí)就介紹到這里,感謝你的閱讀~
本文配套源碼以及圖片資源可見:https://gitee.com/yushengtan/jscode/tree/main/AJAX
迎來到我的微信公眾號(hào)!在這篇文章中,我們將深入研究JavaWeb中的Ajax技術(shù)和前端庫Axios,通過更多具體的例子和實(shí)用的Demo,助你更深入理解前端異步請(qǐng)求的精髓。
### 第一部分:Ajax,服務(wù)端渲染到異步崛起
#### 1.1 服務(wù)端渲染
在傳統(tǒng)的服務(wù)端渲染中,頁面的生成完全依賴于服務(wù)器。用戶每次操作都觸發(fā)整個(gè)頁面的重新加載,這樣的模式雖然簡(jiǎn)單,但用戶體驗(yàn)相對(duì)較差。
#### 1.2 Ajax渲染
Ajax技術(shù)的引入改變了這一格局。通過異步請(qǐng)求,頁面可以在不刷新整個(gè)頁面的情況下獲取數(shù)據(jù),從而實(shí)現(xiàn)局部刷新。下面是一個(gè)簡(jiǎn)單的例子:
// 使用原生JavaScript實(shí)現(xiàn)Ajax請(qǐng)求
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// 處理服務(wù)器返回的數(shù)據(jù)
console.log(xhr.responseText);
}
};
xhr.open('GET', '/api/data', true);
xhr.send();
#### 1.3 前后端分離
前后端分離的模式隨著Ajax的普及而逐漸成為主流。前端負(fù)責(zé)頁面渲染和用戶交互,后端提供API接口和業(yè)務(wù)邏輯。這樣的架構(gòu)更有利于團(tuán)隊(duì)協(xié)作和開發(fā)的獨(dú)立性。
#### 1.4 同步與異步
Ajax的核心是異步通信。下面的例子演示了一個(gè)使用jQuery庫的異步請(qǐng)求:
// 使用jQuery實(shí)現(xiàn)Ajax請(qǐng)求
$.ajax({
url: '/api/data',
type: 'GET',
success: function (data) {
// 處理成功返回的數(shù)據(jù)
console.log(data);
},
error: function (error) {
// 處理請(qǐng)求失敗
console.error(error);
}
});
### 第二部分:Axios,現(xiàn)代前端異步的精華之選
#### 2.1 Axios簡(jiǎn)介
Axios是一個(gè)基于Promise的HTTP客戶端,相比原生的XMLHttpRequest更加強(qiáng)大和易用。下面是一個(gè)簡(jiǎn)單的Axios請(qǐng)求示例:
// 使用Axios發(fā)送GET請(qǐng)求
axios.get('/api/data')
.then(response => {
// 處理響應(yīng)數(shù)據(jù)
console.log(response.data);
})
.catch(error => {
// 處理錯(cuò)誤
console.error(error);
});
#### 2.2 Axios的用法
Axios支持豐富的配置和攔截器,使得開發(fā)者可以更靈活地處理請(qǐng)求和響應(yīng)。以下是一個(gè)帶有攔截器的例子:
// 添加請(qǐng)求攔截器
axios.interceptors.request.use(config => {
// 在發(fā)送請(qǐng)求之前做些處理
console.log('請(qǐng)求發(fā)送中...');
return config;
}, error => {
// 處理請(qǐng)求錯(cuò)誤
return Promise.reject(error);
});
// 添加響應(yīng)攔截器
axios.interceptors.response.use(response => {
// 對(duì)響應(yīng)數(shù)據(jù)做點(diǎn)什么
console.log('響應(yīng)接收中...');
return response;
}, error => {
// 處理響應(yīng)錯(cuò)誤
return Promise.reject(error);
});
// 發(fā)起GET請(qǐng)求
axios.get('/api/interceptedData')
.then(response => {
// 處理響應(yīng)數(shù)據(jù)
console.log(response.data);
})
.catch(error => {
// 處理錯(cuò)誤
console.error(error);
});
#### 2.3 發(fā)送請(qǐng)求體JSON
Axios支持發(fā)送JSON格式的請(qǐng)求體,示例如下:
// 發(fā)起POST請(qǐng)求,發(fā)送JSON數(shù)據(jù)
axios.post('/api/postData', { key: 'value' })
.then(response => {
// 處理響應(yīng)數(shù)據(jù)
console.log(response.data);
})
.catch(error => {
// 處理錯(cuò)誤
console.error(error);
});
#### 2.4 服務(wù)端返回JSON
Axios默認(rèn)以JSON格式解析響應(yīng)數(shù)據(jù),因此當(dāng)服務(wù)端返回JSON數(shù)據(jù)時(shí),我們可以直接在響應(yīng)對(duì)象中獲取解析后的數(shù)據(jù)。
// 發(fā)起GET請(qǐng)求
axios.get('/api/jsonData')
.then(response => {
// 直接獲取JSON格式的響應(yīng)數(shù)據(jù)
console.log(response.data);
})
.catch(error => {
// 處理錯(cuò)誤
console.error(error);
});
## 結(jié)語:前端異步請(qǐng)求的奇妙世界
通過這篇文章,我們深入學(xué)習(xí)了JavaWeb中的Ajax和前端庫Axios,了解了它們?cè)谇岸水惒秸?qǐng)求中的應(yīng)用和原理。關(guān)注我的公眾號(hào),獲取更多關(guān)于JavaWeb和前端開發(fā)的實(shí)用知識(shí),讓我們一同探索前端異步的奇妙世界!
點(diǎn)擊關(guān)注,共同迎接前端異步的挑戰(zhàn)!
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。