文章目錄
一、入門概述
Vue是一套用於構建用戶界面的漸進式JavaScript框架
特點:
輕量級:體積小
漸進式:不需要學完全部功能,用到什麼學什麼
響應式:數據更新之後,視圖不需要刷新,會自動更新
學習成本低:基於HTML和js,官方文檔都是中文
官方教程文檔:https://cn.vuejs.org/v2/guide/
安裝引入
Vue有兩年環境版本
開發版本:
包含完整的警告和調試模式
本地下載:https://cn.vuejs.org/js/vue.js
生產版本:
刪除了警告,33.30KB min+gzip
本地下載:https://cn.vuejs.org/js/vue.min.js
CDN引入:
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
二、基礎語法
1、聲明式渲染
示例:
<div id="app">{{message}}</div>
<script type="text/javascript">
var vm =new Vue({
el:"#app",
data:{
message:"hello Vue!"
}
})
</script>
頁面顯示結果:
hello Vue!
el叫做掛載點,對應的值是html元素的id。一個Vue應用會將其掛載到一個DOM元素上,即這個id對應的元素。掛載點支持css選擇器,推薦使用id選擇器。掛載點的DOM只支持雙標籤(和標籤除外),不支持單標籤。
data是渲染的時候動態的數據,當這些數據改變時,視圖會進行重渲染(不需要手動刷新),也就是響應式。
在Vue中使用{{屬性名}}
(插值)來獲取data中的值,如上面代碼中的{{message}}
對應的就是data中的message
2、條件渲染
指令:v-if
控制一個元素是否顯示,使用指令。在Vue中,元素中V-前綴的特殊屬性叫做指令。指令的職責是,當表達式的值改變時,將其產生的連帶影響。
<div id="app">
<p v-if="seen">直接顯示的內容</p>
<p v-else >默認隱藏</p>
</div>
var vm =new Vue({
el:"#app",
data:{
seen:true
}
})
瀏覽器顯示:
直接顯示的內容
指令:v-show
也是控制一個元素是否顯示,不過改變的是樣式(適合頻繁切換的元素),而v-if
改變的是DOM樹。
<div id="app">
<p v-show="seen">直接顯示的內容</p>
</div>
<script type="text/javascript">
var vm =new Vue({
el:"#app",
data:{
seen:false
}
})
</script>
瀏覽器顯示:
當seen爲false改變了css樣式
<p style="display: none;">直接顯示的內容</p>
3、列表渲染
指令:v-for
顯示的數據是一個數組
<div id="app">
<ul>
<li v-for="todo in todos">{{todo.text}}</li>
</ul>
</div>
<script type="text/javascript">
var vm =new Vue({
el:"#app",
data:{
todos:[{text:"愛學習,愛java"},{text: "java是世界上最好的語言"},{text: "day day up"}]
}
})
</script>
頁面效果:
愛學習,愛java
java是世界上最好的語言
day day up
在控制檯裏,輸入vm.todos.push({ text: '新的內容' })
,列表最後會添加新內容。
複雜一點的數據
<div id="app">
<ul>
<li v-for="goods in goodsList">商品名:{{goods.name}}<br>商品價格:{{goods.price}}</li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
goodsList: [{"id": 1, "name": "蘋果", "price": 10},
{"id": 2, "name": "香蕉", "price": 12},
{"id": 3, "name": "梨", "price": 8}]
}
})
</script>
瀏覽器顯示:
商品名:蘋果
商品價格:10
商品名:香蕉
商品價格:12
商品名:梨
商品價格:8
獲取索引可以使用v-for="(goods,index) in goodsList"
,其中index是當前元素的索引,{{index}}
可以獲取到當前元素的索引
4、原始html
如果響應式的內容是HTML,就不能使用雙大括號,需要使用v-html指令
<div id="app">
<ul>
<li>差值表達式支持輸出的內容:{{rawHtml}}</li>
<li>指令v-html輸出的內容:<span v-html="rawHtml"></span></li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
rawHtml:"<span><a href='#' style='color: red'>文字內容</a></span>"
}
})
</script>
瀏覽器顯示:
差值表達式支持輸出的內容:<span><a href=’#’ style=‘color: red’>文字內容</a></span>`
指令v-html輸出的內容:文字內容
5、表達式
對於所有的數據綁定,Vue 都提供了完全的JavaScript 表達式支持。每個綁定都只能包含單個表達式
<div id="app">
<ul>
<li>{{!seen?"false":"true"}}</li>
<li>{{num+1}}</li>
<li>{{text+",你來自哪裏"}}</li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
seen:true,
num:1,
text:"你是誰"
}
})
</script>
瀏覽器顯示:
true
2
你是誰,你來自哪裏
6、綁定屬性
指令:v-bind
縮寫是::屬性名
用於響應式地更新HTML屬性
<div id="app">
<ul>
<li v-bind:class="id"></li>
<li :class="id"></li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
id:"top"
}
})
</script>
審查元素看元素節點屬性:
<ul>
<li class="top"></li>
<li class="top"></li>
</ul>
7、綁定樣式
可以傳給v-bind:class
一個對象,以動態地切換class, 也可以傳遞數組,或者進行一些計算。
使用v-bind:style
綁定css樣式。
<style type="text/css">
.active{
color: red;
}
.large-cls{
font-weight: bolder;
}
</style>
<div id="app">
<ul>
<li v-bind:class="{active:isActive}">文本內容1</li>
<!--靜態和指令共存-->
<li :class="{active:isActive}" class="large-cls">文本內容2</li>
<!--綁定數組-->
<li :class="[activeClass,largeClass]">文本內容3</li>
<!--綁定對象-->
<li :class="classObj1">文本內容4</li>
<!--綁定計算的對象-->
<li :class="classObj2">文本內容5</li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
isActive:false,
activeClass:"active",
largeClass:"large-cls",
classObj1:{active:true}
},
computed:{
classObj2:function () {
return{
active:this.isActive,
'large-cls':!this.isActive//名字中有特殊符號,如“-”,用單引號
}
}
}
})
</script>
生成的靜態class屬性
<ul>
<li class="">文本內容1</li>
<li class="large-cls">文本內容2</li>
<li class="active large-cls">文本內容3</li>
<li class="active">文本內容4</li>
<li class="large-cls">文本內容5</li>
</ul>
8、綁定事件
指令:v-on:事件名
簡寫:@事件名
使用v-on綁定事件
<div id="app">
<ul>
<li >num={{num}} <button v-on:click="num+=1" >add 1</button></li>
<li ><button v-on:click="method1(str)">點擊領紅包</button></li>
<li ><button @click="method2">hello</button></li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
num:0,
str:"恭喜你獲得500元"
},
methods:{
method1:function (str) {
alert(str)
},
method2:function () {
console.log("helllo vue")
}
}
})
</script>
顯示效果:
9、表單數據
指令:v-model
在表單元素上創建雙向數據綁定。v-model會忽略表單元素默認值,而將Vue實例的數據作爲數據來源。
<div id="app">
<ul>
<li >用戶名:<input type="text" name="userName" v-model="nameVal"></li>
<li >密碼:<input type="password" name="password" v-model="passwordVal"></li>
<li >性別:<input type="radio" name="sex" value="1" v-model="sexVal">男<input type="radio" name="sex" value="2" v-model="sexVal">女</li>
<li >愛好:<input type="checkbox" name="hobby" value="1" v-model="hobbyVal">看書<input type="checkbox" name="hobby" value="2" v-model="hobbyVal">電影<input type="checkbox" name="hobby" value="3" v-model="hobbyVal">唱歌</li>
<li ><select name="city" v-model="sityVal">
<option value="1">深圳</option>
<option value="2">上海</option>
</select></li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
nameVal:"張三",
passwordVal:"a66666",
sexVal:1,
hobbyVal:[1,2],
sityVal:1
}
})
</script>
瀏覽器顯示:
10、過濾器
<div id="app">
<ul>
<li >{{message|filter1}}</li>
<li >{{message|filter2('arg1', 'arg2')}}</li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
message:"Hello Vue"
},
filters:{
filter1:function (value) {
return value.toUpperCase();
},
filter2:function (value,arg1,arg2) {
return value+arg1+arg2;
}
}
})
</script>
瀏覽器顯示:
HELLO VUE
Hello Vuearg1arg2
11、計算屬性
對於複雜邏輯,需要使用計算屬性。computed將不經常變化的計算結果進行緩存,以節約系統開銷。
<div id="app">
<ul>
<li >{{getTime1}}</li>
<li >{{getTime2()}}</li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
computed:{
getTime1:function () {
return new Date();
}
},
methods:{
getTime2:function () {
return new Date();
}
}
})
</script>
methods和computed區別是:
methods需要帶括號, computed不需要
computed計算的值會緩存起來,多次調用,其值不變:
12、聲明組件
組件可複用的Vue實例。可以把組件看成小型的,獨立的U模塊。
一個組件必須有一個根節點
全局組件,在當前Vue實例中都可用,局部註冊的組件只在父組件中可用。
父子組件data無法共享
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<comp2></comp2>
</div>
<script type="text/javascript">
//聲明組件
Vue.component('button-counter', {
template:'<div>num={{num}} <button v-on:click="num+=1">add 1</button> <button v-on:click="method1(str)">點擊領紅包</button> <button @click="method2()">hello</button><innerChild></innerChild></div>',
methods: {
method1: function (str) {
alert(str)
},
method2: function () {
alert("hello vue")
}
},
data:function () {
return{
num:0,
str: "恭喜你獲得500元"
}
},
components:{
innerChild:{
template:'<span>局部組件</span>'
}
}
})
Vue.component('comp2',{
template:'<button-counter></button-counter>'
})
var vm = new Vue({
el: "#app"
})
</script>
13、axios動態數據
引入文件
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id="app">
<button @click="search">查詢</button>
<ul><li v-for="data in dataList">{{data.id}}-{{data.name}}-{{data.price}}</li></ul>
</div>
<script type="text/javascript">
var vm= new Vue({
el:"#app",
data:{
dataList:[]
},
methods:{
search:function () {
axios.get("./data.json").then(res=>{
console.log(res.data)
this.dataList=res.data;
});
}
}
})
</script>
data.json
[{"id": 1, "name": "蘋果", "price": 10},
{"id": 2, "name": "香蕉", "price": 12},
{"id": 3, "name": "梨", "price": 8}]
打開瀏覽器點擊查詢顯示數據
三、組件詳解
1、屬性(父傳子)
自定義屬性props:組件的props中聲明的屬性
原生屬性attrs:沒有聲明的屬性,默認自動掛載到組件根元素上。
特殊屬性class、style:掛載到組件根元素上,支持字符串、對象。數組等多種語法
屬性可以通過數組的形式列出:
props:['title','commentIds','author']
但在正式開發的時候,爲了系統的維護性,我們還是推薦使用如下形式,注意組件中的屬性名,在html標籤中並不是使用駝峯。如果使用的是數字類型或者其它動態值,需要使用v-bind:
<div id="app">
<!--數字和布爾綁定需要動態賦值,不然會報錯,:prop-c="abc"會報錯,字母動態賦值會被認爲是方法或變量-->
<button-counter :prop-a="1" :prop-b="1" prop-c="abc" :prop-d="20" prop-f="success"></button-counter>
</div>
<script type="text/javascript">
//聲明組件
Vue.component('button-counter', {
template: '<div>propA:{{propA}}<br/>propB:{{propB}}<br/>propC:{{propC}}<br/>propD:{{propD}}<br/>propE:{{propE}}<br/>propF:{{propF}}</div>',
//聲明屬性
props: {
//基礎的類型檢查('null'和、'undefined'會通過任何類型驗證)
propA: Number,
//多個可能的類型
propB: [String, Number],
//必填的字符串
propC: {
type: String,
required: true
},
//帶有默認值的數字類型
propD: {
type: Number,
default: 100
},
//帶有默認值的對象類型
propE: {
type: Object,
//對象或數組默認值必須從一個工廠函數獲取
default: function () {
return {
message:"hello Vue!"
}
}
},
propF:{
validator:function (value) {
//這個值必須匹配下列字符串的一個
return ['success','warning','danger'].indexOf(value)!==-1
}
}
}
})
var vm = new Vue({
el: "#app"
})
</script>
瀏覽器顯示:
propA:1
propB:1
propC:abc
propD:20
propE:{ "message": "hello Vue!" }
propF:success
2、事件
普通事件:@click
、@change
等事件, 通過this.$emit( 'myEvent' )
觸發(子傳父)。
修飾符事件:@input.trim
、@click.stop
等, 自定義組件需要自行開發。
<div id="app">
<my-component></my-component>
</div>
<script type="text/javascript">
Vue.component('my-component',{
template: '<div @click="HandlerDivClick"><button @click="HandlerButClick">向上傳遞</button><button @click.stop="HandlerButClick">阻止冒泡</button></div>',
methods:{
HandlerDivClick:function () {
console.log("aaa")
},
HandlerButClick:function () {
console.log("bbb")
}
}
})
var vm=new Vue({
el:"#app"
})
</script>
瀏覽器顯示:
父傳子靠屬性,子傳父靠事件
<div id="app">
<!--不帶括號默認傳event,默認寫法-->
<child @myevent="father"></child>
<!--帶括號$event固定寫法-->
<child @myevent="father($event)"></child>
</div>
<script type="text/javascript">
Vue.component('child', {
template: ` <div>
<button @click="callParent()">子傳父</button>
</div>`,
data:function () {
return {
childName:"aaa"
}
},
methods: {
callParent: function () {
console.log("child")
this.$emit('myevent',this.childName)//子組件觸發父組件的方法
}
}
})
var vm = new Vue({
el: "#app",
methods: {
father:function (e) {
console.log("I’m father:"+e)
}
}
})
</script>
控制檯輸出:
child
I’m father:aaa
3、插槽
在Vue中如果在自定義組件的標籤內部寫東西,默認是不顯示的。使用slot
實現插槽功能,可以顯示在組件中寫的內容。
<div id="app">
<div-counter>默認不顯示</div-counter>
</div>
<script type="text/javascript">
//聲明組件
Vue.component('div-counter', {
template: ` <div>
<ul>
<slot></slot>
<li>這是內容1</li>
<li>這是內容1</li>
</ul>
</div>`,
})
var vm = new Vue({
el: "#app"
})
</script>
瀏覽器顯示:
默認不顯示
這是內容1
這是內容1
具名插槽
把內容插入到指定的插槽中,當插槽名都有名字,而插入的內容沒有名字指向,則內容不會顯示
<div id="app">
<div-counter><div slot="a">插槽a的內容</div><div slot="b">插槽b的內容</div></div-counter>
</div>
<script type="text/javascript">
//聲明組件
Vue.component('div-counter', {
template: ` <div>
<ul>
<slot name="a"></slot>
<li>這是內容1</li>
<li>這是內容1</li>
<slot name="b"></slot>
</ul>
</div>`,
})
var vm = new Vue({
el: "#app"
})
</script>
瀏覽器顯示:
插槽a的內容
這是內容1
這是內容1
插槽b的內容
4、中央事件組件
兄弟組件之間相互調用,可以使用中央事件組件
<div id="app">
<c1></c1>
<c2></c2>
</div>
<script type="text/javascript">
var bus=new Vue();
Vue.component('c1', {
template: `<div><input ref="msg">
<button @click="HandleClick">這是組件1</button>
</div>`,
methods:{
HandleClick:function () {
console.log(this.$refs.msg.value)
bus.$emit('myListener',this.$refs.msg.value)//發佈攜帶的事件myListener
}
}
})
Vue.component('c2', {
template: `<div>
<button>這是組件2</button>
</div>`,
mounted:function () {
bus.$on('myListener',function (data) {//訂閱事件
console.log('組件2接收的內容:'+data)
})
}
})
var vm = new Vue({
el: "#app"
})
</script>
控制檯顯示內容
5、動態組件
動態組件使用<component>
標籤佔位,使用is
屬性指定具體替換爲哪個組件。每次切換都會重新渲染組件。使用<keep-alive>
<div id="app">
<!--組件只被初始化一次-->
<keep-alive>
<component :is="nav"></component>
</keep-alive>
<!--點擊改變nav值切換組件-->
<button @click="nav='home'">home</button>
<button @click="nav='list'">list</button>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
components:{
list:{
template:`<div>list<input></div>`,
mounted:function () {
console.log('mounted')//查看組件初始化次數
}
},
home:{
template: ` <div>home</div>
`
}
},
data:{
nav:"list"
}
})
</script>
瀏覽器顯示:
四、生命週期
每個Vue實例在被創建時都要經過一系列的初始化過程,叫做生命週期鉤子
<div id="app">
<button @click="message='content changed'" >{{ message }}</button>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
message : "Hello Vue!"
},
beforeCreate: function () {
console.group('beforeCreate 創建前狀態===============》');
console.log("%c%s", "color:red" , "el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //undefined
console.log("%c%s", "color:red","message: " + this.message)//undefined
},
created: function () {
console.group('created 創建完畢狀態===============》');
console.log("%c%s", "color:red","el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
beforeMount: function () {
console.group('beforeMount 掛載前狀態===============》');
console.log("%c%s", "color:red","el : " + (this.$el)); //已被初始化
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
mounted: function () {
console.group('mounted 掛載結束狀態===============》');
console.log("%c%s", "color:red","el : " + this.$el); //已被初始化
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
beforeUpdate: function () {
console.group('beforeUpdate 更新前狀態===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
updated: function () {
console.group('updated 更新完成狀態===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
beforeDestroy: function () {
console.group('beforeDestroy 銷燬前狀態===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
destroyed: function () {
console.group('destroyed 銷燬完成狀態===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message)
}
})
</script>
生命週期代碼來源:https://segmentfault.com/a/1190000008010666
掛載結束前的狀態
更新狀態
五、腳手架Vue CLI
1、安裝node.js
官網下載:https://nodejs.org/en/download/
安裝版直接雙擊安裝,解壓版解壓文件
解壓後創建兩個文件夾
配置環境變量,在系統變量下新建一個NODE_HOME變量,把新建的NODE_HOME添加到PATH中
cmd配置剛纔新建的兩個文件夾
執行命令
npm config set cache "E:\study\node-v12.18.2-win-x64\npm_cache"
npm config set prefix "E:\study\node-v12.18.2-win-x64\npm_global"
再添加環境變量
%NODE_PATH%\npm_global
安裝cnmp,加快下載速度
npm install -g cnpm --registry=https://registry.npm.taobao.org
安裝vue腳手架:
cnpm install -g @vue/cli
2、創建項目
創建一個項目路徑,在該項目路徑中執行vue create 名字,按上下箭頭切換,選擇手動配置Manually這個再回車進入下一步
空格選中需要安裝的模塊
後面幾步選擇,右側有對應值
之後開始下載…
工程下載完成
按照提示信息,進入到項目內,執行命令
npm run serve
提示訪問地址
根據提示訪問地址,出現如下頁面表示項目創建成功
idea中打開啓動方式
idea中的npm工具啓動
在工具中啓動,默認端口8080,修改端口在Arguments使用-- --port 80
3、單文件組件
在App.vue寫入如下內容:
單頁面分爲三部分:模板標籤、js和css
<template>
<div id="app">
<div>
<input ref="msg">
<button @click="add()">添加</button>
<ul>
<li v-for="data in dataList" :key="data">{{data}}</li>
</ul>
</div>
</div>
</template>
<script>
export default {
// ()相當於:funtion()
data () {
return {
dataList: []
}
},
methods: {
add () {
console.log(this.$refs.msg.value)
this.dataList.push(this.$refs.msg.value)
}
}
}
</script>
<style>
ul,li{
list-style: none;
background-color: #ccc;
}
</style>
4、項目打包
使用nmp run lint
可以將代碼格式化,符合ES6風格。
使用npm run build
可以將項目打包,打包成功後會有一個dist文件夾, 將這個文件夾中的內容給後端開發人員即可(emmm就是你自己咯)
5、axios反向代理
跨域:端口、協議或域名不一致
模塊化開發需要在當前的工程下安裝axios模塊npm install axios ,在頁面中引入axios模塊,跨域的時候,axios的請求路徑不寫域名,交給代理實現
<template>
<div>
<ul>
<button @click="search">查詢</button>
<li v-for="data in dataList">{{data.id}}-{{data.name}}</li>
</ul>
</div>
</template>
<script>
import Vue from 'vue'
import axios from 'axios'
export default {
data () {
return {
dataList: []
}
},
methods: {
search: function () {
axios.get('/tupes')
.then(res => {
this.dataList = res.data
})
}
}
}
</script>
axios跨域請求時會報錯,可以請求到數據,但無法使用
這時需要配置反向代理,在項目根目錄src下創建vue.config.js文件:
module.exports = {
devServer: {
proxy: {
'/types': {
target: 'http://localhost:8099',
changeOrigin: true
}
}
}
}
六、路由
1、一級路由
對於單頁面應用,使用路由切換組件,先創建兩個組件
<template>
<div>
<h1>用戶</h1>
</div>
</template>
<script>
export default {}
</script>
在router文件夾下的index.js中配置路由信息。這個路徑是可以自定義的,和main.js中的路徑相對應
import Vue from 'vue'
import VueRouter from 'vue-router'
import User from '../views/User'
import Order from '../views/Order'
Vue.use(VueRouter)
const routes = [
{
path: '/user', // 對應頁面中的#/user
component: User // 組件User
},
{
path: '/order',
component: Order
}
]
const router = new VueRouter({
routes
})
export default router
main.js中引入路由文件:此處創建項目會默認配置
在App.vue主頁面中,需要展示組件的地方加上<router-view></ router-view>
<ul>
<li><a href="#/user">用戶頁面</a></li>
<li><a href="#/order">訂單頁面</a></li>
</ul>
<!--類似插槽,渲染切換頁面的組件-->
<router-view></router-view>
訪問路徑: http://localhost:8080/#/order, 其中的/#/order就是路由的請求路徑了
2、聲明式導航
使用路由標籤,可以管理路由連接和高亮樣式
to:路徑
tag:渲染成什麼標籤
activeClass:高亮的樣式
<div>
<ul>
<router-link to="/user" tag="button" active-class="myActive">用戶管理</router-link>
<router-link to="/order" tag="button" active-class="myActive">訂單管理</router-link>
</ul>
<!--類似插槽,渲染切換頁面的組件-->
<router-view></router-view>
</div>
<style>
.myActive{
color: #444;
background-color: coral;
}
button:hover{
cursor:pointer
}
</style>
瀏覽器顯示:
3、重定向
路由中指定一個默認的地址,當訪問路徑沒有匹配到組件的時候,會重定向到指定頁面:
{
path: '*',
redirect: '/order'
}
4、二級路由
如果在子組件中更新部分內容們可以使用二級路由,如Order.vue中 :
<template>
<div>
<h1>訂單頁面</h1>
<ul>
<router-link to="paid" tag="button" active-class="myActive">已支付</router-link>
<router-link to="notpay" tag="button" active-class="myActive">未支付</router-link>
</ul>
<router-view></router-view>
</div>
</template>
<script>
export default {}
</script>
路由配置(在一級路由的節點上加children節點):
{
path: '/order',
component: Order,
children: [{
path: 'paid',
component: Paid
}, {
path: '/order/notpay',
component: NotPay
}, {
path: '', // 默認重定向
redirect: '/order/notpay'
}]
}
瀏覽器效果:
5、動態路由
如果路由中有動態的參數,可以進行如下配置:
發起請求的組件(Nopay.vue):
<template>
<div>
<h2>未支付訂單</h2>
<ul>
<li v-for="num in dataList" :key="num" @click="changePage(num)">文章{{num}}</li>
</ul>
</div>
</template>
<script>
export default {
data () {
return {
dataList: ['1', '2', '3']
}
},
methods: {
changePage: function (id) {
console.log(id)
this.$router.push(`/order/detail/${id}.html`) // 傳url動態參數
}
}
}
</script>
路由配置:
{
path: '/order/detail/:myid.html', // myid是動態參數
component: Detail
},
詳情頁面組件
<template>
<div>
<h3>訂單{{num}}的詳情內容</h3>
</div>
</template>
<script>
export default {
mounted () {
console.log(this.$route.params.myid) // 輸出動態id
},
data () {
return {
num: this.$route.params.myid
}
}
}
</script>
瀏覽器顯示:
6、命名路由
配置路由的時候設置一個name屬性
{
name: 'od',
path: '/order/detail/:myid.html', // myid是動態參數
component: Detail
}
跳轉的時候
this.$router.push({ name: 'od', params: { myid: id } })
7、history模式
在定義路由的地方加上mode: ’ history’可以去掉路徑中的#:
const router = new VueRouter({
mode: 'history',
routes
})
這種模式會真的向後端發送一個請求, 後端需要配置:如果URL 匹配不到任何資源,則返回同一個index.html
8、路由守衛
全局解析守衛,定義在路由js裏
使用路由守衛,相當於一個過濾器:
// 模擬用戶沒有登錄
const auth = {
isLogin () {
return false
}
}
// to去哪個頁面,form從哪個頁面來,下一個頁面
router.beforeEach((to, from, next) => {
console.log(to.path)
if (/\/order\/.*/.test(to.path)) { // 匹配正則路徑,所有以order開頭的頁面
console.log('攔截')
if (auth.isLogin()) {
next()
} else {
next('/login')
}
} else { // 不需要登錄的頁面直接放行
next()
}
})
組件內的守衛,定義在組件內
<script>
// 模擬用戶沒有登錄
const auth = {
isLogin () {
return false
}
}
export default {
beforeRouteEnter (to, from, next) {
// 在渲染該組件的對應路由被confirm前調用
// 不能獲取組件實例 `this`
// 因爲當守衛執行前,組件實例還沒被創建
if (auth.isLogin()) {
next()
} else {
next('/login')
}
}
}
</script>