天天看點

VUE基礎Vue基礎

VUE基礎

  • Vue基礎
    • 資料綁定
    • 過濾器
    • 指令
    • 計算屬性
      • 計算屬性的getter、setter方法
      • 計算屬性擴充
      • 計算屬性緩存
    • v-bind
      • 綁定class
        • 使用對象文法綁定class:
        • 使用數組文法綁定class
      • 綁定内聯樣式
        • 使用數組文法綁定多個樣式
    • 内置指令
      • v-cloak
      • v-pre
      • v-once
      • v-if、v-else-if、v-else
      • v-for
        • v-for疊代整數
        • 更新數組觸發資料改變的方法
      • v-on
    • v-model
    • 元件
      • 挂載元件
      • 通過props傳遞資料:
      • 子元件向父元件傳值
      • 使用v-model和$emit傳值
    • 中央事件總線
      • 父(\$parent)鍊傳遞資料
      • 子元件索引
      • slot插槽
      • 具名slot
      • 使用component标簽挂載模闆
      • $nextTick
    • 自定義指令
    • 虛拟dom
    • vue-router
      • 安裝vue-router
      • 配置vue-router
    • 配置跳轉
      • 方式一,router-link
      • 方式二,api跳轉
      • router鈎子函數
        • beforeEach
        • afterEach
    • vuex
      • 安裝vuex
      • 配置vuex
      • 使用vuex,建立資料
        • 擷取vuex中的資料
      • 使用mutations修改states的資料
      • commit接收對象
      • getters
      • 異步操作資料使用actions
      • modules狀态區分
    • 中央事件總線vue-bus

Vue基礎

資料綁定

通過{{}}可以與vue中data中的資料綁定。如果不想使用{{}}可以使用

v-pre

取消{{}}資料綁定。

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
</head>
<body>
    <id id="app">
        <span >{{ a }}</span>
        <span v-pre>{{a}}</span>
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let vue = new Vue({
           el: "#app",
           data: {
               a: '<a href="www.baidu.com" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >百度</a>'
           },
           created() {
               console.log(this);
               console.log(this.a);
               console.log(this.$el);
               // vue資料執行個體建立完成,資料生成
           },
           mounted() {
               console.log(this);
               console.log(this.$el);
               // 挂載el,與dom關聯
           }
           
       })
    </script>
</body>
</html>
           

使用v-html輸出html内容。

<id id="app">
	<span >{{ a }}</span>
    <span v-pre>{{a}}</span>
    <span v-html='a'></span>
</id>

<script src="./js/vue.min.js"></script>
<script>
   let vue = new Vue({
       el: "#app",
       data: {
           a: '<a href="www.baidu.com" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >百度</a>'
       }
   })
</script>
           

過濾器

filters屬性加上|操作符實作過濾:

<id id="app">
		<!-- name 即為要過濾的資料  | 表示要使用過濾 formartName表示使用的哪個過濾器 -->
       {{ name | formartName}}
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: "#app",
           data: {
               name: 'zs'
           },
           // 在filters中使用過濾器方法
           filters: {
               formartName(value) { // value就是需要過濾的資料
                    return "@_" + value + "[email protected]";
               }
           }
       })
    </script>
           

可以指定使用多個過濾器,也可以給過濾器傳遞參數:

<id id="app">
        可以使用多個過濾器,并且還能給過濾器傳遞參數
       {{ name | formartName | formartName1('*')}}
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: "#app",
           data: {
               name: 'zs'
           },
           filters: {
               formartName(value) { // value就是需要過濾的資料
                    return "@_" + value + "[email protected]";
               },
               formartName1(value, param) {
                    return value + '->' + param;
               }
           }
       })
    </script>
           

指令

使用

v-show

,如果為false時,隻是設定了對應的元素的

display

屬性為none:

<id id="app">
       <p v-show="isShow">v-show的使用</p>
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               isShow: true
           }
       })
    </script>
           

v-bind

作資料綁定,可以為元素動态綁定一個屬性。

<id id="app">
		為p标簽綁定了一個name屬性,name屬性的值就是data資料中text對應的值
       <p v-bind:name='text' v-show="isShow">v-show的使用</p>
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               isShow: true,
               text: '_text'
           }
       })
    </script>
           

v-on

指令,可以用來監聽事件,其後接一個methods中定義的方法或者一個表達式。

<id id="app">
       <p v-bind:name='text' v-show="isShow" v-on:click="isShow = false">v-show的使用</p>
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               isShow: true,
               text: '_text'
           }
       })
    </script>
           

計算屬性

computed

時計算屬性,計算屬性也是一個屬性,類似于data中的資料,計算屬性是一個函數,計算屬性的值是函數的傳回值。

<id id="app">
       {{ fullName }}
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               firstName: 'Jhon',
               lastName: 'Cena'
           },
           computed: {
               fullName() {
                   return this.firstName + " " + this.lastName;
               }
           }
       })
    </script>
           

計算屬性的getter、setter方法

計算屬性有getter和setter方法,分别用于讀取和設定計算屬性的值。

<id id="app">
       {{ fullName }}
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               firstName: 'Jhon',
               lastName: 'Cena'
           },
           computed: {
               fullName: {
                   get() {
                       return this.firstName + " " + this.lastName;
                   },
                   set(value) {
                        let vs = value.split(' ');
                        this.firstName = "*" + vs[0];
                        this.lastName = vs[1];
                   }
               }
           }
       })
       app.fullName = 'zhang san';
    </script>
           

計算屬性是依賴其他屬性的,隻要其他屬性發生改變,計算屬性就會跟着發生變化。setter屬性可以接收一個參數,這個參數接收了并不是一定能改變計算屬性的值,而是根據參數,去改變對應的計算屬性依賴的值,依賴的值改變,getter方法會傳回對應格式的資料。

計算屬性擴充

計算屬性可以依賴其他計算屬性,計算屬性也可以依賴其他執行個體資料,這裡示範計算屬性依賴其他執行個體資料。

<div id="app1">
        {{ msg }}
    </div>
    <div id="app2">
        {{message}}
    </div>
    
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app1 = new Vue({
           el: '#app1',
           data: {
               msg: 'message'
           }
       });
       let app2 = new Vue({
           el: '#app2',
           computed: {
               message() {
                   return app1.msg.split('').reverse().join('');
               }
           }
       })
       app1.msg = 'hello world!';
       
    </script>
           

計算屬性緩存

計算屬性(computed)類似于方法(methods),但是方法每次調用都會被執行,而計算屬性則不同,隻有在計算屬性所依賴的資料發生改變時才會執行。

<div id="app1">
		計算屬性是一個屬性,可以直接使用,methods是方法,需要調用
        {{ cTime }},<br/> {{ mTime() }}
    </div>
  
    <script src="./js/vue.min.js"></script>
    <script>
       let app1 = new Vue({
           el: '#app1',
           data: {
               data: new Date()
           },
           computed: {
                cTime() {
                    return this.data + " --- ";
                }
           },
           methods: {
               mTime() {
                   return new Date();
               }
           }
       });
           

v-bind

綁定class

使用對象文法綁定class:

<div id="app">
        <span :class="{ 'red': isRed, 'error': isError}">這段話的顔色</span>
    </div>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               isRed: true,
               isError: true,
               active: 'active',
               primary: 'primary'
           }
       })
    </script>
           

<span :class="{ ‘red’: isRed, ‘error’: isError}">這段話的顔色</span>

,這裡為class綁定一個對象,對象的屬性名将作為class屬性的值,當且僅當對象屬性的值為true時,才會被應用。

使用數組文法綁定class

使用數組文法,可以嵌套對象文法。

<div id="app">
        <span :class="[{ 'red': isRed, 'error': isError}, active, primary]">這段話的顔色</span>
    </div>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               isRed: true,
               isError: true,
               active: 'active',
               primary: 'primary'
           }
       })
    </script>
           

要綁定多個class屬性需要使用對象文法或者數組文法,如果都不使用,而是直接使用資料,最多隻能有一個資料。

錯誤寫法:

正确寫法(隻能有一個):

綁定内聯樣式

對象文法,與綁定class不同的是,對象屬性作為内聯樣式屬性,資料的值作為樣式的值,而不是根據true和false來确定應用誰

<div id="app">
        <span :style="{'color': red, 'fontSize': fontSize + 'px'}">這段話的顔色</span>
    </div>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               red: 'red',
               fontSize: 20
           }
       })
    </script>
           

使用數組文法綁定多個樣式

<div id="app">
        <span :style="[color, font]">這段話的顔色</span>
    </div>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               color: {
                   color: 'red',
                   background: 'green'
               },
               font: {
                   fontSize: 20 + 'px'
               }
           }
       })
    </script>
           

内置指令

v-cloak

v-cloak

的作用:如果網速較慢等情況下,資料加載較慢,{{data}}可能會直接顯示在頁面上,而v-cloak的作用就是阻止這種情況的發生。使用v-cloak時需要配合下面css樣式:

[v-cloak] {
            display: none;
        }
           
<div id="app">
        <span v-cloak>{{ msg }}</span>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: 'message'
           }
       })
    </script>
           

v-pre

v-pre

的作用:{{data}}是取資料,而有時候我們需要原樣輸出,即{{}}不具備任何功能,這是就可以使用v-pre

<div id="app">
        <span v-pre>{{ msg }}</span>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: 'message'
           }
       })
    </script>
           

v-once

使用v-once,資料隻被渲染一次,之後資料發生變化使用了v-once的資料也不會被渲染

<div id="app" @click="changeMsg">
        <span>{{ msg }}</span><br/>
        <span v-once>{{ msg }}</span>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: 'message'
           },
           methods: {
               changeMsg() {
                   this.msg = this.msg.split('').reverse().join('');
               }
           }
       })
           

v-if、v-else-if、v-else

v-if和

v-show

的差別是,v-if不會加載html标簽,v-show時設定css樣式dispaly為none,

v-show

多用于頻繁操作的場景。

<div id="app">
        <span v-if='status == 1'>1</span>
        <span v-else-if='status == 2'>2</span>
        <span v-else-if='status == 3'>3</span>
        <span v-else>4</span>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               status: 3
           }
       })
    </script>
           

可以使用

<template>

标簽作為v-if的載體,

<template>

最終不會被加載到html中。

注:使用v-if時vue會盡可能的複用元件,比如下面代碼,點選切換的時候,vue做的其實就是把相同标簽的不同的地方更換了,即把手機号換成了郵箱,name屬性的phone換成了email:

<div id="app">
        <template v-if='status === 1'>
            <label>手機号:</label>
            <input type="text" name="phone">
        </template>
        <template v-if='status === 2'>
            <label>郵箱:</label>
            <input type="text" name="emial">
        </template>
        <button @click='change'>切換</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               status: 1
           },
           methods: {
               change() {
                   this.status = this.status === 1 ? 2 : 1;
               }
           }
       })
    </script>
           

如果不需要元件被複用,可以元件添加一個key屬性,屬性的值必須是唯一的。

v-for

v-for用來周遊數組或者對象屬性,也可以結合template标簽使用。

周遊數組時,有兩個參數可選,第一個是每一項的資料,第二個是索引。周遊對象時,第一個參數是對象的屬性名,第二個參數是對象屬性值,第三個參數是索引:

<div id="app">
       <ul>
           <li v-for="(a, index) of arr"> {{ a }} -- {{ index }}</li>
       </ul>
       <template v-for="(key, value, index) of person">
            {{ index }} : {{ key }} -> {{ value }}<br>
       </template>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               arr: [1, 3, 5, 7],
               person: {
                   name: 'zs',
                   age: 18,
                   address: 'China'
               }
           }
       })
           

v-for疊代整數

<div id="app">
   <span v-for="(item, index) of integer">{{index}} : {{item}} /</span>
</div>
<script src="./js/vue.min.js"></script>
<script>
   let app = new Vue({
       el: '#app',
       data: {
         integer: 10
       }
   })
</script>
           

更新數組觸發資料改變的方法

  • push():向原數組末尾增加一個元素

    示例:

<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [1,2,3,4,5]
           }, 
           methods: {
               change() {
                 this.arr.push(6);
               }
           }
       })
           
  • pop():從數組末尾删除一個元素

    示例:

<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [1,2,3,4,5]
           }, 
           methods: {
               change() {
                 this.arr.pop();
               }
           }
       })
    </script>
           
  • shift():從數組開頭删除一個元素
<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [1,2,3,4,5]
           }, 
           methods: {
               change() {
                 this.arr.shift();
               }
           }
       })
    </script>
           
  • unshift():向數組開始位置添加一個元素
<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [1,2,3,4,5]
           }, 
           methods: {
               change() {
                 this.arr.unshift(1);
               }
           }
       })
    </script>
           
  • splice():改變數組長度

    示例:

<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [1,2,3,4,5]
           }, 
           methods: {
               change() {
                 this.arr.splice(2);
               }
           }
       })
    </script>
           
  • sort():數組排序
<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [7,2,1,4,5]
           }, 
           methods: {
               change() {
                this.arr.sort((a, b) => {
                    // a-b就相當于a要大于b,升序排序
                    return a - b;
                })
               }
           }
       })
    </script>
           
  • reverse() :反轉數組

    示例:

<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [7,2,1,4,5]
           }, 
           methods: {
               change() {
                this.arr.reverse();
               }
           }
       })
    </script>
           
  • filter():數組過濾,不改變原數組,傳回一個新的數組

    示例:

<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [7,2,1,4,5]
           }, 
           methods: {
               
               change() {
                    console.log(this.arr);
                    // 不改變原數組,産生一個新的數組
                    this.arr = this.arr.filter(function(data) {
                        return data > 2;
                    });
               }
           }
       })
    </script>
           
  • concat():連接配接數組,把一個數組追加大目前數組後,不改變原有數組,産生新的數組

    示例:

<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [7,2,1,4,5]
           }, 
           methods: {
               
               change() {
                    let arr2 = ['a', 'b', 'c'];
                    this.arr = this.arr.concat(arr2);
               }
           }
       })
    </script>
           
  • slice():根據下腳标查找元素,不改變原有數組,産生一個新數組并傳回

    示例:

<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [7,2,1,4,5]
           }, 
           methods: {
               
               change() {
                    let arr2 = [2,4];
                    // 查找數組中索引大于等于2的所有元素,組成一個新數組并傳回
                    // this.arr = this.arr.slice(2);
                    // 查找下腳标大于等于0小于1的元素,組成一個新數組并傳回
                    this.arr = this.arr.slice(0,1);
               }
           }
       })
    </script>
           

v-on

監聽事件:

<div id="app" >
       {{count}}
       <button @click="count++">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             count: 0
           }
       })
    </script>
           

綁定使用方法:

<div id="app" >
       {{count}}
       可以傳參,也可以傳入目前事件$event
       <button @click="change('abc',$event)">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             count: 0
           },
           methods: {
               change(param) {
               		// 可以通過event去通路事件
                    console.log(param, event);
               }
           }
       })
   </script>
           

事件修飾符.stop,.prevent,.capture,.self,.once

  • .stop 阻止事件冒泡

    示例:點選button按鈕,如果事件冒泡的話,也會觸發div的單擊事件,但是在button上使用.stop就會阻止事件冒泡

<div id="app" >
       {{count}}
       <div @click="count++">
            <button @click.stop=''>change</button>
       </div>
       
    </div>
           
  • .prevent 阻止事件的預設行為

    示例:

<div id="app" >
       {{count}}
       <div @click="count++">
            <a href="www.baidu.com" @click.prevent=''>change</a>
       </div>
    </div>
           
  • .capture 事件捕獲模式

    下面代碼先執行1後執行2,如果不适應.capture的話是先執行2後執行1

<div id="app" >
   <div @click.capture="change(1)">
        <button @click.capture='change(2)'>change</button>
   </div>
</div>
           
  • .self 元素本身觸發事件時才執行
<div id="app" >
       {{count}}
       <div @click.self="count++">
       		<!--點選button不會觸發div的單擊事件-->
            <button @click.prevent=''>change</button>
       </div>
    </div>
           

v-model

使用v-model實作表單資料綁定,v-model可以用@input來實作。

<div id="app" >
        {{msg}}
       <input v-model="msg" placeholder="請輸入...">
       <input @input="input" placeholder="請輸入..." :value="msg">
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             msg: ''
           },
           methods: {
               input(e) {
                    this.msg = e.target.value;
               }
           }
       })
    </script>
           

元件

元件注冊

<div id="app" >
        <!-- 使用全局注冊的元件 -->
       <my-component></my-component>
       <!-- 使用局部注冊的元件 -->
       <child></child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
        // 注冊全局元件
        Vue.component('my-component', {
            template: '<div>xxx</div>'
        });
       let app = new Vue({
           el: '#app',
           // 注冊局部元件
           components: {
               'child': {
                   template: '<div>child</div>'
               }
           }
       })
    </script>
           

挂載元件

在類似于table這樣的标簽中,隻能使用td,tr等,不能使用自定義元件的時候,需要把元件挂載到某個節點上。

<div id="app" >
       <table>
            <!-- 通過is屬性挂載元件 -->
            <tbody is='child'></tbody>
       </table>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           // 注冊局部元件
           components: {
               'child': {
                   template: '<th>child</th>'
               }
           }
       })
    </script>
           

通過props傳遞資料:

<div id="app" >
       <table>
            <!-- 通過is屬性挂載元件 -->
            <tbody is='child' message='傳遞資料的方式'></tbody>
       </table>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           // 注冊局部元件
           components: {
               'child': {
                   props: ['message'],
                   template: '<th>{{message}}</th>'
               }
           }
       })
    </script>
           

子元件向父元件傳值

<div id="app" >
        {{ msg }}
        <!-- 通過子元件定義的事件來接收子元件傳遞的值 -->
       <child @data='changeData' message='h'></child>
    
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: 'o'
           },
           methods: {
                changeData(data) {
                    // data就是 子元件 傳遞過來的資料
                    this.msg = data;
                }
           },
           // 注冊局部元件
           components: {
               'child': {
                   props: ['message'],
                   template: '<div>{{message}}' +
                            '<button @click="change">傳遞資料</button></div>',
                   methods: {
                        change() {
                            // 子元件通過$emit傳值,第一個參數是自定義事件名稱,第二個參數是傳的值
                            this.$emit('data','abc')
                        }
                   }
               }
           }
       })
  </script>
           

使用v-model和$emit傳值

<div id="app" >
        {{msg}}
        <child v-model='msg'></child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: '0'
           },
           methods: {
               changeMsg(data) {
                   this.msg = data;
               }
           },
           components: {
               child: {
                   template: '<button @click="sendMsg">傳遞資料</button>',
                   methods: {
                       sendMsg() {
                           this.$emit('input', 'abc');
                       }
                   }
               }
           }
       })
    </script>
           

上面這個對應的自定義事件寫法:

<div id="app" >
        {{msg}}
        <child @input='changeMsg'></child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: '0'
           },
           methods: {
               changeMsg(data) {
                   this.msg = data;
               }
           },
           components: {
               child: {
                   template: '<button @click="sendMsg">傳遞資料</button>',
                   methods: {
                       sendMsg() {
                           this.$emit('input', 'abc');
                       }
                   }
               }
           }
       })
    </script>
           

中央事件總線

<div id="app" >
        {{msg}}
        <child></child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       // 建立一個空執行個體vue,隻用于傳遞資料
       var bus = new Vue();
       let app = new Vue({
           el: '#app',
           data: {
               msg: '0'
           },
           mounted() {
                let _this = this;
                // 通過這個空執行個體vue監聽這個事件,并接收資料
                bus.$on('input', (data) => {
                    _this.msg = data;
                })
           },
           components: {
               child: {
                   template: '<button @click="sendMsg">傳遞資料</button>',
                   methods: {
                       sendMsg() {
                           // 通過空執行個體vue注冊一個事件,并傳遞資料
                           bus.$emit('input', 'abc');
                       }
                   }
               }
           }
       })
    </script>
           

父($parent)鍊傳遞資料

多個父元件隻需要多次.$parent就可以了。但是這種子元件直接修改父元件的方式不推薦使用。(緊耦合)

<div id="app" >
        {{msg}}
        <child></child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: '0'
           },
           components: {
               child: {
                   template: '<button @click="sendMsg">傳遞資料</button>',
                   methods: {
                       sendMsg() {
                           // 直接修改父元件的資料
                           this.$parent.msg = 'hahaha';
                       }
                   }
               }
           }
       })
    </script>
           

子元件索引

<div id="app" >
        {{msg}}
        <!-- ref 為元件取一個别名 -->
        <child ref='childA'></child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: '0'
           },
           mounted() {
                // 通過$refs.别名 去通路子元件的資料
                this.msg = this.$refs.childA.msg;
           },
           components: {
               child: {
                   template: '<button @click="sendMsg">傳遞資料</button>',
                   data() {
                       return {
                           msg: '12345'
                       }
                   },
                   methods: {
                       sendMsg() {
                           // 直接修改父元件的資料
                           this.$parent.msg = 'hahaha';
                       }
                   }
               }
           }
       })
    </script>
           

slot插槽

<div id="app" >
       <child>
           <!-- 向插槽内添加資料 -->
           <p>{{msg}}</p>
       </child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let vue = new Vue({
           el: '#app',
           data: {
               msg: '12345'
           },
           components: {
               child: {
                //    slot作為插槽,在使用目前元件時,如果在标簽内寫入了内容,就替換插槽内的内容
                   template: "<div>子元件的内容:<slot>插槽</slot></div>"
               }
           }
       });
    </script>
           

具名slot

用于向指定的插槽内添加資料:

<div id="app" >
       <child>
           <!-- 向插槽内添加資料 -->
           <p>
               <!-- 向name為n2的插槽内添加資料 -->
               <div slot='n2'>{{msg}}</div>
           </p>
       </child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let vue = new Vue({
           el: '#app',
           data: {
               msg: '12345'
           },
           components: {
               child: {
                //    slot作為插槽,在使用目前元件時,如果在标簽内寫入了内容,就替換插槽内的内容
                   template: "<div>子元件的内容:<slot name='n1'>插槽</slot><slot name='n2'>2</slot></div>"
               }
           }
       });
    </script>
           

使用component标簽挂載模闆

is指定要挂載的是哪個模闆,可以動态指定

:is

<div id="app" >
      <component is='child'></component>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let vue = new Vue({
           el: '#app',
           data: {
               msg: '12345',
           },
           components: {
               child: {
                   name: 'child',
                   template: "<div>123</div>"
               }
           }
       });
    </script>
           

$nextTick

下面代碼執行會報錯:

<div id="app" >
        <div id="content" v-if='isShow'>hello world!</div>
        <button @click='isShow = false'>隐藏</button>
        <button @click='getText'>顯示并擷取内容</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let vue = new Vue({
           el: '#app',
          data: {
                isShow: true
          },
          methods: {
              getText() {
                  this.isShow = true;
                  // this.isShow = true 此時并沒有去更新dom,而是開啟一個隊列,在隊列中處理資料(去重,得到最終改變),
                  // 不是資料改變一次,頁面就渲染一次,隻有所有資料最終固定後渲染資料,改變dom,是以此時去擷取一個不存在的元素報錯
                  // 在下一次事件循環tick完成更新
                  let msg = document.getElementById("content").innerText;
                  console.log(msg);
              }
          }
       });
    </script>
           

修改後,使用$netTick

<div id="app" >
        <div id="content" v-if='isShow'>hello world!</div>
        <button @click='isShow = false'>隐藏</button>
        <button @click='getText'>顯示并擷取内容</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let vue = new Vue({
           el: '#app',
          data: {
                isShow: true
          },
          methods: {
              getText() {
                  this.isShow = true;
                  // this.isShow = true 此時并沒有去更新dom,而是開啟一個隊列,在隊列中處理資料(去重,得到最終改變),
                  // 不是資料改變一次,頁面就渲染一次,隻有所有資料最終固定後渲染資料,改變dom,是以此時去擷取一個不存在的元素報錯
                  // 在下一次事件循環tick完成更新
                  // $nextTick可以知道什麼時候dom更新完成
                  this.$nextTick(() => {
                    let msg = document.getElementById("content").innerText;
                    console.log(msg);
                  });
              }
          }
       });
    </script>
           

自定義指令

注冊指令的兩種方式

一、全局注冊

Vue.directive('指令名', {
            // 指令選項
        })
           

二、局部注冊

new Vue({
      el: '#app', 
        directivies: {
            '指令名': {
                // 指令選項
            }
        }
    })
           

使用 v-指令名 即可。

全局方式:

<div id="app" >
        <input v-focus>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
        Vue.directive ('focus', {
            inserted(el) {
                el.focus();
            }
        })
    </script>
           

局部方式:

<div id="app" >
        <input v-focus>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
        let app = new Vue({
            el: '#app',
            directives: {
                focus: {
                    inserted: function(el) {
                        el.focus();
                    }
                }
            }
        })
    </script>
           

虛拟dom

<div id="app" >
       <anchor :level='2' title="特性">特性</anchor>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
        Vue.component('anchor', {
            props: {
                level: {
                    type: Number,
                    required: true
                },
                title: String,
                default: ''
            },
            render: function(createElement) {
                return createElement(
                    'h' + this.level,
                    [
                        createElement(
                            'a',
                            {
                                domProps: {
                                    href: '#' + this.title
                                }
                            },
                            this.$slots.default
                        )
                    ]
                )
            }
        })
        let app = new Vue({
            el: '#app'
        })
    </script>
           

vue-router

安裝vue-router

npm install vue-router --save
           

配置vue-router

import Vue from 'vue'
import App from './App.vue'
// 導入vue-router
import VueRouter from 'vue-router'
// 導入vue元件
import Index from './views/Index'
import About from './views/About'

// 配置路由群組件映射
const Routers = [
  {
    path: '/index',
    component: Index
  },
  {
    path: '/about',
    component: About
  },
  {
    path: '*',
    redirect: '/index'
  }
]
// 配置路由
const RouterConfig = {
  mode: 'history',
  routes: Routers
}
// 建立vue-router執行個體
const router = new VueRouter(RouterConfig)

Vue.use(VueRouter)

Vue.config.productionTip = false

new Vue({
  el: '#app',
  router: router,
  render: h => h(App)
}).$mount('#app')

           

配置跳轉

方式一,router-link

<router-view></router-view>

标簽内顯示元件内容,

router-link

标簽類似a标簽,tag标簽使用與指定router-link使用哪個标簽實作。

<template>
  <div id="app">
    hello
    <router-view></router-view>
    <router-link to='/index'>首頁</router-link>
    <router-link to='/about' tag='span'>關于</router-link>
  </div>
</template>

<script>
export default {

}
</script>
<style scoped>
  #app {
    color: red;
  }
</style>

           

router-link

的其他屬性:

replace :不會留下曆史記錄,回退不能回到上個頁面
 <router-link replace to='/about' >關于</router-link>
           
active-class:目前router-link被選中時的類名,比如下面這個關于被選中時的class屬性為about
<router-link to='/about' tag='span' replace active-class='about'>關于</router-link>
           

方式二,api跳轉

this.$router.push(’/about’)

<template>
  <div id="app">
    hello
    <router-view></router-view>
    <router-link to='/index'>首頁</router-link>
    <router-link to='/about' tag='span' replace active-class='about'>關于</router-link>
    <button @click="handleRouter">API跳轉</button>
  </div>
</template>

<script>
export default {
  methods: {
    handleRouter () {
     // 通過api的方式跳轉
      this.$router.push('/about')
    }
  }
}
</script>
<style scoped>
  #app {
    color: red;
  }
</style>

           

$router的其他方法:

replace: 方法類似于router-link中的replace屬性,this.$router.replace('/index')
go:類似于window.history.go(),表示向前或向後後退多少步。例如this.$router.go(-1)後退1頁,this.$router.go(2)前進2頁
           

router鈎子函數

beforeEach

進入路由前beforeEach函數:

// 配置路由群組件映射
const Routers = [
  {
    path: '/index',
    meta: {
      title: '首頁'
    },
    component: Index
  },
  {
    path: '/about',
    meta: {
      title: '關于'
    },
    component: About
  },
  {
    path: '*',
    redirect: '/index'
  }
]
// 配置路由
const RouterConfig = {
  mode: 'history',
  routes: Routers
}
// 建立vue-router執行個體
const router = new VueRouter(RouterConfig)

// 進入路由前
router.beforeEach((to, from, next) => {
  window.document.title = to.meta.title
})
           

meta字段可以自定義資訊。

三個參數:

to:要跳轉到的路由
from: 從哪個路由跳轉的
next:函數,調用這個函數才進入下一個鈎子,否則路由不跳轉
           

afterEach

每一個路由中的設定

比如進入每個頁面後,滾動條都在起始位置:

router.afterEach((to, from, next) => {
	window.scrollTo(0,0)
})
           

或者判斷是否登入:

router.afterEach((to, from, next) => {
	if ('登入') {
		next(); // 允許路由跳轉
	} else {
		next('login'); // 否則跳轉到登入頁面
	}
})
           

next()

函數,不接受參數,路由跳轉,設定為false,路由取消跳轉,參數為具體路由,跳轉到指定路由。

vuex

安裝vuex

npm install vuex --save
           

配置vuex

在main.js中配置

import Vuex from 'vuex'

Vue.use(Vuex)

// 配置vuex
const store = new Vuex.Store({

})
new Vue({
  el: '#app',
  router: router,
  store: store, // 配置vuex
  render: h => h(App)
}).$mount('#app')
           

使用vuex,建立資料

資料儲存在state字段:

const store = new Vuex.Store({
  state: {
    count: 0
  }
})
           

擷取vuex中的資料

通過$store.state.xxx通路資料

<template>
    <div>
        首頁 {{ $store.state.count }}
        <button @click="handleCount">加一</button>
    </div>
</template>
<script>
export default {
  methods: {
    handleCount () {
      this.$store.state.count++
    }
  }
}
</script>

           

這樣通路每次都會調用

$store.state.xxx

,可以把這個作為計算屬性

<template>
    <div>
        首頁 {{ count }}
        <button @click="handleCount">加一</button>
    </div>
</template>
<script>
export default {
  computed: {
    count () {
      return this.$store.state.count
    }
  },
  methods: {
    handleCount () {
      this.$store.state.count++
    }
  }
}
</script>

           

使用mutations修改states的資料

state中的資料不建議直接修改,而是通過mutations屬性定義方法來修改

// 配置vuex
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    },
    decrease (state, n = 1) {
      state.count -= n
    }
  }
})
           

在元件中掉喲mutations中的方法來改變資料,調用mutations中的資料要使用commit來調用:

<template>
    <div>
        首頁 {{ count }}
        <button @click="handleCountA">加</button>
        <button @click="handleCountD">減</button>
    </div>
</template>
<script>
export default {
  computed: {
    count () {
      return this.$store.state.count
    }
  },
  methods: {
    handleCountA () {
      this.$store.commit('increment')
    },
    handleCountD () {
      this.$store.commit('decrease', 2)
    }
  }
}
</script>

           

commit接收對象

main.js中定義方法:

mutations: {
    increment (state) {
      state.count++
    },
    decrease (state, n = 1) {
      state.count -= n
    },
    // param作為一個對象
    change (state, param) {
      state.count += (param.count1 - param.count2)
    }
  }
           

在元件中調用,type就是要調用的方法名,其他的就是具體的參數:

changeCount () {
  this.$store.commit({
    type: 'change',
    count1: 1,
    count2: 5
  })
}
           

在mutations中不要做異步操作,commit後資料不能及時跟新。

getters

getters類似于計算屬性

需求:對一個數組進行過濾,去大于10的數

state: {
    count: 11,
    list: [1, 3, 5, 7, 10, 11, 13, 15]
  },
getters: {
    listFilter: state => state.list.filter(data => data > 10),
    // getters中的資料也可以通路其他getters中的資料
    equalseCount: (state, getters) => getters.listFilter.filter(data => data === state.count)
  },
           

通路getter資料:

getter中的資料 {{ $store.getters.listFilter }} -> {{ $store.getters.equalseCount}}
           

異步操作資料使用actions

定義actions

mutations: {
    increment (state) {
      state.count++
    },
    decrease (state, n = 1) {
      state.count -= n
    },
    change (state, param) {
      state.count += (param.count1 - param.count2)
    }
  },
  actions: {
    increment (context, param) {
      context.commit('change', param)
    }
  }
           

調用actions要使用dispatch方法

actions () {
      this.$store.dispatch({ // 使用dispath方法調用action中的方法
        type: 'increment',
        count1: 1,
        count2: 5
      })
    }
           

異步案例:

actions:

actions: {
    asyncIncrement (context) {
      return new Promise(resolve => {
        setTimeout(() => {
          context.commit('increment')
          resolve('success')
        }, 2000)
      })
    }
  }
           

在元件中調用:

async () {
      this.$store.dispatch('asyncIncrement').then(data => console.log(data))
    }
           

資料改變用mutations,存在業務邏輯用actions

modules狀态區分

如果所有的狀态寫在一起不容易區分,這時可以用modules來做區分:

const moduleA = {
  state: {
    count: 10
  }
}

const moduleB = {
  state: {
    count: 20
  },
  getters: {
    sumCount (state, getters, rootState) {
      return state.count + rootState.b.count + rootState.count
    }
  }
}

// 配置vuex
const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  },
  state: {
    count: 11,
    list: [1, 3, 5, 7, 10, 11, 13, 15]
  },
}
           

擷取,要注意的是 子產品内部的 action、mutation、和 getter 注冊在全局命名空間,不能使用子產品名.getters等方式去調用

<template>
    <div>介紹 {{ $store.state.count }}
        moduleB中的Count {{ $store.state.b.count }}
        moduleB中的sumCount {{ $store.getters.sumCount }}
    </div>
</template>
<script>
export default {
}
</script>

           

中央事件總線vue-bus

建立一個vue-bus.js檔案:

const install = function (Vue) {
    const Bus = new Vue({
        methods: {
            emit(event, ...args) {
                this.$emit(event, args)
            },
            on(event, callback) {
                this.$on(event, callback);
            },
            off(event, callback) {
                this.off(event, callback)
            }
        }
    })
    Vue.prototype.$bus = Bus
}
export default install

           

在main.js中引入并使用:

import VueBus from './vue-bus'

Vue.use(VueBus)
           

在元件中使用-發送資料:

<template>
    <div id="app">
        <img alt="Vue logo" src="./assets/logo.png">
        <button @click="handleNum">click</button>
        <HelloWorld/>
    </div>
</template>

<script>
    import HelloWorld from './components/HelloWorld.vue'

    export default {
        name: 'app',
        components: {
            HelloWorld
        },
        methods: {
            handleNum() {
                this.$bus.emit('add', 10);
            }
        }
    }
</script>

<style>

</style>

           

擷取資料:

<template>
    <div class="hello">
        <h1>{{ number }} </h1>
    </div>
</template>

<script>
    export default {
        name: 'HelloWorld',
        data() {
            return {
                number: 0
            }
        },
        methods: {
            handle(num) {
                let data = parseInt(num)
                this.number += data
            }
        },
        created() {
            this.$bus.on('add', this.handle)
        },
        beforeDestroy() {
            this.$bus.off('add', data => console.log(data))
        }
    }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

           
下一篇: Vue基礎-1