Vue基礎入門

一、入門概述

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}} &nbsp;<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}}&nbsp;<button v-on:click="num+=1">add 1</button>&nbsp;<button v-on:click="method1(str)">點擊領紅包</button>&nbsp;<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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章