VUE入門
1.vue.js的快速入門使用
1.1 vue.js庫的下載
vue.js是目前前端web開發最流行的工具庫,由尤雨溪在2014年2月發布的。
另外幾個常見的工具庫:react.js /angular.js
官方網站:
中文://cn.vuejs.org/
英文://vuejs.org/
vue.js目前有1.x、2.x和3.x 版本,我們學習2.x版本的。
1.2 vue.js庫的基本使用
在github下載:
在官網下載地址: //cn.vuejs.org/v2/guide/installation.html
vue的引入類似於jQuery,開發中可以使用開發版本vue.js,產品上線要換成vue.min.js。
下圖是github網站下載的vue.js目錄
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
window.onload = function(){
// vue.js的程式碼開始於一個Vue對象。所以每次操作數據都要聲明Vue對象開始。
var vm = new Vue({
el:'#app', // 設置當前vue對象要控制的標籤範圍。
data:{ // data是將要展示到HTML標籤元素中的數據。
message: 'hello world!',
}
});
}
</script>
</head>
<body>
<div id="app">
<!-- {{ message }} 表示把vue對象裡面data屬性中的對應數據輸出到頁面中 -->
<!-- 在雙標籤中顯示數據要通過{{ }}來完成 -->
<p>{{ message }}</p>
</div>
</body>
</html>
總結:
1. vue的使用要從創建Vue對象開始
var vm = new Vue();
2. 創建vue對象的時候,需要傳遞參數,是json對象,json對象對象必須至少有兩個屬性成員
var vm = new Vue({
el:"#app",
data: {
數據變數:"變數值",
數據變數:"變數值",
數據變數:"變數值",
},
});
el:設置vue可以操作的html內容範圍,值一般就是css的id選擇器。
data: 保存vue.js中要顯示到html頁面的數據。
3. vue.js要控制器的內容外圍,必須先通過id來設置。
<div id="app">
<h1>{{message}}</h1>
<p>{{message}}</p>
</div>
1.3 vue.js的M-V-VM思想
MVVM 是Model-View-ViewModel 的縮寫,它是一種基於前端開發的架構模式。
Model
指代的就是vue對象的data屬性裡面的數據。這裡的數據要顯示到頁面中。
View
指代的就是vue中數據要顯示的HTML頁面,在vue中,也稱之為「視圖模板」 。
ViewModel
指代的是vue.js中我們編寫程式碼時的vm對象了,它是vue.js的核心,負責連接 View 和 Model,保證視圖和數據的一致性,所以前面程式碼中,data裡面的數據被顯示中p標籤中就是vm對象自動完成的。
編寫程式碼,讓我們更加清晰的了解MVVM:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
window.onload = function(){
// vm視圖控制對象,會實時監控,時刻保證data屬性中的數據和html視圖中的內容保持一致:
vm = new Vue({
el: "#app",
data:{
img: "logo.png",
num: 1,
content:"<h1>大標題</h1>",
url:"//www.baidu.com"
},
// 事件觸發時調用的方法,或者其他屬性方法中調用的內部方法
methods:{
show(){
alert("hello")
}
}
});
}
// js中也有三元表達式,也叫三元運算符
// 格式:
// 條件?true:false;
</script>
</head>
<body>
<div id="app">
<input type="text" v-model="img">
{{"圖片地址是:"+img}}
<span v-html="img.toLocaleUpperCase()"></span>
<img :src="img">
{{num%2==0?"偶數":"奇數"}}<br>
<p v-html="content"></p>
<p v-text="content"></p>
{{content}}<br>
<!-- <a v-bind:href="url">路飛</a>-->
<a :href="url">百度</a>
<p @click="show">內容</p>
<!-- <p v-on:click="show">內容</p>-->
</div>
</body>
</html>
在瀏覽器中可以在 console.log通過 vm對象可以直接訪問el和data屬性,甚至可以訪問data裡面的數據
console.log(vm.$el) # #box vm對象可以控制的範圍
console.log(vm.$data); # vm對象要顯示到頁面中的數據
console.log(vm.$data.message); # 訪問data裡面的數據
console.log(vm.message);# 這個 message就是data裡面聲明的數據,也可以使用 vm.變數名顯示其他數據,message只是舉例.
總結:
1. 如果要輸出data裡面的數據作為普通標籤的內容,需要使用{{ }}
用法:
vue對象的data屬性:
data:{
name:"小明",
}
標籤元素:
<h1>{{ name }}</h1>
2. 如果要輸出data裡面的數據作為表單元素的值,需要使用vue.js提供的元素屬性v-model
用法:
vue對象的data屬性:
data:{
name:"小明",
}
表單元素:
<input v-model="name">
使用v-model把data裡面的數據顯示到表單元素以後,一旦用戶修改表單元素的值,則data裡面對應數據的值也會隨之發生改變,甚至,頁面中凡是使用了這個數據都會發生變化。
3. 可以在普通標籤中使用{{ }} 或者 v-html 來輸出data裡面的數據
<h1>{{message}}</h1>
4. 可以在表單標籤中使用v-model屬性來輸出data裡面的數據,同時還可以修改data裡面的數據
<input type="text" v-model="username">
2. 常用指令
指令 (Directives) 是帶有「v-」前綴的特殊屬性。每一個指令在vue中都有固定的作用。
在vue中,提供了很多指令,常用的有:v-if、v-model、v-for等等。
指令會在vm對象的data屬性的數據發生變化時,會同時改變元素中的其控制的內容或屬性。
因為vue的歷史版本原因,所以有一部分指令都有兩種寫法:
vue1.x寫法 vue2.x的寫法
v-html ----> {{ 普通文本 }} # vue2.x 也支援v-html,v-text,輸出html程式碼的內容
v-bind:屬性名 ----> :屬性
v-on:事件名 ----> @事件名
2.1 操作屬性
格式:
<標籤名 :標籤屬性="data屬性"></標籤名>
<p :title="str1">{{ str1 }}</p> <!-- 也可以使用v-html顯示雙標籤的內容,{{ }} 是簡寫 -->
<a :href="url2">淘寶</a>
顯示wifi密碼效果:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input :type="tp">
<input type="button" @mousedown="down" @mouseup="up" v-model="message">
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
message:"顯示密碼",
tp:"password",
},
methods:{
down(){
// 在methods中的子方法裡面要操作data的屬性,可以使用this.屬性值
this.tp="text";
this.message="隱藏密碼";
},
up(){
this.tp="password";
this.message="顯示密碼";
}
}
})
</script>
</body>
</html>
2.2 事件綁定
有兩種事件操作的寫法,@事件名 和 v-on:事件名
<button @click="num+=5">按鈕2</button>
總結:
1. 使用@事件名來進行事件的綁定
語法:
<h1 @click="num++">{{num}}</h1>
2. 綁定的事件的事件名,全部都是js的事件名:
@submit ---> onsubmit
@focus ---> onfocus
....
完成商城購物車中的商品增加減少數量
步驟:
- 給vue對象添加操作數據的方法
- 在標籤中使用指令調用操作數據的方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button @click="add">+</button>
<input type="text" v-model="num">
<button @click="sub">-</button>
單價:{{price}}
<!-- 保留兩位小數-->
<p>總計:{{total.toFixed(2)}}</p>
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
num: 1,
price: 39.8,
total: 39.8,
},
methods:{
add(){
// 增加數量 轉化數字相加
this.num = parseInt(this.num) + 1;
this.calc();
},
sub(){
// 減少數量
if(this.num<=1){
return;
}
this.num -= 1;
this.calc();
},
calc(){
// 計算總價
this.total = this.price * this.num;
}
}
})
</script>
</body>
</html>
2.3 操作樣式
2.3.1 控制標籤class類名
格式:
<h1 :class="值">元素</h1> 值可以是字元串、對象、對象名、數組
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.box{
width: 100px;
height: 100px;
background-color: #ff6666;
}
.box1{
border-radius: 22px;
}
.box2{
width: 200px;
height: 200px;
background-color: #66f;
}
</style>
</head>
<body>
<div id="app">
<div :class="cls"></div>
<div :class="[cls,cls2]"></div>
<div :class="{box1:show_box1,box2:show_box2}"></div>
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
cls: "box",
cls2: "box1",
// 布爾值變數如果是true,則不會添加對象的屬性名作為樣式
show_box1:false,
show_box2:true,
},
})
</script>
</body>
</html>
總結:
1. 給元素綁定class類名,最常用的就是第二種。
vue對象的data數據:
data:{
myObj:{
complete:true,
uncomplete:false,
}
}
html元素:
<div class="box" :class="myObj">2222</div>
最終瀏覽器效果:
<div class="box complete">2222</div>
控制白天黑夜
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.bg{
width: 300px;
height: 1000px;
}
.baitian{
background-color: white;
}
.heiye{
background-color: #666;
}
</style>
</head>
<body>
<div id="app" class="bg" :class="{baitian:is_show,heiye:is_show_2}">
<button @click="change">關燈</button>
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
is_show:true,
is_show_2:false
},
methods:{
change(){
if(this.is_show==true){
this.is_show=false;
this.is_show_2=true;
}else{
this.is_show=true;
this.is_show_2=false;
}
}
}
})
</script>
</body>
</html>
2.3.2 控制標籤style樣式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div style="width:100px;height:100px;" :style="{backgroundColor:`#6f6`}"></div>
<div style="" :style="box"></div>
<div style="" :style="[box,box2]"></div>
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
box:{
backgroundColor:`#6f6`,
width:"100px",
height:"100px",
},
box2:{
borderRadius:"50px", // borderRadius 邊框圓角
}
},
})
</script>
</body>
</html>
2.3.2 實例-vue版本選項卡
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#card{
width: 500px;
height: 350px;
}
.title{
height:50px;
}
.title span{
width: 100px;
height: 50px;
background-color:#ccc;
display: inline-block;
line-height: 50px; /* 設置行和當前元素的高度相等,就可以讓文本內容上下居中 */
text-align:center;
}
.content .list{
width: 500px;
height: 300px;
background-color: yellow;
display: none;
}
.content .active{
display: block;
}
.title .current{
background-color:yellow;
}
</style>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="card">
<div class="title">
<span @mouseover="num=1" :class="num==1?'current':''">中國新聞</span>
<span @mouseover="num=2" :class="num==2?'current':''">國際新聞</span>
<span @mouseover="num=3" :class="num==3?'current':''">銀河新聞</span>
</div>
<div class="content">
<div class="list" :class="num==1?'active':''">中國新聞列表</div>
<div class="list" :class="num==2?'active':''">國際新聞列表</div>
<div class="list" :class="num==3?'active':''">銀河新聞列表</div>
</div>
</div>
<script>
// 實現一個js的特效時:關鍵是找出3個數據出來
// 1. 用戶操作的元素
// 2. 用戶觸發的事件
// 3. 事件觸發以後的效果是什麼?
var vm = new Vue({
el:"#card",
data:{
num:1,
}
})
</script>
</body>
</html>
思路:
當用戶點擊標題欄的按鈕[span]時,顯示對應索引下標的內容塊[.list]
程式碼實現:
2.4 條件渲染指令
vue中提供了兩個指令可以用於判斷是否要顯示元素,分別是v-if和v-show。
2.4.1 v-if
標籤元素:
<!-- vue對象最終會把條件的結果變成布爾值 -->
<h1 v-if="ok">Yes</h1>
data數據:
data:{
ok:false // true則是顯示,false是隱藏
}
2.4.2 v-else
v-else指令來表示 v-if 的「else 塊」,v-else 元素必須緊跟在帶 v-if 或者 v-else-if 的元素的後面,否則它將不會被識別。
標籤元素:
<h1 v-if="ok">Yes</h1>
<h1 v-else>No</h1>
data數據:
data:{
ok:false // true則是顯示,false是隱藏
}
2.4.3 v-else-if
可以出現多個v-else-if語句,但是v-else-if之前必須有一個v-if開頭。後面可以跟著v-else,也可以沒有。
標籤元素:
<h1 v-if="num==1">num的值為1</h1>
<h1 v-else-if="num==2">num的值為2</h1>
<h1 v-else>num的值是{{num}}</h1>
data數據:
data:{
num:2
}
2.4.4 v-show
用法和v-if大致一樣,區別在於2點:
- v-show後面不能v-else或者v-else-if
- v-show隱藏元素時,使用的是display:none來隱藏的,而v-if是直接從HTML文檔中移除元素[ DOM操作中的remove ]
標籤元素:
<h1 v-show="ok">Hello!</h1>
data數據:
data:{
ok:false // true則是顯示,false是隱藏
}
2.5 列表渲染指令
在vue中,可以通過v-for指令可以將一組數據渲染到頁面中,數據可以是數組或者對象。
數據是數組
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<table border="1" width="800px">
<tr>
<th>序號</th>
<th>id</th>
<th>姓名</th>
<th>年齡</th>
</tr>
<tr v-for="v,k in student_list">
<td>{{k+1}}</td>
<td>{{v.id}}</td>
<td>{{v.name}}</td>
<td>{{v.age}}</td>
</tr>
</table>
</div>
<script>
var vm1 = new Vue({
el:"#app",
data:{
student_list:[
{"id":1,"name":"zbb","age":18},
{"id":1,"name":"zbb","age":18},
{"id":1,"name":"zbb","age":18},
{"id":1,"name":"zbb","age":18},
{"id":1,"name":"zbb","age":18},
]
},
})
</script>
</body>
</html>
數據是對象:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<ul id="app">
<!-- v是每一個value值,j是每一個鍵名-->
<li v-for="v, j in book">{{j}}:{{v}}</li>
</ul>
<script>
var vm1 = new Vue({
el:"#app",
data:{
book: {
// "attr":"value"
"id":11,
"title":"圖書名稱1",
"price":200
},
},
})
</script>
</body>
</html>
練習:
goods:[
{"name":"python入門","price":150},
{"name":"python進階","price":100},
{"name":"python高級","price":75},
{"name":"python研究","price":60},
{"name":"python放棄","price":110},
]
# 把上面的數據採用table表格輸出到頁面,價格大於60的數據需要添加背景色橙色[orange]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<style>
.orange{
background: orange ;
}
</style>
<body>
<div id="app">
<table border="1" width="800px">
<tr>
<th>序號</th>
<th>課程</th>
<th>價格</th>
</tr>
<tr v-for="v,k in goods" :class="v.price>60?'orange':''">
<td>{{k+1}}</td>
<td>{{v.name}}</td>
<td>{{v.price}}</td>
</tr>
</table>
</div>
<script>
var vm1 = new Vue({
el: "#app",
data: {
goods: [
{"name": "python入門", "price": 150},
{"name": "python進階", "price": 100},
{"name": "python高級", "price": 75},
{"name": "python研究", "price": 60},
{"name": "python放棄", "price": 110},
]
},
})
</script>
</body>
</html>
2.6 在表中添加數據
第一步:
循環表格, 編寫添加對話框, 更新列表,編寫刪除按鈕
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<style>
.win {
background: orange;
width: 300px;
height: 100px;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
</style>
<body>
<div id="app">
<table border="1" width="800px" align="center">
<td colspan="5">
<button @click="win_show = 1">add</button>
</td>
<tr>
<th>序號</th>
<th>課程</th>
<th>價格</th>
<th>按鈕</th>
</tr>
<tr v-for="v,k in goods">
<td>{{k+1}}</td>
<td>{{v.name}}</td>
<td>{{v.price}}</td>
<td>
<button>edit</button>
<button @click="del(k)">del</button>
</td>
</tr>
</table>
<div class="win" v-show=win_show>
<lable>課程:<input type="text" v-model="name"></lable>
<br>
<lable>價格:<input type="text" v-model="price"></lable>
<br>
<button @click="sava">確定</button>
<button @click="close">取消</button>
</div>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
win_show: false,
goods: [
{"name": "python入門", "price": 150},
{"name": "python進階", "price": 100},
{"name": "python高級", "price": 75},
{"name": "python研究", "price": 60},
{"name": "python放棄", "price": 110},
],
name: "",
price: "",
},
methods: {
sava() {
// 追加成員
this.goods.push({
"name": this.name,
"price": this.price
});
this.close();
},
close() {
// 關閉窗口
this.win_show = false;
// 清空窗口中的數據
this.title = "";
this.number = "";
this.price = ""
},
del(k){
this.goods.splice(k,1)
}
}
})
</script>
</body>
</html>
第二步,編輯按鈕
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<style>
.win {
background: orange;
width: 300px;
height: 100px;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
</style>
<body>
<div id="app">
<table border="1" width="800px" align="center">
<td colspan="5">
<button @click="win_show = 1">add</button>
</td>
<tr>
<th>序號</th>
<th>課程</th>
<th>價格</th>
<th>按鈕</th>
</tr>
<tr v-for="v,k in goods">
<td>{{k+1}}</td>
<td>{{v.name}}</td>
<td>{{v.price}}</td>
<td>
<button @click="edit(k)">edit</button>
<button @click="del(k)">del</button>
</td>
</tr>
</table>
<div class="win" v-show=win_show>
<lable>課程:<input type="text" v-model="name"></lable>
<br>
<lable>價格:<input type="text" v-model="price"></lable>
<br>
<button @click="sava">確定</button>
<button @click="close">取消</button>
</div>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
win_show: false,
goods: [
{"name": "python入門", "price": 150},
{"name": "python進階", "price": 100},
{"name": "python高級", "price": 75},
{"name": "python研究", "price": 60},
{"name": "python放棄", "price": 110},
],
name: "",
price: "",
current: -1, //沒有編輯任何的內容
},
methods: {
sava() {
if (this.current == -1) {
// 追加成員
this.goods.push({
"name": this.name,
"price": this.price
});
}else{
//編輯
this.goods[this.current].name=this.name;
this.goods[this.current].price=this.price;
}
this.close();
},
close() {
// 關閉窗口
this.win_show = false;
//重置編輯操作
this.current=-1
// 清空窗口中的數據
this.title = "";
this.number = "";
this.price = ""
},
del(k) {
this.goods.splice(k, 1)
},
edit(k){
this.current=k;
this.name=this.goods[k].name;
this.price=this.goods[k].price;
this.win_show=1;
}
}
})
</script>
</body>
</html>
3. Vue對象提供的屬性功能
3.1 過濾器
過濾器,就是vue允許開發者自定義的文本格式化函數,可以使用在兩個地方:輸出內容和操作數據中。
定義過濾器的方式有兩種。
3.1.1 使用Vue.filter()進行全局定義
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="js/filters.js"></script>
</head>
<body>
<div id="box">
<p>{{price|RMB}}</p>
</div>
<script>
/*
* // 過濾器,有兩種:
// 全局過濾器, 通過Vue.filter("過濾器名稱",匿名函數)
Vue.filter("RMB", function(v){
return "¥"+v;
});
*/
var vm = new Vue({
el:"#box",
data:{
price:30.5
}
})
</script>
</body>
</html>
3.1.2 在vue對象中通過filters屬性局部
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
<p>{{price|RMB}}</p>
</div>
<script>
var vm = new Vue({
el:"#box",
data:{
price:30.5
},
filters:{
RMB(v){
return "¥"+v;
}
}
})
</script>
</body>
</html>
3.4 計算和偵聽屬性
3.4.1 計算屬性
我們之前學習過字元串反轉,如果直接把反轉的程式碼寫在元素中,則會使得其他同事在開發時時不易發現數據被調整了,所以vue提供了一個計算屬性(computed),可以讓我們把調整data數據的程式碼存在在該屬性中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
<p>{{price}}</p>
<p>{{price2}}</p>
</div>
<script>
// 當我們需要針對data的數據盡心調整成另一個變數,留作後面其他地方進行運算使用時,可以使用計算屬性得出一個新的變數
var vm = new Vue({
el: "#box",
data: {
price: 30.5
},
// 計算屬性
computed: {
price2: function () {
return this.price.toFixed(2);
}
}
})
</script>
</body>
</html>
3.4.2 監聽屬性
偵聽屬性,可以幫助我們偵聽data某個數據的變化,從而做相應的自定義操作。
偵聽屬性是一個對象,它的鍵是要監聽的對象或者變數,值一般是函數,當偵聽的data數據發生變化時,會自定執行的對應函數,這個函數在被調用時,vue會傳入兩個形參,第一個是變化前的數據值,第二個是變化後的數據值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
數量:<input type="text" v-model="num">
單價:<input type="text" v-model="price">
總價:{{total}}
</div>
<script>
var vm = new Vue({
el: "#box",
data: {
num: 0,
price: 30.5,
total: 0
},
watch: {
num(newval, oldval) {
console.log("修改後num="+newval);
console.log("修改前num="+oldval);
this.total = this.price * this.num;
},
price() {
this.total = this.price * this.num;
}
}
})
</script>
</body>
</html>
3.5 vue對象的生命周期
每個Vue對象在創建時都要經過一系列的初始化過程。在這個過程中Vue.js會自動運行一些叫做生命周期的的鉤子函數,我們可以使用這些函數,在對象創建的不同階段加上我們需要的程式碼,實現特定的功能。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
{{num}}
<input type="text" v-model="num">
</div>
<script>
var vm = new Vue({
el: "#box",
data: {
num: 30,
},
beforeCreate() {
// 這裡的程式碼執行時,vm對象尚未創建,所以data中的數據是無法操作
// console.log(this.num); // undefined
},
created() {
// 這裡的程式碼執行時,vm對象已經創建完成,但是還沒有把數據和視圖模板進行綁定
// console.log(this.num); // data的數據已經可以操作了。
// console.log(this.$el); // 此時還沒有綁定視圖
// 這裡可以用於編寫從後端獲取數據的程式碼
},
beforeMount() {
// 這裡的程式碼執行時,已經綁定了視圖,但是沒有更新視圖中的數據
console.log(this.$el.innerHTML);
},
mounted() {
// 這裡的程式碼執行時,已經把data中的數據替換了模板視圖中對應的內容了
console.log(this.$el);
// 這裡可以用於編寫一些需要操作視圖額初始化程式碼
},
beforeUpdate() {
// 更新html模板的數據之前
console.log(this.num);
console.log(this.$el.innerHTML)
},
updated() {
// 更新html模板的數據之後
console.log(this.num);
console.log(this.$el.innerHTML)
}
})
</script>
</body>
</html>
總結:
在vue使用的過程中,如果要初始化操作,把初始化操作的程式碼放在 mounted 中執行。
mounted階段就是在vm對象已經把data數據實現到頁面以後。一般頁面初始化使用。例如,用戶訪問頁面載入成功以後,就要執行的ajax請求。
另一個就是created,這個階段就是在 vue對象創建以後,把ajax請求後端數據的程式碼放進 created
3.2 阻止事件冒泡和刷新頁面
什麼是事件冒泡
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body onclick="alert('body')">
<div onclick="alert('div')">
<button>按鈕</button>
</div>
<script>
// 事件,event,在js中表示用戶和瀏覽器之間進行的一次交互過程
// 事件在觸發時,就會有一個事件對象來記錄整個事件發生的過程和發生的位置
// 從事件發生位置由內及外,根據標籤之間父子嵌套關係,逐層往外傳播,讓父級元素觸發同類事件,這種事件的傳遞方式,就是 事件冒泡
// 事件冒泡有好,有壞。
// 好處就是可以利用這種機制,實現事件委託
// 壞處就是當前元素的父級元素有同類事件,會隨著冒泡直接全部執行
</script>
</body>
</html>
使用.stop和.prevent
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box" @click="show2">
<!-- @click.stop來阻止事件冒泡 -->
<button @click.stop="show">按鈕</button>
<!-- @click.prevent來阻止標籤刷新 -->
<a href="" @click.prevent="show3">a鏈接</a>
</div>
<script>
var vm = new Vue({
el: "#box",
data: {},
methods: {
show() {
alert("按鈕");
},
show2() {
// alert("父元素");
},
show3() {
console.log("一句話");
}
}
})
</script>
</body>
</html>
3.3 綜合案例-todolist
我的計劃列表
html程式碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>todolist</title>
<style type="text/css">
.list_con{
width:600px;
margin:50px auto 0;
}
.inputtxt{
width:550px;
height:30px;
border:1px solid #ccc;
padding:0px;
text-indent:10px;
}
.inputbtn{
width:40px;
height:32px;
padding:0px;
border:1px solid #ccc;
}
.list{
margin:0;
padding:0;
list-style:none;
margin-top:20px;
}
.list li{
height:40px;
line-height:40px;
border-bottom:1px solid #ccc;
}
.list li span{
float:left;
}
.list li a{
float:right;
text-decoration:none;
margin:0 10px;
}
</style>
</head>
<body>
<div class="list_con">
<h2>To do list</h2>
<input type="text" name="" id="txt1" class="inputtxt">
<input type="button" name="" value="增加" id="btn1" class="inputbtn">
<ul id="list" class="list">
<!-- javascript:; # 阻止a標籤跳轉 -->
<li>
<span>學習html</span>
<a href="javascript:;" class="up"> ↑ </a>
<a href="javascript:;" class="down"> ↓ </a>
<a href="javascript:;" class="del">刪除</a>
</li>
<li><span>學習css</span><a href="javascript:;" class="up"> ↑ </a><a href="javascript:;" class="down"> ↓ </a><a href="javascript:;" class="del">刪除</a></li>
<li><span>學習javascript</span><a href="javascript:;" class="up"> ↑ </a><a href="javascript:;" class="down"> ↓ </a><a href="javascript:;" class="del">刪除</a></li>
</ul>
</div>
</body>
</html>
特效實現效果:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>todolist</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style type="text/css">
.list_con {
width: 600px;
margin: 50px auto 0;
}
.inputtxt {
width: 550px;
height: 30px;
border: 1px solid #ccc;
padding: 0px;
text-indent: 10px;
}
.inputbtn {
width: 40px;
height: 32px;
padding: 0px;
border: 1px solid #ccc;
}
.list {
margin: 0;
padding: 0;
list-style: none;
margin-top: 20px;
}
.list li {
height: 40px;
line-height: 40px;
border-bottom: 1px solid #ccc;
}
.list li span {
float: left;
}
.list li a {
float: right;
text-decoration: none;
margin: 0 10px;
}
</style>
</head>
<body>
<div class="list_con" id="app">
<h2>To do list</h2>
<input type="text" v-model="text" id="txt1" class="inputtxt">
<input type="button" @click="add" value="增加" id="btn1" class="inputbtn">
<ul id="list" class="list">
<!-- javascript:; # 阻止a標籤跳轉 -->
<li v-for="item,key in todolist">
<span>{{item}}</span>
<a href="javascript:;" @click="up(key)" class="up"> ↑ </a>
<a href="javascript:;" @click="down(key)" class="down"> ↓ </a>
<a href="javascript:;" @click="del(key)" class="del">刪除</a>
</li>
</ul>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
text: "",
todolist: [
"學習html",
"學習css",
"學習javascript",
]
},
methods: {
add() {
this.todolist.push(this.text);
this.text = "";
},
del(key) {
// splice 萬能函數
// 刪除和替換
// 參數1: 開始下表
// 參數2: 元素長度,如果不填默認刪除到最後
// 參數3: 表示使用當前參數替換已經刪除內容的位置
this.todolist.splice(key, 1);
},
up(key) {
// 向上移動
// splice(刪除的開始位置,刪除的成員個數, 替換的新數據)
if (key === 0) {
return;
}
//就是刪掉然後插入
ret = this.todolist.splice(key, 1)[0];
this.todolist.splice(key - 1, 0, ret);
},
down(key) {
// 向下移動
ret = this.todolist.splice(key, 1)[0];
this.todolist.splice(key + 1, 0, ret);
}
}
});
</script>
</body>
</html>
4. 通過axios實現數據請求
vue.js默認沒有提供ajax功能的。
所以使用vue的時候,一般都會使用axios的插件來實現ajax與後端伺服器的數據交互。
注意,axios本質上就是javascript的ajax封裝,所以會被同源策略限制。
下載地址:
<script src="//unpkg.com/axios/dist/axios.min.js"></script>
axios提供發送請求的常用方法有兩個:axios.get() 和 axios.post() 。
增 post
刪 delete
改 put/patch
查 get
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>axios</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="//unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<button @click="get_data">點擊</button>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {},
methods: {
get_data() {
// 發送get請求
// axios.get('//baidu.com', {
// params: {
// //查詢字元串的鍵值對
// username: 'zbb'
// }
// }, {
// //請求頭資訊
// Compant: "oldboy"
// });
// 發送post請求
axios.post("//www.baidu.com", {
username: "xiaoming",
password: "123456",
}, {
// 請求頭資訊
}).then((response) => {
// 請求成功以後,axios執行的程式碼
// response.data 響應體數據
}).catch(function (error) {
// 請求發生異常錯誤時,axios執行的程式碼
// error 錯誤對象(本地)
// error.response 來自服務端的響應錯誤資訊
});
}
}
});
// 匿名函數
// var func = function(response){
// // 函數程式碼
// };
//
// // 箭頭函數
// var func = (response)=>{
// // 函數程式碼
// }
</script>
</body>
</html>
總結
// 發送get請求
// 參數1: 必填,字元串,請求的數據介面的url地址,例如請求地址://www.baidu.com?id=200
// 參數2:可選,json對象,要提供給數據介面的參數
// 參數3:可選,json對象,請求頭資訊
// 發送post請求,參數和使用和axios.get()一樣。
// 參數1: 必填,字元串,請求的數據介面的url地址
// 參數2:必填,json對象,要提供給數據介面的參數,如果沒有參數,則必須使用{}
// 參數3:可選,json對象,請求頭資訊
4.1 json
json是 JavaScript Object Notation 的首字母縮寫,單詞的意思是javascript對象表示法,這裡說的json指的是類似於javascript對象的一種數據格式。
json的作用:在不同的系統平台,或不同程式語言之間傳遞數據。
4.1.1 json數據的語法
json數據對象類似於JavaScript中的對象,但是它的鍵對應的值裡面是沒有函數方法的,值可以是普通變數,不支援undefined,值還可以是數組或者json對象。
// 原生的js的json對象
var obj = {
age:10,
sex: '女',
work:function(){
return "好好學習",
}
}
// json數據的對象格式,json數據格式,是沒有方法的,只有屬性:
{
"name":"tom",
"age":18
}
// json數據的數組格式:
["tom",18,"programmer"]
複雜的json格式數據可以包含對象和數組的寫法。
{
"name":"小明",
"age":200,
"is_delete": false,
"fav":["code","eat","swim","read"],
"son":{
"name":"小小明",
"age":100,
"lve":["code","eat"]
}
}
// 數組結構也可以作為json傳輸數據。
json數據可以保存在.json文件中,一般裡面就只有一個json對象。
總結:
1. json文件的後綴是.json
2. json文件一般保存一個單一的json數據
3. json數據的屬性不能是方法或者undefined,屬性值只能:數值[整數,小數,布爾值]、字元串、json和數組
4. json數據只使用雙引號、每一個屬性成員之間使用逗號隔開,並且最後一個成員沒有逗號。
{
"name":"小明",
"age":200,
"fav":["code","eat","swim","read"],
"son":{
"name":"小小明",
"age":100
}
}
工具:postman可以用於測試開發的數據介面。
4.1.2 js中提供的json數據轉換方法
javascript提供了一個JSON對象來操作json數據的數據轉換.
方法 | 參數 | 返回值 | 描述 |
---|---|---|---|
stringify | json對象 | 字元串 | json對象轉成字元串 |
parse | 字元串 | json對象 | 字元串格式的json數據轉成json對象 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>axios</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="//unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<script>
var data = {
"name":"xiaopmiong",
"age":13,
"sex":true
};
// 把json對象轉換成json字元串
json_str = JSON.stringify(data);
console.log()
// 把json字元串裝換成json對象
data_str = '{"name":"xiaopmiong","age":13,"sex":true}';
json_obj = JSON.parse(data_str);
console.log(json_obj);
</script>
</body>
</html>
4.2 ajax
ajax,一般中文稱之為:”阿賈克斯”,是英文 「Async Javascript And Xml」的簡寫,譯作:非同步js和xml數據傳輸數據。
ajax的作用: ajax可以讓js代替瀏覽器向後端程式發送http請求,與後端通訊,在用戶不知道的情況下操作數據和資訊,從而實現頁面局部刷新數據/無刷新更新數據。
所以開發中ajax是很常用的技術,主要用於操作後端提供的數據介面
,從而實現網站的前後端分離
。
ajax技術的原理是實例化js的XMLHttpRequest對象,使用此對象提供的內置方法就可以與後端進行數據通訊。
4.2.1 數據介面
數據介面,也叫api介面,表示後端提供
操作數據/功能的url地址給客戶端使用。
客戶端通過發起請求向服務端提供的url地址申請操作數據【操作一般:增刪查改】
同時在工作中,大部分數據介面都不是手寫,而是通過函數庫/框架來生成。
4.2.3 ajax的使用
ajax的使用必須與服務端程式配合使用,但是目前我們先學習ajax的使用,所以暫時先不涉及到服務端python程式碼的編寫。因此,我們可以使用別人寫好的數據介面進行調用。
jQuery將ajax封裝成了一個函數$.ajax(),我們可以直接用這個函數來執行ajax請求。
編寫程式碼獲取介面提供的數據:
vue版本:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>axios</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="//unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<button @click="get_data">點擊</button>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {},
methods: {
get_data() {
axios.get("//wthrcdn.etouch.cn/weather_mini?city=北京", {
}).then(response => {
// 成功
console.log(response.data);
}).catch(error => {
// 報錯
console.log(error.response);
});
}
}
})
</script>
</body>
</html>
4.2.4 同源策略
同源策略,是瀏覽器為了保護用戶資訊安全的一種安全機制。所謂的同源就是指代通訊的兩個地址(例如服務端介面地址與瀏覽器客戶端頁面地址)之間比較,是否協議、域名(IP)和埠相同。不同源的客戶端腳本[javascript]在沒有明確授權的情況下,沒有許可權讀寫對方資訊。
ajax本質上還是javascript,是運行在瀏覽器中的腳本語言,所以會被受到瀏覽器的同源策略所限制。
前端地址://www.oldboy.cn/index.html |
是否同源 | 原因 |
---|---|---|
//www.oldboy.cn/user/login.html |
是 | 協議、域名、埠相同 |
//www.oldboy.cn/about.html |
是 | 協議、域名、埠相同 |
//www.oldboy.cn/user/login.html |
否 | 協議不同 ( https和http ) |
http:/www.oldboy.cn:5000/user/login.html |
否 | 埠 不同( 5000和80) |
//bbs.oldboy.cn/user/login.html |
否 | 域名不同 ( bbs和www ) |
同源策略針對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("//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 '//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 '//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
ajax跨域(跨源)方案:後端授權[CORS],jsonp,服務端代理
CORS是一個W3C標準,全稱是"跨域資源共享",它允許瀏覽器向跨源的後端伺服器發出ajax請求,從而克服了AJAX只能同源使用的限制。
實現CORS主要依靠<mark>後端伺服器中響應數據中設置響應頭資訊Access-Control-Allow-Origin返回</mark>的。
django的視圖
def post(request):
response = new Response()
response .headers["Access-Control-Allow-Origin"] = "//localhost:63342"
return response;
// 在響應行資訊裡面設置以下內容:
Access-Control-Allow-Origin: ajax所在的域名地址
Access-Control-Allow-Origin: www.oldboy.cn # 表示只允許www.oldboy.cn域名的客戶端的ajax跨域訪問
// * 表示任意源,表示允許任意源下的客戶端的ajax都可以訪問當前服務端資訊
Access-Control-Allow-Origin: *
總結:
0. 同源策略:瀏覽器的一種保護用戶數據的一種安全機制。
瀏覽器會限制ajax不能跨源訪問其他源的數據地址。
同源:判斷兩個通訊的地址之間,是否協議,域名[IP],埠一致。
ajax: //127.0.0.1/index.html
api數據介面: //localhost/index
這兩個是同源么?不是同源的。是否同源的判斷依據不會根據電腦來判斷,而是通過協議、域名、埠的字元串是否來判斷。
1. ajax默認情況下會受到同源策略的影響,一旦受到影響會報錯誤如下:
No 'Access-Control-Allow-Origin' header is present on the requested resource
2. 解決ajax只能同源訪問數據介面的方式:
1. CORS,跨域資源共享,在服務端的響應行中設置:
Access-Control-Allow-Origin: 允許訪問的域名地址
2. jsonp
3. 是否服務端代理
思路:通過python來請求對應的伺服器介面,獲取到數據以後,
jsonp方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jsonp</title>
<script src="//code.jquery.com/jquery-3.4.1.min.js"></script>
</head>
<body>
<button>點擊</button>
<script>
// function get_data(){
// // 發送請求
// // 1. 創建一個支援跨域標籤的標籤[script]
// var script = document.createElement("script");
// // 2. 給標籤加上src屬性,指向請求的地址
// script.src="//tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.search.catalogSug&query=我的中國心"
// console.log(script);
// // 3. 把設置好的script標籤放到head標籤裡面
// document.head.appendChild(script);
// // 4. 調用伺服器返回的數據,提前聲明一個函數,返回的數據作為參數
//
// }
// // callback(`{"song":[{"bitrate_fee":"{\\"0\\":\\"0|0\\",\\"1\\":\\"0|0\\"}","weight":"13099","songname":"我的中國心","resource_type":"0","songid":"604603771","has_mv":"0","yyr_artist":"0","resource_type_ext":"0","artistname":"CBS","info":"","resource_provider":"1","control":"0000000000","encrypted_songid":"78082409857A085D08CADC"},{"bitrate_fee":"{\\"0\\":\\"129|-1\\",\\"1\\":\\"-1|-1\\"}","weight":"4199","songname":"月亮代表我的中國心","resource_type":"0","songid":"544880401","has_mv":"0","yyr_artist":"0","resource_type_ext":"2","artistname":"大慶小芳","info":"","resource_provider":"1","control":"0000000000","encrypted_songid":"3408207A37080859645F87"}],"order":"song,album","error_code":22000,"album":[{"albumname":"我的中國心","weight":"130","artistname":"CBS","resource_type_ext":"0","artistpic":"http:\\/\\/qukufile2.qianqian.com\\/data2\\/pic\\/3b22a5976d07dbbe38b60f92ab2b6afd\\/660129785\\/660129785.jpg@s_2,w_40,h_40","albumid":"604603768"},{"albumname":"我的中國心","weight":"0","artistname":"陳東東","resource_type_ext":"0","artistpic":"http:\\/\\/qukufile2.qianqian.com\\/data2\\/pic\\/default_album.jpg@s_2,w_40,h_40","albumid":"611655247"}]}`)
// function callback(data){
// console.log(data);
// }
$.ajax({
url:"//tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.search.catalogSug&query=我的中國心",
type:"get",
dataType:"jsonp"
}).then(response=>{
console.log(response);
});
</script>
</body>
</html>
5. 組件化開發
5.1 組件[component]
組件(Component)是自定義封裝的功能。在前端開發過程中,經常出現多個網頁的功能是重複的,而且很多不同的頁面之間,也存在同樣的功能。
而在網頁中實現一個功能,需要使用html定義功能的內容結構,使用css聲明功能的外觀樣式,還要使用js來定義功能的特效,因此就產生了把一個功能相關的[HTML、css和javascript]程式碼封裝在一起組成一個整體的程式碼塊封裝模式,我們稱之為「組件」。
所以,組件就是一個html網頁中的功能,一般就是一個標籤,標籤中有自己的html內容結構,css樣式和js特效。
這樣,前端人員就可以在組件化開發時,只需要書寫一次程式碼,隨處引入即可使用。
vue的組件有兩種:默認組件[全局組件] 和 單文件組件
5.1.1 默認組件(很少用)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>zbb</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="//unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="page">
<!-- 組件名aa 寫好之後直接運行組件名即可-->
<aa></aa>
<aa></aa>
</div>
<script>
Vue.component("aa", {
template: "<p>公共組件<span @click='show'>{{message}}</span></p>",
// data在組件中變成了一個函數,函數的返回值必須是一個json對象
data: function () {
return {
message: "這是一本書"
}
},
methods: {
show() {
alert(this.message)
}
}
})
var vm = new Vue({
el: '#page',
data: {},
})
</script>
</body>
</html>
6. Vue自動化工具(Vue-cli)
前面學習了普通組件以後,接下來我們繼續學習單文件組件則需要提前先安裝準備一些組件開發工具。否則無法使用和學習單文件組件。
一般情況下,單文件組件,我們運行在 自動化工具vue-CLI中,可以幫我們編譯單文件組件。所以我們需要在系統中先搭建vue-CLI工具,
Vue CLI 需要 Node.js 8.9 或更高版本 (推薦 8.11.0+)。你可以使用 nvm 或 nvm-windows在同一台電腦中管理多個 Node 版本。
nvm工具的下載和安裝: //www.jianshu.com/p/d0e0935b150a
//www.jianshu.com/p/622ad36ee020
安裝記錄:
打開://github.com/coreybutler/nvm-windows/releases 下載然後安裝
常用的nvm命令
nvm list # 列出目前在nvm裡面安裝的所有node版本
nvm install node版本號 # 安裝指定版本的node.js
nvm uninstall node版本號 # 卸載指定版本的node.js
nvm use node版本號 # 切換當前使用的node.js版本
如果使用nvm工具,則直接可以不用自己手動下載,如果使用nvm下載安裝 node的npm比較慢的時候,可以修改nvm的配置文件(在安裝根目錄下)
#settings.txt
root: C:\tool\nvm [這裡的目錄地址是安裝nvm時自己設置的地址,要根據實際修改]
path: C:\tool\nodejs
arch: 64
proxy: none
node_mirror: //npm.taobao.org/mirrors/node/
npm_mirror: //npm.taobao.org/mirrors/npm/
6.1 安裝node.js
Node.js是一個新的後端(後台)語言,它的語法和JavaScript類似,所以可以說它是屬於前端的後端語言,後端語言和前端語言的區別:
- 運行環境:後端語言一般運行在伺服器端,前端語言運行在客戶端的瀏覽器上
- 功能:後端語言可以操作文件,可以讀寫資料庫,前端語言不能操作文件,不能讀寫資料庫。
我們一般安裝LTS(長線支援版本 Long-Time Support):
下載地址://nodejs.org/en/download/【上面已經安裝了nvm,那麼這裡不用手動安裝了】
node.js的版本有兩大分支:
官方發布的node.js版本:0.xx.xx 這種版本號就是官方發布的版本
社區發布的node.js版本:xx.xx.x 就是社區開發的版本
Node.js如果安裝成功,可以查看Node.js的版本,在終端輸入如下命令:
node -v
6.2 npm
在安裝node.js完成後,在node.js中會同時幫我們安裝一個npm包管理器npm。我們可以藉助npm命令來安裝node.js的包。這個工具相當於python的pip管理器。
npm install -g 包名 # 安裝模組 -g表示全局安裝,如果沒有-g,則表示在當前項目安裝
npm list # 查看當前目錄下已安裝的node包
npm view 包名 engines # 查看包所依賴的Node的版本
npm outdated # 檢查包是否已經過時,命令會列出所有已過時的包
npm update 包名 # 更新node包
npm uninstall 包名 # 卸載node包
npm 命令 -h # 查看指定命令的幫助文檔
6.3 安裝Vue-cli
npm install -g vue-cli
如果安裝速度過慢,一直超時,可以考慮切換npm鏡像源://npm.taobao.org/
6.4 使用Vue-CLI初始化創建前端項目
6.4.1 生成項目目錄
使用vue自動化工具可以快速搭建單頁應用項目目錄。
該工具為現代化的前端開發工作流提供了開箱即用的構建配置。只需幾分鐘即可創建並啟動一個帶熱重載、保存時靜態檢查以及可用於生產環境的構建配置的項目:
#生成一個基於 webpack 模板的新項目
vue init webpack 項目目錄名
例如:
vue init webpack myproject
// 啟動開發伺服器 ctrl+c 停止服務
cd myproject
npm run dev # 運行這個命令就可以啟動node提供的測試http伺服器
運行了上面程式碼以後,終端下會出現以下效果提示:
那麼訪問://localhost:8080/
6.4.2 項目目錄結構
src 主開發目錄,要開發的單文件組件全部在這個目錄下的components目錄下
static 靜態資源目錄,所有的css,js文件放在這個文件夾
dist項目打包發布文件夾,最後要上線單文件項目文件都在這個文件夾中[後面打包項目,讓項目中的vue組件經過編譯變成js 程式碼以後,dist就出現了]
node_modules目錄是node的包目錄,
config是配置目錄,
build是項目打包時依賴的目錄
src/router 路由,後面需要我們在使用Router路由的時候,自己聲明.
6.4.3 項目執行流程圖
整個項目是一個主文件index.html,index.html中會引入src文件夾中的main.js,
main.js中會導入頂級單文件組件App.vue,
App.vue中會通過組件嵌套或者路由來引用components文件夾中的其他單文件組件。
7. 單文件組件的使用
組件有兩種:普通組件、單文件組件
普通組件的缺點:
- html程式碼是作為js的字元串進行編寫,所以組裝和開發的時候不易理解,而且沒有高亮效果。
- 普通組件用在小項目中非常合適,但是複雜的大項目中,如果把更多的組件放在html文件中,那麼維護成本就會變得非常昂貴。
- 普通組件只是整合了js和html,但是css程式碼被剝離出去了。使用的時候的時候不好處理。
將一個組件相關的html結構,css樣式,以及交互的JavaScript程式碼從html文件中剝離出來,合成一個文件,這種文件就是單文件組件,相當於一個組件具有了結構、表現和行為的完整功能,方便組件之間隨意組合以及組件的重用,這種文件的擴展名為「.vue」,比如:”Home.vue”。
在組件中編輯三個標籤,編寫視圖、vm對象和css樣式程式碼。
7.1 完成案例-點擊加減數字
創建Home.vue
<template>
<div>
<button @click="add">+</button>
<input type="text" v-model="num">
<button @click="sub">-</button>
</div>
</template>
<script>
export default {
name: "Home",//組件名,提供給路由,進行頁面渲染
data() {
return {
num: 0,
}
},
methods: {
add() {
this.num = parseInt(this.num) + 1;
},
sub() {
if (this.num <= 1) {
return 0;
} else {
this.num -= 1;
}
}
}
}
</script>
<style scoped>
/*空間*/
input[type=text] {
width: 400px;
}
</style>
在App.vue組件中調用上面的組件
<template>
<div id="app">
<Home></Home>
</div>
</template>
<script>
import Home from "./components/Home";
export default {
name: 'App',
components: {
Home
}
}
</script>
<style>
</style>
在開發vue項目之前,需要手動把 App.vue的HelloWorld組件程式碼以及默認的css樣式,清除。
7.2 組件的嵌套
有時候開發vue項目時,頁面也可以算是一個大組件,同時頁面也可以分成多個子組件.
因為,產生了父組件調用子組件的情況.
例如,我們可以聲明一個組件,作為父組件
在components/創建一個子組件,例如,是Menu.vue
<template>
<div class="menu">
<ul>
<li v-for="i in list">{{i}}</li>
</ul>
</div>
</template>
<script>
export default {
name: "Menu",
data() {
return {
list: [
"首頁",
"列表",
"詳情"
],
}
}
}
</script>
<style scoped>
ul{
list-style: none;
margin: 0;
padding: 0;
}
</style>
然後,在父組件中調用上面聲明的子組件。
Home.vue
<template>
<div>
<Menu></Menu>
<button @click="add">+</button>
<input type="text" v-model="num">
<button @click="sub">-</button>
</div>
</template>
<script>
import Menu from "./Menu";
export default {
name: "Home",
components: {Menu},
//組件名,提供給路由,進行頁面渲染
data() {
return {
num: 0,
}
},
methods: {
add() {
this.num = parseInt(this.num) + 1;
},
sub() {
if (this.num <= 1) {
return 0;
} else {
this.num -= 1;
}
}
},
comments: {
Menu
}
}
</script>
<style scoped>
/*空間*/
input[type=text] {
width: 40px;
}
</style>
最後,父組件被App.vue調用.就可以看到頁面效果.
<template>
<div id="app">
<Home></Home>
</div>
</template>
<script>
import Home from "./components/Home";
export default {
name: 'App',
components: {
Home
}
}
</script>
<style>
</style>
7.3 傳遞數據
父組件的數據傳遞給子組件
例如,我們希望把父組件的數據傳遞給子組件.
可以通過props屬性來進行數據傳遞.
傳遞數據三個步驟:
-
在父組件中,調用子組件的組件標籤時,使用屬性值的方式往下傳遞數據
<template> <div> <Menu msg="傳遞的數據" :mynum="num"></Menu> <button @click="add">+</button> <input type="text" v-model="num"> <button @click="sub">-</button> </div> </template>
.上面表示在父組件調用Menu子組件的時候傳遞了2個數據:
.如果要傳遞變數,屬性名左邊必須加上冒號:,同時,屬性名是自定義的,會在子組件中使用。
.如果要傳遞普通字元串數據,則不需要加上冒號: -
在子組件中接受上面父組件傳遞的數據,需要在vm組件對象中,使用props屬性類接受。
<script> export default { name: "Menu", props:["msg","mynum"], data() { return { list: [ "首頁", "列表", "詳情" ], } } } </script> // 上面 props屬性中表示接受了兩個數據。
-
在子組件中的template中使用父組件傳遞過來的數據.
<template> <div class="menu"> <h1>{{msg}}</h1> <h1>{{mynum}}</h1> <ul> <li v-for="i in list">{{i}}</li> </ul> </div> </template>
使用父組件傳遞數據給子組件時, 注意一下幾點:
-
傳遞數據是變數,則需要在屬性左邊添加冒號.
傳遞數據是變數,這種數據稱之為”動態數據傳遞”
傳遞數據不是變數,這種數據稱之為”靜態數據傳遞”
-
父組件中修改了數據,在子組件中會被同步修改,但是,子組件中的數據修改了,是不是影響到父組件中的數據.
這種情況,在開發時,也被稱為”單向數據流”
子組件傳遞數據給父組件
-
在子組件中,通過
this.$emit()
來調用父組件中定義的事件.<template> <div class="menu"> <h1>{{msg}}</h1> <h1>{{mynum}}</h1> <input type="text" v-model="mynum"> <ul> <li v-for="i in list">{{i}}</li> </ul> </div> </template> <script> export default { name: "Menu", props: ["msg", "mynum"], data() { return { list: [ "首頁", "列表", "詳情" ], } }, //這裡傳值 watch: { mynum() { this.$emit("zz",this.mynum) } } } </script> <style scoped> ul { list-style: none; margin: 0; padding: 0; } </style>
-
父組件中聲明一個和子組件中
this.$emit("自定義事件名稱")
對應的事件屬性。<template> <div> <Menu msg="傳遞的數據" :mynum="num" @zz="zz"></Menu> <button @click="add">+</button> <input type="text" v-model="num"> <button @click="sub">-</button> </div> </template>
-
父組件中,聲明一個自定義方法,在事件被調用時,執行的。
<script> import Menu from "./Menu"; export default { name: "Home", components: {Menu}, //組件名,提供給路由,進行頁面渲染 data() { return { num: 0, } }, methods: { add() { this.num = parseInt(this.num) + 1; }, sub() { if (this.num <= 1) { return 0; } else { this.num -= 1; } }, zz(data) { console.log("父組件綁定的方法"); this.num=data } }, comments: { Menu } } </script>
<style scoped> /*空間*/ input[type=text] { width: 40px; } </style>
8. 在組件中使用axios獲取數據
默認情況下,我們的項目中並沒有對axios包的支援,所以我們需要下載安裝。
在項目根目錄中使用 npm安裝包
npm install axios
接著在main.js文件中,導入axios並把axios對象 掛載到vue屬性中作為一個子對象,這樣我們才能在組件中使用。
import Vue from 'vue' // 這裡表示從別的目錄下導入 單文件組件
import App from './App' // 從node_modules目錄中導入包
import axios from 'axios' // 把對象掛載vue中
Vue.config.productionTip = false
Vue.prototype.$axios = axios; // 把對象掛載vue中
new Vue({
el: '#app',
components: { App },
template: '<App/>'
})
8.1 在組建中使用axios獲取數據
<script>
export default{
methods:{
// 使用axios請求數據
get_w() {
this.$axios.get("//wthrcdn.etouch.cn/weather_mini?city=青島").then((response) => {
console.log(response.data);
})
}
},
</script>
效果:
使用的時候,因為本質上來說,我們還是原來的axios,所以也會收到同源策略的影響。
9.查詢未來5天的天氣
單文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.js">
<script src="//unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="city" placeholder="請填寫查詢的城市" id="">
<button @click="get_weather">查看天氣</button>
<table border="1" width="600">
<tr>
<td colspan="4">今天天氣情況: {{weather_info}}</td>
</tr>
<tr>
<th>日期</th>
<th>風力</th>
<th>溫度</th>
<th>狀況</th>
</tr>
<tr v-for="item in date_list">
<td>{{item.date}}</td>
<td>{{item.fengli|sub_cdata}}</td>
<td>{{item.low}}~{{item.high}}</td>
<td>{{item.type}}</td>
</tr>
</table>
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
city: "",
weather_info:"",
date_list:[],
},
filters:{
sub_cdata(data){
data = data.replace("<![CDATA[","");
data = data.replace("]]>","");
return data;
}
},
methods:{
get_weather(){
axios.get("//wthrcdn.etouch.cn/weather_mini",{
params:{
city:this.city,
}
}).then(response=>{
console.log(response.data);
this.weather_info = response.data.data.ganmao;
this.date_list = response.data.data.forecast;
}).catch(error=>{
console.log(error);
})
}
}
})
</script>
</body>
</html>
組件
App.vue
<template>
<div id="app">
<Tiqian></Tiqian>
</div>
</template>
<script>
import Tiqian from "./components/Tiqian";
export default {
name: 'App',
components: {
Tiqian
}
}
</script>
<style>
</style>
Tiqian
<template>
<div>
<input type="text" v-model="city" placeholder="請填寫查詢的城市" id="">
<button @click="get_weather">查看天氣</button>
<table border="1" width="600">
<tr>
<td colspan="4">今天天氣情況: {{weather_info}}</td>
</tr>
<tr>
<th>日期</th>
<th>風力</th>
<th>溫度</th>
<th>狀況</th>
</tr>
<tr v-for="item in date_list">
<td>{{item.date}}</td>
<td>{{item.fengli|sub_cdata}}</td>
<td>{{item.low}}~{{item.high}}</td>
<td>{{item.type}}</td>
</tr>
</table>
</div>
</template>
<script>
export default {
name: "tiqian",
data() {
return {
city: "",
weather_info: "",
date_list: [],
}
},
filters: {
sub_cdata(data) {
data = data.replace("<![CDATA[", "");
data = data.replace("]]>", "");
return data;
}
},
methods: {
get_weather() {
this.$axios.get("//wthrcdn.etouch.cn/weather_mini", {
params: {
city: this.city,
}
}).then(response => {
console.log(response.data);
this.weather_info = response.data.data.ganmao;
this.date_list = response.data.data.forecast;
}).catch(error => {
console.log(error);
})
}
}
}
</script>;
<style scoped>
</style>
1. 項目分析
首頁
導航、登錄註冊欄、輪播圖、底部導航
2. 項目搭建
2.1 創建項目目錄
cd 項目目錄
vue init webpack luffycity
除了code test,test2其他都選擇
接下來,我們根據終端上效果顯示的對應地址來訪問項目(如果有多個vue項目在運行,8080埠被佔據了,伺服器會自動改埠,所以根據自己實際在操作中看到的地址來訪問。)
2.2 初始化項目
清除默認的HelloWorld.vue組件和APP.vue中的默認模板程式碼和默認樣式
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
</style>
2.3.2 配置路由
2.3.2.1 初始化路由對象
在src目錄下的router目錄下修改index.js路由文件
index.js路由文件中,編寫初始化路由對象的程式碼 .
import Vue from 'vue'
import Router from 'vue-router'
// import HelloWorld from '@/components/HelloWorld'
// 這裡導入可以讓讓用戶訪問的組件
Vue.use(Router)
export default new Router({
// 設置路由模式為『history』,去掉默認的#
mode: "history",
routes: [
{
// path: '/',
// name: 'HelloWorld' 路由別名
// component: HelloWorld 組件類名
}
]
})
接下來,我們可以查看效果了,一張白紙~
3. 引入ElementUI
對於前端頁面布局,我們可以使用一些開源的UI框架來配合開發,Vue開發前端項目中,比較常用的就是ElementUI了。
ElementUI是餓了么團隊開發的一個UI組件框架,這個框架提前幫我們提供了很多已經寫好的通用模組,我們可以在Vue項目中引入來使用,這個框架的使用類似於我們前面學習的bootstrap框架,也就是說,我們完全可以把官方文檔中的組件程式碼拿來就用,有訂製性的內容,可以直接通過樣式進行覆蓋修改就可以了。
//element.eleme.cn/
3.1 快速安裝ElementUI
項目根目錄執行以下命令:
npm i element-ui -S
上面的命令等同於 npm install element-ui --save
3.2 配置ElementUI到項目中
在main.js中導入ElementUI,並調用。程式碼:
// 導入 elementUI的組件庫
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 調用插件
Vue.use(ElementUI);
或者在index中添加
在index.html入口文件中,載入樣式庫,程式碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- i mport CSS -->
<link rel="stylesheet" href="//unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
<div id="app">
<el-button @click="visible = true">Button</el-button>
<el-dialog :visible.sync="visible" title="Hello world">
<p>Try Element</p>
</el-dialog>
</div>
</body>
<!-- import Vue before Element -->
<script src="//unpkg.com/vue/dist/vue.js"></script>
<!-- import JavaScript -->
<script src="//unpkg.com/element-ui/lib/index.js"></script>
<script>
new Vue({
el: '#app',
data: function() {
return { visible: false }
}
})
</script>
</html>
成功引入了ElementUI以後,接下來我們就可以開始進入前端頁面開發,首先是首頁。
4. 首頁
首頁採用了上下頁面布局,首頁是導航欄、輪播圖。。。腳部等幾個小模組。所以我們可以把首頁作為一個組件進行開發,然後把首頁的這些小模組作為單獨的組件來進行開發。
4.1 創建首頁組件
在src/components目錄下創建文件 Home.vue
程式碼:
<template>
<div class="home">首頁</div>
</template>
<script>
export default {
name: "Home"
}
</script>
<style scoped>
</style>
4.1.1 創建首頁對應的路由
在router/index.js中引入Home組件,並設置Home組件作為首頁路由。
程式碼:
import Vue from 'vue'
import Router from 'vue-router'
import Home from "../components/Home";
// 這裡導入可以讓讓用戶訪問的組件
Vue.use(Router)
export default new Router({
// 設置路由模式為『history』,去掉默認的#
mode: "history",
routes: [
{
path: '/',
name: 'Home' ,
component: Home
}
]
})
4.2 開發頭部子組件
經過前面的觀察,可以發現導航不僅在首頁出現,其他頁面也有,所以對於這些不同頁面中公共的內容,可以創建一個單獨的組件目錄存放。
創建Header.vue目錄路徑,編寫程式碼:
<template>
<div>頭部</div>
</template>
<script>
export default {
name: "Header"
}
</script>
<style scoped>
</style>
4.2.1 在首頁引入導航組件
程式碼:home.vue
<template>
<div class="home">首頁
<Header></Header>
</div>
</template>
<script>
import Header from "./common/Header";
export default {
name: "Home",
data() {
return {};
},
components: {
Header
}
}
</script>
<style scoped>
</style>
接下來,我們就可以在組件中參考ElementUI文檔來進行樣式開發了。
初始化樣式
@charset "utf-8";
/* 聲明全局樣式和項目的初始化樣式 */
body,h1,h2,h3,h4,p,table,tr,td,ul,li,a,form,input,select,option,textarea{
margin:0;
padding: 0;
font-size: 15px;
}
a{
text-decoration: none;
color: #333;
}
ul,li{
list-style: none;
}
table{
border-collapse: collapse; /* 合併邊框 */
}
img{
max-width: 100%;
max-height: 100%;
}
/* 工具的全局樣式 */
.full-left{
float: left!important;
}
.full-right{
float: right!important;
}
[class*=" el-icon-"], [class^=el-icon-]{
font-size: 50px;
}
.el-carousel__arrow{
width: 80px;
height: 80px;
}
.el-checkbox__input.is-checked .el-checkbox__inner,
.el-checkbox__input.is-indeterminate .el-checkbox__inner{
background: #ffc210;
border-color: #ffc210;
border: none;
}
.el-checkbox__inner:hover{
border-color: #9b9b9b;
}
.el-checkbox__inner{
width: 16px;
height: 16px;
border: 1px solid #9b9b9b;
border-radius: 0;
}
.el-checkbox__inner::after{
height: 9px;
width: 5px;
}
在main.js中引入 初始化css
// 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 router from "./router/index"
Vue.config.productionTip = false;
// elementUI 導入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 調用插件
Vue.use(ElementUI);
// 載入初始化樣式
import "../static/css/reset.css";
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
Header的子組件程式碼:
<template>
<div class="header-box">
<div class="header">
<el-row>
<el-col :span="4" class="logo">
<a href=""><img src="/static/images/logo.svg" alt=""></a>
</el-col>
<el-col :span="15">
<el-menu class="nav" mode="horizontal">
<el-menu-item>免費課</el-menu-item>
<el-menu-item>實戰課</el-menu-item>
<el-menu-item>老男孩教育</el-menu-item>
</el-menu>
</el-col>
<el-col :span="5" class="header-right">
<a href="" class="cart">
<img src="/static/images/cart.svg" alt="">
購物車
</a>
<div class="loginbar">
<a href="" class="login">登錄</a>
|
<a href="" class="register">註冊</a>
</div>
</el-col>
</el-row>
</div>
</div>
</template>
<script>
export default {
name:"Header",
data(){
return {
}
}
}
</script>
<style scoped>
.header-box{
height: 80px;
}
.header{
box-shadow: 0 0.5px 0.5px 0 #c9c9c9;
position: fixed;
top: 0;
left: 0;
right: 0;
margin: auto;
z-index: 99;
background: #fff;
}
.logo{
height: 80px;
line-height: 80px;
}
.logo a{
display: block;
overflow: hidden;
height: 80px;
line-height: 80px;
text-align: center;
}
.logo a img{
vertical-align: middle;
}
.nav{
height: 80px;
}
.el-menu--horizontal>.el-menu-item{
height: 80px;
line-height: 80px;
}
.header .nav li{
color: #4a4a4a;
}
.header .nav li:hover{
color: #000;
}
.header .header-right{
height: 80px;
line-height: 80px;
}
.header .header-right .cart{
float:left;
margin-right: 20px;
height: 28px;
width: 88px;
margin-top: 26px;
line-height: 28px;
}
.header .header-right .cart:hover{
background: #f0f0f0;
border-radius: 17px;
}
.header .header-right .cart img{
width: 15px;
margin-right: 4px;
margin-left: 6px;
}
.header .header-right .loginbar{
float: left;
}
.header .header-right .loginbar a:hover{
color: #000;
}
</style>
4.3 開發輪播圖子組件
4.3.1 創建Banner.vue組件文件
程式碼:
<template>
<div class="banner">
</div>
</template>
<script>
export default {
name:"Banner",
data(){
return {};
}
}
</script>
<style scoped>
</style>
4.3.1 在Home組件中引入Banner子組件
<template>
<div class="home">
<Header/>
<Banner/>
</div>
</template>
<script>
import Header from "./common/Header"
import Banner from "./common/Banner"
export default{
name:"Home",
data(){
return {};
},
components:{
Header,
Banner,
}
}
</script>
<style scoped>
</style>
接下來,在ElementUI中有對應的輪播圖[跑馬燈]效果,可以直接提取過來使用。
注意,圖片保存到static目錄下。保存在assets目錄下的圖片等同於保存在static/images目錄下。
對於圖片的使用,如果是vue程式碼中直接要使用的圖片,可以保存accets目錄下,如果是第三方插件要使用到的圖片,需要保存在static目錄下。其實本質上來說,所有的圖片都是保存在static目錄下的,而assets目錄下的內容,最終被vue解析成地址的時候,也是在static目錄的.
Banner.vue組件,程式碼:
<template>
<div class="banner">
<el-carousel height="506px">
<el-carousel-item v-for="banner in banner_list" :key="banner">
<a :href="banner.link"><img width="100%" :src="banner.img" alt=""></a>
</el-carousel-item>
</el-carousel>
</div>
</template>
<script>
export default {
name:"Banner",
data(){
return {
banner_list:[
{link:"//www.baidu.com",img:"/static/images/banner1.png"},
{link:"//www.baidu.com",img:"/static/images/banner2.png"},
]
};
}
}
</script>
<style scoped>
</style>
4.5 頁面腳部
4.5.1 創建腳部組件文件
程式碼:
<template>
<el-container>
</el-container>
</template>
<script>
export default {
name:"Footer",
data(){
return {}
}
}
</script>
<style scoped>
</style>
4.5.2 在Home組件中引入Footer組件
Home組件程式碼:
<template>
<div class="home">
<Header/>
<Banner/>
<Footer/>
</div>
</template>
<script>
import Header from "./common/Header"
import Banner from "./common/Banner"
import Footer from "./common/Footer"
export default{
name:"Home",
data(){
return {};
},
components:{
Header,
Banner,
Footer,
}
}
</script>
<style scoped>
</style>
4.5.3 編寫腳部樣式
<template>
<div class="footer">
<el-container>
<el-row>
<el-col :span="4">
<router-link to="">關於我們</router-link>
</el-col>
<el-col :span="4">
<router-link to="">聯繫我們</router-link>
</el-col>
<el-col :span="4">
<router-link to="">商務合作</router-link>
</el-col>
<el-col :span="4">
<router-link to="">幫助中心</router-link>
</el-col>
<el-col :span="4">
<router-link to="">意見回饋</router-link>
</el-col>
<el-col :span="4">
<router-link to="">新手指南</router-link>
</el-col>
<el-col :span="24"><p class="copyright">Copyright © sadasdsy.com版權所有 | 京ICP備17072161號-1</p></el-col>
</el-row>
</el-container>
</div>
</template>
<script>
export default {
name: "Footer",
data() {
return {}
}
}
</script>
<style scoped>
.footer {
width: 100%;
height: 128px;
background: #25292e;
}
.footer .el-container {
width: 1200px;
margin: auto;
}
.footer .el-row {
align-items: center;
padding: 0 200px;
padding-bottom: 15px;
width: 100%;
margin-top: 38px;
}
.footer .el-row a {
color: #fff;
font-size: 14px;
}
.footer .el-row .copyright {
text-align: center;
color: #fff;
font-size: 14px;
}
</style>