vue.js默認沒有提供ajax功能的。javascript
因此使用vue的時候,通常都會使用axios的插件來實現ajax與後端服務器的數據交互。css
注意,axios本質上就是javascript的ajax封裝,因此會被同源策略限制。html
前端
https://unpkg.com/axios@0.18.0/dist/axios.js
https://unpkg.com/axios@0.18.0/dist/axios.min.js
axios提供發送請求的經常使用方法有兩個:axios.get() 和 axios.post() 。vue
增 postjava
刪 deletenode
改 putpython
查 getjquery
// 發送get請求
// 參數1: 必填,字符串,請求的數據接口的url地址,例如請求地址:http://www.baidu.com?id=200
// 參數2:可選,json對象,要提供給數據接口的參數
// 參數3:可選,json對象,請求頭信息
axios.get('服務器的資源地址',{ // http://www.baidu.com
params:{
參數名:'參數值', // id: 200,
}
}).then(function (response) { // 請求成功之後的回調函數
console.log("請求成功");
console.log(response);
}).catch(function (error) { // 請求失敗之後的回調函數
console.log("請求失敗");
console.log(error.response);
});
// 發送post請求,參數和使用和axios.get()同樣。
// 參數1: 必填,字符串,請求的數據接口的url地址
// 參數2:必填,json對象,要提供給數據接口的參數,若是沒有參數,則必須使用{}
// 參數3:可選,json對象,請求頭信息
axios.post('服務器的資源地址',{
username: 'xiaoming',
password: '123456'
},{
responseData:"json",
})
.then(function (response) { // 請求成功之後的回調函數
console.log(response);
})
.catch(function (error) { // 請求失敗之後的回調函數
console.log(error);
});
// json數據的對象格式:
{
"name":"tom",
"age":18
}
// json數據的數組格式:
["tom",18,"programmer"]
複雜的json格式數據能夠包含對象和數組的寫法。
{
"name":"小明",
"age":200,
"fav":["code","eat","swim","read"],
"son":{
"name":"小小明",
"age":100,
"lve":["code","eat"],
}
}
方法 | 參數 | 返回值 | 描述 |
---|---|---|---|
stringify | json對象 | 字符串 | json對象轉成字符串 |
parse | 字符串 | json對象 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> // json語法 let humen = { "username":"xiaohui", "password":"1234567", "age":20 }; console.log(humen); console.log(typeof humen); // JSON對象提供對json格式數據的轉換功能 // stringify(json對象) # 用於把json轉換成字符串 let result = JSON.stringify(humen); console.log(result); console.log(typeof result); // parse(字符串類型的json數據) # 用於把字符串轉成json對象 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,通常中文稱之爲:"阿賈克斯",是英文 「Async Javascript And Xml」的簡寫,譯做:異步js和xml數據傳輸數據。webpack
因此開發中ajax是很經常使用的技術,主要用於操做後端提供的數據接口,從而實現網站的先後端分離。
ajax技術的原理是實例化js的XMLHttpRequest對象,使用此對象提供的內置方法就能夠與後端進行數據通訊。
數據接口,也叫api接口,表示
客戶端經過發起請求向服務端提供的url地址申請操做數據【操做通常:增刪查改】
同時在工做中,大部分數據接口都不是手寫,而是經過函數庫/框架來生成。
編寫代碼獲取接口提供的數據:
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,提交數據的方式,默認是'GET',經常使用的還有'POST' type: 'get', dataType: 'json', // 返回的數據格式,經常使用的有是'json','html',"jsonp" data:{ // 設置發送給服務器的數據,若是是get請求,也能夠寫在url地址的?後面 "city":'北京' } }) .done(function(resp) { // 請求成功之後的操做 console.log(resp); }) .fail(function(error) { // 請求失敗之後的操做 console.log(error); }); }); }) </script> </head> <body> <button id="btn">點擊獲取數據</button> </body> </html>
總結:
1. 發送ajax請求,要經過$.ajax(),參數是對象,裏面有固定的參數名稱。
$.ajax({
"url":"數據接口url地址",
"method":"http請求方式,前端只支持get和post",
"dataType":"設置服務器返回的數據格式,經常使用的json,html,jsonp,默認值就是json",
// 要發送給後端的數據參數,post時,數據必須寫在data,get能夠寫在data,也能夠跟在地址欄?號後面
"data":{
"數據名稱":"數據值",
}
}).then(function(resp){ // ajax請求數據成功時會自動調用then方法的匿名函數
console.log( resp ); // 服務端返回的數據
}).fail(function(error){ // ajax請求數據失敗時會自動調用fail方法的匿名函數
console.log( error );
});
2. ajax的使用每每配合事件/鉤子操做進行調用。
tml |
是否同源 | 緣由 |
---|---|---|
http://www.oldboy.cn/user/login.html | 是 | 協議、域名、端口相同 |
http://www.oldboy.cn/about.html | 是 | 協議、域名、端口相同 |
https://www.oldboy.cn/user/login.html | 否 | 協議不一樣 ( https和http ) |
http:/www.oldboy.cn:5000/user/login.html | 否 | 端口 不一樣( 5000和80) |
http://bbs.oldboy.cn/user/login.html | 否 |
同源策略針對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">點擊獲取天氣</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=個人中國心") .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.
上面錯誤,關鍵詞:Access-Control-Allow-Origin
只要出現這個關鍵詞,就是訪問受限。出現同源策略的攔截問題。
4.2.5 ajax跨域(跨源)方案之CORS
CORS是一個W3C標準,全稱是"跨域資源共享",它容許瀏覽器向跨源的後端服務器發出ajax請求,從而克服了AJAX只能同源使用的限制。
django的視圖
def post(request):
response = new Response()
response .set_header("Access-Control-Allow-Origin","*")
// 在響應行信息裏面設置如下內容:
Access-Control-Allow-Origin: ajax所在的域名地址
Access-Control-Allow-Origin: www.oldboy.cn # 表示只容許www.oldboy.cn域名的客戶端的ajax跨域訪問
// * 表示任意源,表示容許任意源下的客戶端的ajax均可以訪問當前服務端信息
Access-Control-Allow-Origin: *
同源策略:瀏覽器的一種保護用戶數據的一種安全機制。
瀏覽器會限制腳本語法不能跨源訪問其餘源的數據地址。
同源:判斷兩個通訊的地址之間,是否協議,域名[IP],端口一致。
ajax: http://127.0.0.1/index.html
api數據接口: http://localhost/index
這兩個是同源麼?不是同源的。是否同源的判斷依據不會根據電腦來判斷,而是經過協議、域名、端口的字符串是否來判斷。
1. ajax默認狀況下會受到同源策略的影響,一旦受到影響會報錯誤以下:
No 'Access-Control-Allow-Origin' header is present on the requested resource
2. 解決ajax只能同源訪問數據接口的方式:
1. 在服務端的響應行中設置:
Access-Control-Allow-Origin: 容許訪問的域名地址
2. jsonp
3. 是否服務端代理
思路:經過python來請求對應的服務器接口,獲取到數據之後,
組件(Component)是自定義封裝的功能。在前端開發過程當中,常常出現多個網頁的功能是重複的,並且不少不一樣的網站之間,也存在一樣的功能。
而在網頁中實現一個功能,須要使用html定義功能的內容結構,使用css聲明功能的外觀樣式,還要使用js來定義功能的特效,所以就產生了把一個功能相關的[HTML、css和javascript]代碼封裝在一塊兒組成一個總體的代碼塊封裝模式,咱們稱之爲「組件」。
因此,組件就是一個html網頁中的功能,通常就是一個標籤,標籤中有本身的html內容結構,css樣式和js特效。
這樣,前端人員就能夠在開發時,只須要書寫一次代碼,隨處引入便可使用。
組件有兩種:默認組件[全局組件] 和 單文件組件
默認組件:
<!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標籤 <!-- 腳部--> </div> <script> // Vue.component("組件名稱",組件的相關參數[html,css,js代碼]); Vue.component("Tou",{ //定義一個Tou標籤 template:`<div class="header"> <ul> <li @click="indexHander">{{index}}</li> <li>{{list}}</li> </ul> </div>`, data:function(){ return { index: "首頁", list:"列表頁" } }, methods:{ indexHander(){ alert("跳轉到首頁"); } } }); let vm = new Vue({ el:"#app", data:{} }) </script> </body> </html>
// 生成一個基於 webpack 模板的新項目
vue init webpack myproject
// 啓動開發服務器 ctrl+c 中止服務
cd myproject npm run dev # 運行這個命令就能夠啓動node提供的測試http服務器
├── build/ ├── config/ ├── index.html ├── node_modules/ # 項目運行的依賴庫存儲目錄[很是大] ├── package.json # 項目運行須要的依賴庫記錄配置 ├── src/ │ ├── App.vue # 父級組件 │ ├── assets/ # 靜態資源目錄,圖片存放在這裏 │ ├── components/ # 單文件組件保存目錄 │ └── main.js └── static/ # 靜態資源目錄,全部的css,js等文件放在這個目錄
src 主開發目錄,要開發的單文件組件所有在這個目錄下的components目錄下
static 靜態資源目錄,全部的css,js文件放在這個文件夾
dist 項目打包發佈文件夾,最後要上線單文件項目文件都在這個文件夾中[後面打包項目,讓項目中的vue組件通過編譯變成js 代碼之後,dist就出現了]
config是配置目錄,
build是項目打包時依賴的目錄
src/router 路由,後面須要咱們在使用Router路由的時候,本身聲明.
普通組件的缺點:
html代碼是做爲js的字符串進行編寫,因此組裝和開發的時候不易理解,並且沒有高亮效果。
普通組件用在小項目中很是合適,可是複雜的大項目中,若是把更多的組件放在html文件中,那麼維護成本就會變得很是昂貴。
普通組件只是整合了js和html,可是css代碼被剝離出去了。使用的時候的時候很差處理。
將一個組件相關的html結構,css樣式,以及交互的JavaScript代碼從html文件中剝離出來,合成一個文件,這種文件就是單文件組件,至關於一個組件具備告終構、表現和行爲的完整功能,方便組件之間隨意組合以及組件的重用,這種文件的擴展名爲「.vue」,好比:"Home.vue"。
<template> </template> <script> </script> <style> </style>
<template> <div id="Home"> # 全部代碼要在一個塊裏面 <Header/> <div class="main"> 頁面主題內容 </div> <div class="footer"> 頁面腳步內容 </div> </div> </template> 下面寫法會報錯 <template> <Header/> <div class="main"> 頁面主題內容 </div> <div class="footer"> 頁面腳步內容 </div> </template>
<script> import Header from "./common/Header" export default { name:"Home", // 組件名稱,用於之後路由跳轉 data(){ // 當前組件中須要使用的數據 return { } }, components:{ Header, } } </script>
// scoped 表示當前style的樣式只做用於當前組件的template代碼中,其餘地方不會被影響 <style scoped> .header{ height: 100px; line-height: 100px; background-color: #eee; text-align: center; } </style>
home組件引入header組件 (和app中引入Home相似)
<template> <div id="Home"> <Header/> <div class="main"> <p>加減數字的功能</p> <div class="box"> <button @click="num++">+</button> <input type="text" v-model="num"> <button @click="num--">-</button> </div> </div> <div class="footer"> 頁面腳步內容 </div> </div> </template> <script> import Header from "./common/Header" export default { name:"Home", // 組件名稱,用於之後路由跳轉 data(){ // 當前組件中須要使用的數據 return { num:0, // 這裏須要聲明num } }, components:{ Header, } } </script> // scoped 表示當前style的樣式只做用於當前組件的template代碼中,其餘地方不會被影響 <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", // 組件名稱,用於之後路由跳轉 data(){ // 當前組件中須要使用的數據 return { msg: "你們好" } } } </script> // scoped 表示當前style的樣式只做用於當前組件的template代碼中,其餘地方不會被影響 <style scoped> </style>
而後,在父組件 Home.vue 中調用上面聲明的子組件。
// Menu 首字母大寫 <template> <div> <Header /> <div class="main"> <p>增減數字</p> <button @click="num++">+</button> <input type="text" name="" id="" v-model="num"> <button @click="num--">-</button> </div> <Menu /> //調用 </div> </template> <script> import Header from "./common/Header" import Menu from "./common/Menu" //導入 export default{ name: "Home", data(){ return{ num:0, } }, components:{ Header,Menu //聲明 } } </script> <style> </style>
能夠經過props屬性來進行傳遞.
在父組件中,調用子組件的組名處,使用屬性值的方式往下傳遞數
<template>
<Menu :mynum="num" title="home裏面寫的數據"/>
</template>
# 上面表示在父組件調用Menu子組件的時候傳遞了2個數據:
若是要傳遞變量[變量能夠各類類型的數據],屬性名左邊必須加上冒號:,同時,屬性名是自定義的,會在子組件中使用。
若是要傳遞普通字符串數據,則不須要加上冒號:
<script> export default { name:"Menu", props:["mynum","title"], //用props接收值 data: function(){ return { msg:"這是Menu組件裏面的菜單", } } } </script>
在子組件中的template中使用父組件傳遞過來的數據.
<template> <div id="menu"> <span>{{msg}},{{title}}</span> <div>hello,{{mynum}}</div> </div> </template>
傳遞數據是變量,則須要在屬性左邊添加冒號.
傳遞數據是變量,這種數據稱之爲"動態數據傳遞"
傳遞數據不是變量,而是數值或者字符串,這種數據稱之爲"靜態數據傳遞"
父組件中修改了數據,在子組件中會被同步修改,可是,子組件中的數據修改了,是不會影響到父組件中的數據.
這種狀況,在開發時,也被稱爲"單向數據流"
事實上,咱們若是要在子組件中把數據傳遞給父組件,也能夠完成的。
經過事件冒泡的方式,進行數據傳遞
在vue中提供的this.$emit()方法進行給咱們傳遞數據
默認狀況下,咱們的項目中並無對axios包的支持,因此咱們須要下載安裝。
在項目根目錄中使用 npm安裝包在命令行下執行安裝包的命令:
npm install axios
接着在main.js文件中,導入axios並把axios對象 掛載到vue屬性中多爲一個子對象,這樣咱們才能在組件中使用。
// 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' // 這裏表示從別的目錄下導入 單文件組件 import axios from 'axios'; // 從node_modules目錄中導入包 Vue.config.productionTip = false Vue.prototype.$http = axios; // 把對象掛載vue中 $http 能夠本身定義名稱 /* eslint-disable no-new */ new Vue({ el: '#app', components: { App }, template: '<App/>' });
代碼編寫在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", // 組件名稱,用於之後路由跳轉 props:["num"], data(){ // 當前組件中須要使用的數據 return { message:"頁面頭部", weather_info:"", } }, // 鉤子方法,在頁面中vue掛在data數據之後,自動執行 created() { // 使用axios發送請求獲取數據 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 表示當前style的樣式只做用於當前組件的template代碼中,其餘地方不會被影響 <style scoped> .header{ height: 100px; line-height: 100px; background-color: #eee; text-align: center; } </style>
使用的時候,由於本質上來講,咱們仍是原來的axios,因此也會收到同源策略的影響。
後面開發項目的時候,咱們會使用cors來解決跨域的問題