4. 通過(guò)axios實(shí)現(xiàn)數(shù)據(jù)請(qǐng)求
vue.js默認(rèn)沒(méi)有提供ajax功能的。
所以使用vue的時(shí)候,一般都會(huì)使用axios的插件來(lái)實(shí)現(xiàn)ajax與后端服務(wù)器的數(shù)據(jù)交互。
注意,axios本質(zhì)上就是javascript的ajax封裝,所以會(huì)被同源策略限制。
https://unpkg.com/axios@0.18.0/dist/axios.js
https://unpkg.com/axios@0.18.0/dist/axios.min.js
axios提供發(fā)送請(qǐng)求的常用方法有兩個(gè):axios.get() 和 axios.post() 。
增 post
刪 delete
改 put
查 get
// 發(fā)送get請(qǐng)求
// 參數(shù)1: 必填,字符串,請(qǐng)求的數(shù)據(jù)接口的url地址,例如請(qǐng)求地址:http://www.baidu.com?id=200
// 參數(shù)2:可選,json對(duì)象,要提供給數(shù)據(jù)接口的參數(shù)
// 參數(shù)3:可選,json對(duì)象,請(qǐng)求頭信息
axios.get('服務(wù)器的資源地址',{ // http://www.baidu.com
params:{
參數(shù)名:'參數(shù)值', // id: 200,
}
}).then(function (response) { // 請(qǐng)求成功以后的回調(diào)函數(shù)
console.log("請(qǐng)求成功");
console.log(response);
}).catch(function (error) { // 請(qǐng)求失敗以后的回調(diào)函數(shù)
console.log("請(qǐng)求失敗");
console.log(error.response);
});
// 發(fā)送post請(qǐng)求,參數(shù)和使用和axios.get()一樣。
// 參數(shù)1: 必填,字符串,請(qǐng)求的數(shù)據(jù)接口的url地址
// 參數(shù)2:必填,json對(duì)象,要提供給數(shù)據(jù)接口的參數(shù),如果沒(méi)有參數(shù),則必須使用{}
// 參數(shù)3:可選,json對(duì)象,請(qǐng)求頭信息
axios.post('服務(wù)器的資源地址',{
username: 'xiaoming',
password: '123456'
},{
responseData:"json",
})
.then(function (response) { // 請(qǐng)求成功以后的回調(diào)函數(shù)
console.log(response);
})
.catch(function (error) { // 請(qǐng)求失敗以后的回調(diào)函數(shù)
console.log(error);
});
// json數(shù)據(jù)的對(duì)象格式:
{
"name":"tom",
"age":18
}
// json數(shù)據(jù)的數(shù)組格式:
["tom",18,"programmer"]
復(fù)雜的json格式數(shù)據(jù)可以包含對(duì)象和數(shù)組的寫(xiě)法。
{
"name":"小明",
"age":200,
"fav":["code","eat","swim","read"],
"son":{
"name":"小小明",
"age":100,
"lve":["code","eat"],
}
}
| 方法 | 參數(shù) | 返回值 | 描述 |
|---|---|---|---|
| stringify | json對(duì)象 | 字符串 | json對(duì)象轉(zhuǎn)成字符串 |
| parse | 字符串 | json對(duì)象 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> // json語(yǔ)法 let humen = { "username":"xiaohui", "password":"1234567", "age":20 }; console.log(humen); console.log(typeof humen); // JSON對(duì)象提供對(duì)json格式數(shù)據(jù)的轉(zhuǎn)換功能 // stringify(json對(duì)象) # 用于把json轉(zhuǎn)換成字符串 let result = JSON.stringify(humen); console.log(result); console.log(typeof result); // parse(字符串類(lèi)型的json數(shù)據(jù)) # 用于把字符串轉(zhuǎn)成json對(duì)象 let json_str = '{"password":"1123","age":20,"name":"xiaobai"}'; console.log(json_str) console.log(typeof json_str) let json_obj = JSON.parse(json_str); console.log(json_obj); console.log(typeof json_obj) console.log(json_obj.age) </script> </body> </html>
ajax,一般中文稱(chēng)之為:"阿賈克斯",是英文 “Async Javascript And Xml”的簡(jiǎn)寫(xiě),譯作:異步j(luò)s和xml數(shù)據(jù)傳輸數(shù)據(jù)。
所以開(kāi)發(fā)中ajax是很常用的技術(shù),主要用于操作后端提供的數(shù)據(jù)接口,從而實(shí)現(xiàn)網(wǎng)站的前后端分離。
ajax技術(shù)的原理是實(shí)例化js的XMLHttpRequest對(duì)象,使用此對(duì)象提供的內(nèi)置方法就可以與后端進(jìn)行數(shù)據(jù)通信。
數(shù)據(jù)接口,也叫api接口,表示
客戶(hù)端通過(guò)發(fā)起請(qǐng)求向服務(wù)端提供的url地址申請(qǐng)操作數(shù)據(jù)【操作一般:增刪查改】
同時(shí)在工作中,大部分?jǐn)?shù)據(jù)接口都不是手寫(xiě),而是通過(guò)函數(shù)庫(kù)/框架來(lái)生成。
編寫(xiě)代碼獲取接口提供的數(shù)據(jù):
JQ版 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/jquery-1.12.4.js"></script> <script> $(function(){ $("#btn").on("click",function(){ $.ajax({ // 后端程序的url地址 url: 'http://wthrcdn.etouch.cn/weather_mini', // 也可以使用method,提交數(shù)據(jù)的方式,默認(rèn)是'GET',常用的還有'POST' type: 'get', dataType: 'json', // 返回的數(shù)據(jù)格式,常用的有是'json','html',"jsonp" data:{ // 設(shè)置發(fā)送給服務(wù)器的數(shù)據(jù),如果是get請(qǐng)求,也可以寫(xiě)在url地址的?后面 "city":'北京' } }) .done(function(resp) { // 請(qǐng)求成功以后的操作 console.log(resp); }) .fail(function(error) { // 請(qǐng)求失敗以后的操作 console.log(error); }); }); }) </script> </head> <body> <button id="btn">點(diǎn)擊獲取數(shù)據(jù)</button> </body> </html>
總結(jié):
1. 發(fā)送ajax請(qǐng)求,要通過(guò)$.ajax(),參數(shù)是對(duì)象,里面有固定的參數(shù)名稱(chēng)。
$.ajax({
"url":"數(shù)據(jù)接口url地址",
"method":"http請(qǐng)求方式,前端只支持get和post",
"dataType":"設(shè)置服務(wù)器返回的數(shù)據(jù)格式,常用的json,html,jsonp,默認(rèn)值就是json",
// 要發(fā)送給后端的數(shù)據(jù)參數(shù),post時(shí),數(shù)據(jù)必須寫(xiě)在data,get可以寫(xiě)在data,也可以跟在地址欄?號(hào)后面
"data":{
"數(shù)據(jù)名稱(chēng)":"數(shù)據(jù)值",
}
}).then(function(resp){ // ajax請(qǐng)求數(shù)據(jù)成功時(shí)會(huì)自動(dòng)調(diào)用then方法的匿名函數(shù)
console.log( resp ); // 服務(wù)端返回的數(shù)據(jù)
}).fail(function(error){ // ajax請(qǐng)求數(shù)據(jù)失敗時(shí)會(huì)自動(dòng)調(diào)用fail方法的匿名函數(shù)
console.log( error );
});
2. ajax的使用往往配合事件/鉤子操作進(jìn)行調(diào)用。
tml | 是否同源 | 原因 |
|---|---|---|
| http://www.oldboy.cn/user/login.html | 是 | 協(xié)議、域名、端口相同 |
| http://www.oldboy.cn/about.html | 是 | 協(xié)議、域名、端口相同 |
| https://www.oldboy.cn/user/login.html | 否 | 協(xié)議不同 ( https和http ) |
| http:/www.oldboy.cn:5000/user/login.html | 否 | 端口 不同( 5000和80) |
| http://bbs.oldboy.cn/user/login.html | 否 |
同源策略針對(duì)ajax的攔截,代碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> <script src="js/axios.js"></script> </head> <body> <div id="app"> <button @click="get_music">點(diǎn)擊獲取天氣</button> </div> <script> let vm = new Vue({ el:"#app", data:{}, methods:{ get_music(){ axios.get("http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.search.catalogSug&query=我的中國(guó)心") .then(response=>{ console.log(response); }).catch(error=>{ console.log(error.response) }); } } }) </script> </body> </html>
Access to XMLHttpRequest at 'http://tingapi.ting.baidu.com/v1/restserver/ting?
method=baidu.ting.search.catalogSug&query=%E6%88%91%E7%9A%84%E4%B8%AD%E5%9B%BD%E5%BF%83' from origin
'http://localhost:63342' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is
present on the requested resource.
上面錯(cuò)誤,關(guān)鍵詞:Access-Control-Allow-Origin
只要出現(xiàn)這個(gè)關(guān)鍵詞,就是訪(fǎng)問(wèn)受限。出現(xiàn)同源策略的攔截問(wèn)題。
4.2.5 ajax跨域(跨源)方案之CORS
CORS是一個(gè)W3C標(biāo)準(zhǔn),全稱(chēng)是"跨域資源共享",它允許瀏覽器向跨源的后端服務(wù)器發(fā)出ajax請(qǐng)求,從而克服了AJAX只能同源使用的限制。
django的視圖
def post(request):
response = new Response()
response .set_header("Access-Control-Allow-Origin","*")
// 在響應(yīng)行信息里面設(shè)置以下內(nèi)容:
Access-Control-Allow-Origin: ajax所在的域名地址
Access-Control-Allow-Origin: www.oldboy.cn # 表示只允許www.oldboy.cn域名的客戶(hù)端的ajax跨域訪(fǎng)問(wèn)
// * 表示任意源,表示允許任意源下的客戶(hù)端的ajax都可以訪(fǎng)問(wèn)當(dāng)前服務(wù)端信息
Access-Control-Allow-Origin: *

同源策略:瀏覽器的一種保護(hù)用戶(hù)數(shù)據(jù)的一種安全機(jī)制。
瀏覽器會(huì)限制腳本語(yǔ)法不能跨源訪(fǎng)問(wèn)其他源的數(shù)據(jù)地址。
同源:判斷兩個(gè)通信的地址之間,是否協(xié)議,域名[IP],端口一致。
ajax: http://127.0.0.1/index.html
api數(shù)據(jù)接口: http://localhost/index
這兩個(gè)是同源么?不是同源的。是否同源的判斷依據(jù)不會(huì)根據(jù)電腦來(lái)判斷,而是通過(guò)協(xié)議、域名、端口的字符串是否來(lái)判斷。
1. ajax默認(rèn)情況下會(huì)受到同源策略的影響,一旦受到影響會(huì)報(bào)錯(cuò)誤如下:
No 'Access-Control-Allow-Origin' header is present on the requested resource
2. 解決ajax只能同源訪(fǎng)問(wèn)數(shù)據(jù)接口的方式:
1. 在服務(wù)端的響應(yīng)行中設(shè)置:
Access-Control-Allow-Origin: 允許訪(fǎng)問(wèn)的域名地址
2. jsonp
3. 是否服務(wù)端代理
思路:通過(guò)python來(lái)請(qǐng)求對(duì)應(yīng)的服務(wù)器接口,獲取到數(shù)據(jù)以后,
組件(Component)是自定義封裝的功能。在前端開(kāi)發(fā)過(guò)程中,經(jīng)常出現(xiàn)多個(gè)網(wǎng)頁(yè)的功能是重復(fù)的,而且很多不同的網(wǎng)站之間,也存在同樣的功能。
而在網(wǎng)頁(yè)中實(shí)現(xiàn)一個(gè)功能,需要使用html定義功能的內(nèi)容結(jié)構(gòu),使用css聲明功能的外觀(guān)樣式,還要使用js來(lái)定義功能的特效,因此就產(chǎn)生了把一個(gè)功能相關(guān)的[HTML、css和javascript]代碼封裝在一起組成一個(gè)整體的代碼塊封裝模式,我們稱(chēng)之為“組件”。
所以,組件就是一個(gè)html網(wǎng)頁(yè)中的功能,一般就是一個(gè)標(biāo)簽,標(biāo)簽中有自己的html內(nèi)容結(jié)構(gòu),css樣式和js特效。
這樣,前端人員就可以在開(kāi)發(fā)時(shí),只需要書(shū)寫(xiě)一次代碼,隨處引入即可使用。
組件有兩種:默認(rèn)組件[全局組件] 和 單文件組件
默認(rèn)組件:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> <style> .header{ width: 100%; height: 40px; } .header ul{ list-style:none; padding:0; margin: 0; overflow: hidden; } .header ul li{ width: 120px; height: 40px; line-height: 40px; text-align: center; color: #fff; background-color: blue; float: left; margin-right: 10px; } </style> </head> <body> <div id="app"> <!-- 頭部 --> <Tou></Tou> //引用Tou標(biāo)簽 <!-- 腳部--> </div> <script> // Vue.component("組件名稱(chēng)",組件的相關(guān)參數(shù)[html,css,js代碼]); Vue.component("Tou",{ //定義一個(gè)Tou標(biāo)簽 template:`<div class="header"> <ul> <li @click="indexHander">{{index}}</li> <li>{{list}}</li> </ul> </div>`, data:function(){ return { index: "首頁(yè)", list:"列表頁(yè)" } }, methods:{ indexHander(){ alert("跳轉(zhuǎn)到首頁(yè)"); } } }); let vm = new Vue({ el:"#app", data:{} }) </script> </body> </html>
6. Vue自動(dòng)化工具(Vue-cli)
6.4 使用Vue-CLI初始化創(chuàng)建項(xiàng)目
6.4.1 生成項(xiàng)目目錄
// 生成一個(gè)基于 webpack 模板的新項(xiàng)目
vue init webpack myproject
// 啟動(dòng)開(kāi)發(fā)服務(wù)器 ctrl+c 停止服務(wù)
cd myproject npm run dev # 運(yùn)行這個(gè)命令就可以啟動(dòng)node提供的測(cè)試http服務(wù)器
訪(fǎng)問(wèn): http://localhost:8080/
├── build/ ├── config/ ├── index.html ├── node_modules/ # 項(xiàng)目運(yùn)行的依賴(lài)庫(kù)存儲(chǔ)目錄[非常大] ├── package.json # 項(xiàng)目運(yùn)行需要的依賴(lài)庫(kù)記錄配置 ├── src/ │ ├── App.vue # 父級(jí)組件 │ ├── assets/ # 靜態(tài)資源目錄,圖片存放在這里 │ ├── components/ # 單文件組件保存目錄 │ └── main.js └── static/ # 靜態(tài)資源目錄,所有的css,js等文件放在這個(gè)目錄
src 主開(kāi)發(fā)目錄,要開(kāi)發(fā)的單文件組件全部在這個(gè)目錄下的components目錄下
static 靜態(tài)資源目錄,所有的css,js文件放在這個(gè)文件夾
dist 項(xiàng)目打包發(fā)布文件夾,最后要上線(xiàn)單文件項(xiàng)目文件都在這個(gè)文件夾中[后面打包項(xiàng)目,讓項(xiàng)目中的vue組件經(jīng)過(guò)編譯變成js 代碼以后,dist就出現(xiàn)了]
config是配置目錄,
build是項(xiàng)目打包時(shí)依賴(lài)的目錄
src/router 路由,后面需要我們?cè)谑褂肦outer路由的時(shí)候,自己聲明.

普通組件的缺點(diǎn):
-
html代碼是作為js的字符串進(jìn)行編寫(xiě),所以組裝和開(kāi)發(fā)的時(shí)候不易理解,而且沒(méi)有高亮效果。
-
普通組件用在小項(xiàng)目中非常合適,但是復(fù)雜的大項(xiàng)目中,如果把更多的組件放在html文件中,那么維護(hù)成本就會(huì)變得非常昂貴。
-
普通組件只是整合了js和html,但是css代碼被剝離出去了。使用的時(shí)候的時(shí)候不好處理。
將一個(gè)組件相關(guān)的html結(jié)構(gòu),css樣式,以及交互的JavaScript代碼從html文件中剝離出來(lái),合成一個(gè)文件,這種文件就是單文件組件,相當(dāng)于一個(gè)組件具有了結(jié)構(gòu)、表現(xiàn)和行為的完整功能,方便組件之間隨意組合以及組件的重用,這種文件的擴(kuò)展名為“.vue”,比如:"Home.vue"。
<template> </template> <script> </script> <style> </style>
<template> <div id="Home"> # 所有代碼要在一個(gè)塊里面 <Header/> <div class="main"> 頁(yè)面主題內(nèi)容 </div> <div class="footer"> 頁(yè)面腳步內(nèi)容 </div> </div> </template> 下面寫(xiě)法會(huì)報(bào)錯(cuò) <template> <Header/> <div class="main"> 頁(yè)面主題內(nèi)容 </div> <div class="footer"> 頁(yè)面腳步內(nèi)容 </div> </template>
<script> import Header from "./common/Header" export default { name:"Home", // 組件名稱(chēng),用于以后路由跳轉(zhuǎn) data(){ // 當(dāng)前組件中需要使用的數(shù)據(jù) return { } }, components:{ Header, } } </script>
// scoped 表示當(dāng)前style的樣式只作用于當(dāng)前組件的template代碼中,其他地方不會(huì)被影響 <style scoped> .header{ height: 100px; line-height: 100px; background-color: #eee; text-align: center; } </style>
home組件引入header組件 (和app中引入Home類(lèi)似)

<template> <div id="Home"> <Header/> <div class="main"> <p>加減數(shù)字的功能</p> <div class="box"> <button @click="num++">+</button> <input type="text" v-model="num"> <button @click="num--">-</button> </div> </div> <div class="footer"> 頁(yè)面腳步內(nèi)容 </div> </div> </template> <script> import Header from "./common/Header" export default { name:"Home", // 組件名稱(chēng),用于以后路由跳轉(zhuǎn) data(){ // 當(dāng)前組件中需要使用的數(shù)據(jù) return { num:0, // 這里需要聲明num } }, components:{ Header, } } </script> // scoped 表示當(dāng)前style的樣式只作用于當(dāng)前組件的template代碼中,其他地方不會(huì)被影響 <style scoped> .header{ height: 100px; line-height: 100px; background-color: #eee; text-align: center; } </style>
<template> <div id="menu"> <span>{{msg}}</span> <p>我是menu視圖,我是主題body部分</p> </div> </template> <script> export default { name:"Menu", // 組件名稱(chēng),用于以后路由跳轉(zhuǎn) data(){ // 當(dāng)前組件中需要使用的數(shù)據(jù) return { msg: "大家好" } } } </script> // scoped 表示當(dāng)前style的樣式只作用于當(dāng)前組件的template代碼中,其他地方不會(huì)被影響 <style scoped> </style>
然后,在父組件 Home.vue 中調(diào)用上面聲明的子組件。
// Menu 首字母大寫(xiě) <template> <div> <Header /> <div class="main"> <p>增減數(shù)字</p> <button @click="num++">+</button> <input type="text" name="" id="" v-model="num"> <button @click="num--">-</button> </div> <Menu /> //調(diào)用 </div> </template> <script> import Header from "./common/Header" import Menu from "./common/Menu" //導(dǎo)入 export default{ name: "Home", data(){ return{ num:0, } }, components:{ Header,Menu //聲明 } } </script> <style> </style>
可以通過(guò)props屬性來(lái)進(jìn)行傳遞.
-
在父組件中,調(diào)用子組件的組名處,使用屬性值的方式往下傳遞數(shù)
<template>
<Menu :mynum="num" title="home里面寫(xiě)的數(shù)據(jù)"/>
</template># 上面表示在父組件調(diào)用Menu子組件的時(shí)候傳遞了2個(gè)數(shù)據(jù):
如果要傳遞變量[變量可以各種類(lèi)型的數(shù)據(jù)],屬性名左邊必須加上冒號(hào):,同時(shí),屬性名是自定義的,會(huì)在子組件中使用。
如果要傳遞普通字符串?dāng)?shù)據(jù),則不需要加上冒號(hào): - 在子組件中接受上面父組件傳遞的數(shù)據(jù),需要在vm組件對(duì)象中,使用props屬性類(lèi)接受。
<script> export default { name:"Menu", props:["mynum","title"], //用props接收值 data: function(){ return { msg:"這是Menu組件里面的菜單", } } } </script>
在子組件中的template中使用父組件傳遞過(guò)來(lái)的數(shù)據(jù).
<template> <div id="menu"> <span>{{msg}},{{title}}</span> <div>hello,{{mynum}}</div> </div> </template>
-
傳遞數(shù)據(jù)是變量,則需要在屬性左邊添加冒號(hào).
傳遞數(shù)據(jù)是變量,這種數(shù)據(jù)稱(chēng)之為"動(dòng)態(tài)數(shù)據(jù)傳遞"
傳遞數(shù)據(jù)不是變量,而是數(shù)值或者字符串,這種數(shù)據(jù)稱(chēng)之為"靜態(tài)數(shù)據(jù)傳遞"
-
父組件中修改了數(shù)據(jù),在子組件中會(huì)被同步修改,但是,子組件中的數(shù)據(jù)修改了,是不會(huì)影響到父組件中的數(shù)據(jù).
這種情況,在開(kāi)發(fā)時(shí),也被稱(chēng)為"單向數(shù)據(jù)流"
-
事實(shí)上,我們?nèi)绻谧咏M件中把數(shù)據(jù)傳遞給父組件,也可以完成的。
通過(guò)事件冒泡的方式,進(jìn)行數(shù)據(jù)傳遞
在vue中提供的this.$emit()方法進(jìn)行給我們傳遞數(shù)據(jù)
默認(rèn)情況下,我們的項(xiàng)目中并沒(méi)有對(duì)axios包的支持,所以我們需要下載安裝。
在項(xiàng)目根目錄中使用 npm安裝包在命令行下執(zhí)行安裝包的命令:
npm install axios
接著在main.js文件中,導(dǎo)入axios并把a(bǔ)xios對(duì)象 掛載到vue屬性中多為一個(gè)子對(duì)象,這樣我們才能在組件中使用。
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' // 這里表示從別的目錄下導(dǎo)入 單文件組件 import axios from 'axios'; // 從node_modules目錄中導(dǎo)入包 Vue.config.productionTip = false Vue.prototype.$http = axios; // 把對(duì)象掛載vue中 $http 可以自己定義名稱(chēng) /* eslint-disable no-new */ new Vue({ el: '#app', components: { App }, template: '<App/>' });
代碼編寫(xiě)在Heaer.vue子組件中
<template> <div id="Header" class="header"> {{message}} <p>num: <input type="text" v-model="num"></p> <p>深圳的天氣情況: {{weather_info}}</p> </div> </template> <script> export default { name:"Header", // 組件名稱(chēng),用于以后路由跳轉(zhuǎn) props:["num"], data(){ // 當(dāng)前組件中需要使用的數(shù)據(jù) return { message:"頁(yè)面頭部", weather_info:"", } }, // 鉤子方法,在頁(yè)面中vue掛在data數(shù)據(jù)以后,自動(dòng)執(zhí)行 created() { // 使用axios發(fā)送請(qǐng)求獲取數(shù)據(jù) this.$http.get("http://wthrcdn.etouch.cn/weather_mini?city=深圳").then(response=>{ console.log(response.data); console.log(response.data.data.ganmao); this.weather_info = response.data.data.ganmao; }).catch(error=>{ }); } } </script> // scoped 表示當(dāng)前style的樣式只作用于當(dāng)前組件的template代碼中,其他地方不會(huì)被影響 <style scoped> .header{ height: 100px; line-height: 100px; background-color: #eee; text-align: center; } </style>
使用的時(shí)候,因?yàn)楸举|(zhì)上來(lái)說(shuō),我們還是原來(lái)的axios,所以也會(huì)收到同源策略的影響。
后面開(kāi)發(fā)項(xiàng)目的時(shí)候,我們會(huì)使用cors來(lái)解決跨域的問(wèn)題

浙公網(wǎng)安備 33010602011771號(hào)