Vue 超詳細手記

Vue

Vue實例屬性

名稱 內容
$data 傳入的data內容,修改可引發頁面內容變化
$props 父組件傳入子組件
$el 綁定的html的節點
$options 新建Vue實例對象時穿進去的內容,修改optins的內容不會引發頁面變化,有render方法,在頁面從新渲染時會調用
$root 整個Vue對象的根節點,app.$root === app
$children 組件內部的元素
$slots 插槽
$scopedSlots 區域化插槽
$refs 模板的引用
$isServer 服務端渲染時能夠用來判斷
$watch 監聽內容,與寫在實例中效果相同,但經過$watch寫的監聽要返回的unWatch方法結束監聽
$on 監聽事件是否被觸發,能夠獲取emit傳遞的參數
$emit 觸發事件,監聽哪一個對象就要經過哪一個事件觸發,能夠傳值
$once 與on類似,但只被觸發一次
$forceUpdate 強制組件從新渲染
$set 給新值賦值而且頁面會渲染
$delete 刪除值
$nextTick 異步操做

Vue 生命週期

生命週期 介紹 可調用次數
beforeCreate 還未綁定Dom,不能進行dom操做**(不要放入ajax請求)**
created 還未綁定Dom,不能進行dom操做
beforeMount el只爲html中寫的節點,還未綁定,說明還未渲染(未調用render方法)
mounted el綁定爲渲染後的節點,說明以前進行了渲染(已調用render方法),實例已經建立完成
beforeUpdate 更新的對象時模板,須要虛擬DOM的重洗渲染和補丁修改,可是若是更改的數據在模板中沒有使用,就不會進行更新
updated 數據更改致使虛擬DOM從新渲染和打補丁,注意要避免在這個鉤子函數中操做數據
activated
deactivated
beforeDestory 實例銷燬以前調用。在這一步,實例仍然徹底可用,this仍能獲取到實例。通常在這一步中進行:銷燬定時器、解綁全局事件、銷燬插件對象等操做
destoryed Vue 實例銷燬後調用。調用後,Vue 實例指示的全部東西都會解綁定,全部的事件監聽器會被移除,全部的子實例也會被銷燬

生命週期圖示

Computed 的特性

  • computed內置緩存,在頁面從新渲染時若是computed的值沒有發生變化便不會再從新渲染,提升性能
  • computed能夠作設置操做,但不建議用computed作設置操做,有必定機率致使重複計算

Wacth 的特性

  • watch能夠用來監聽數據的變化
  • 第一次渲染watch並不會渲染出內容,若是要初次渲染加上handler方法
  • handler 只監聽監聽對象引用的變化,屬性的變化並不會調用handler方法
  • immediate屬性能夠用來確認是否以當前的初始值執行handler的函數
  • 將deep屬性設置爲true就能夠監聽對象屬性的變化
  • 建議不要再watch內修改監聽的值和屬性

Vue指令

指令名 指令做用
v-text 標籤裏面要顯示的文本內容,內容較多時不建議使用
v-html 將html代碼片斷展現爲html標籤
v-show 根據內容的Boolean值來顯示或不顯示內容,原理是設置display:none;
v-if 與v-show不一樣的是若是判斷爲false將不會放在文檔流裏,若是頻繁切換會動態增刪節點,會形成性能問題 搭配指令有 v-else v-else-if
v-for 循環,用法爲 v-for="item in arr",item爲數組內的值或對象,arr爲儲存值的數組,若是要拿到順序則寫爲v-for="(item, index) in arr" 遍歷對象可用 v-for="(val, key,index) in obj"的方式,val爲值,key爲對應的鍵,index爲對應的索引值即順序,使用v-for時須要:key=""來綁定一個惟一識別
v-on 監聽事件,能夠監聽到$emit觸發的事件
v-model 雙向綁定數據,可進行實時更改,通常用於input,通常輸入以後會變爲字符串
若是想讓值爲數字,在v-model後加.number修飾符
若是想去掉首位的空格,在v-model後加.trim修飾符
若是不想實時更改,而是失焦後更改,在v-model後加.lazy修飾符
v-pre 不解析內部內容,即內部內容保留源格式
v-cloak 通常直接在頁面引入vue.js代碼時使用,在vue代碼完成以前讓內容隱藏,vue加載完成後再展現
v-once 數據綁定內容只執行一次,通常爲靜態內容使用,節省性能開銷,不會作虛擬DOM對比

組件

定義組件

首先寫一個組件內容javascript

const component = {
    templete: '<div>This is compoent</div>'
}
複製代碼

而後咱們用Vue實例的方法引入組件html

import Vue from 'vue'
Vue.component('ComponentName',component); //定義了一個名爲name的組件
//組件名用大寫開頭並用駝峯命名 (類的思想)
複製代碼

使用時:前端

第一種狀況-直接在tempelate內使用:vue

new Vue({
    el:'#root',
    tempelate:'<component-name></component-name>' //使用時使用小寫,而且單詞之間用-鏈接
})
複製代碼

第二種狀況-從新命名使用:java

new Vue({
    el:'#root',
    tempelate:'<new-name-component></new-name-component>',
    //使用時使用小寫,而且單詞之間用-鏈接
    components: {
        newNameComponent: component
    }
})
複製代碼

在組件內部綁定數據-data

const component = {
    templete: '<div>{{text}}</div>',
    data(){  //必需要使用函數返回值的方式
        return{
            text:'hello'
        }
    }
}
複製代碼

使用一個return新對象的方法能夠防止多個組件動態綁定至一個相同的值,例如v-model的場景就會出現相關的問題webpack

組件內部傳遞數據-props

const component = {
    templete: ` <div> <span v-show="active">see me if active</span> <span>{{propOne}}</span> //prop與data類似都是綁定在this上,能夠直接使用 </div> `
    data(){  //必需要使用函數返回值的方式
        return{
            text:'hello'
        }
    },
    props: {
        active: Boolean,//向組件傳遞一個布爾值,key爲active
        propOne: String  //駝峯式命名
        
    }
}
複製代碼

使用時web

new Vue({
    el:'#root',
    tempelate:` <new-component :active="true" prop-one="123"></new-component> //須要用v-bind解析傳入的值 <new-component :active="false" prop-one="456"></new-component> //在prop中爲駝峯式的命名在使用時使用小寫而且用-鏈接的方式(非強制,只是規範) `,
    //使用時使用小寫,而且單詞之間用-鏈接
    components: {
        NewComponent: component
    }
})
複製代碼

props數據的一些設置ajax

const component = {
    props: {
        active: {
            type: Boolean, //設置爲布爾值
            required: true, //這個屬性爲必需屬性
            default: true, //設置默認值爲true,若是有了default就不須要required
            validator (value) {   //可用來檢測輸入的值是否符合要求,可用來自定義檢測
            	return typeof value === 'Boolean' 
        	}
        },
        propOne: {
            type: Object,
            default() {   //若是默認值爲一個對象,則應該用函數返回一個對象的形式
                return {
                    
                }
            }
        }
    },
    .....
}
複製代碼

組件的extend

extend實例內的值

當咱們新建一個Vue實例時,它內部都是一些默認的屬性,若是咱們想使用咱們已經定義過的組件的一些屬性內容咱們能夠用下列代碼:vue-router

... 已建立組件component

const ComponentVue = Vue.extend(component);  //前提是component沒有required爲true的props

new ComponentVue({
    el: '#root',
})
複製代碼

但若是咱們須要用到props呢?vuex

咱們能夠用下面的方式:

... 已建立組件component

const ComponentVue = Vue.extend(component); 

new ComponentVue({
    el: '#root',
    propsData: {   //用propsdata來向原組件的props傳值才能使用
    	propOne: 'xxx',
	}
})
複製代碼

extend的mounted

會先執行原組件的mounted,再執行extend實例的mountend

組件內如何實現v-model雙向綁定

const component = {
    props: ['value'],
    template: ` <div> <input type="text" @input="handleInput" v-model="value" > </div> `,
    methods: {
        handleInput(e) {
            this.$emit('input', e.target.value); //向父組件觸發input事件
        }
    }
}

//在Vue實例中

new Vue({
    components: {
        CompOne: component
    },
    el: '#root',
    data () {
        return {
            value: '123'
        }
    }
    template: ` <div> <comp-one :value="value" @input="value = arguments[0]"></comp-one> //arguments數組即爲經過$emit後面傳遞的參數 </div> `
})
複製代碼

咱們還能夠經過下面的功能實現

const component = {
    model: {   
        prop: 'value1', //爲要傳的值
        event: 'change' //爲觸發的事件
    },
    props: ['value1'],
    template: ` <div> <input type="text" @input="handleInput" v-model="value1"> </div> `,
    methods: {
        handleInput(e) {
            this.$emit('input', e.target.value); //向父組件觸發input事件
        }
    }
}

//在Vue實例中

new Vue({
    components: {
        CompOne: component
    },
    el: '#root',
    data () {
        return {
            value: '123'
        }
    }
    template: ` <div> <comp-one v-model="value"></comp-one> //arguments數組即爲經過$emit後面傳遞的參數 </div> `
})
複製代碼

組件高級屬性

插槽 slot

當咱們在Vue實例調用的組件內部直接寫入html元素時,它是不會顯示的,由於咱們沒有告訴組件要放在哪裏顯示,這時就須要 插槽

//組件內
const component = {
    template: ` <div> <slot></slot> //爲內容添加插槽位置,沒有聲明插槽位置的元素都會放在這個裏面 </div> `
}

//實例中
new Vue({
    components: {
        CompOne: component
    },
    el: '#root',
    template: ` <div> <comp-one> <span>我會被放在slot中</soan> </comp-one> </div> `
})
複製代碼

具名插槽

//組件內
const component = {
    template: ` <div> <div class="header"> <slot name="header"></slot> </div> <div class="body"> <slot name="body"></slot> </div> </div> `
}

//實例中
new Vue({
    components: {
        CompOne: component
    },
    el: '#root',
    template: ` <div> <comp-one> <span slot="header">我會被放在slot name爲header的插槽中</soan> <span slot="body">我會被放在slot name爲body的插槽中</soan> </comp-one> </div> `
})
複製代碼

做用域插槽 讓插槽內綁定的數據爲組件的數據

使用方法爲:

//組件內
template: ` <div> <slot value="456" anothervalue="content"></slot> </div> `

//實例中
template:` <div> <comp-one><span slot-scope="props">{{props.value}} {{props.anothervalue}}</span></comp-one> //slot-scope 的對象即爲組件內slot傳遞值的對象 </div> `
複製代碼

或者可使用組件內部data的值,它並不影響本地data的使用:

//組件內
template: ` <div> <slot :value="value" anothervalue="content"></slot> //注意要使用v-bind形式 </div> `,
data() {
    return{
        value="this is data value"
    }    
}

//實例中
template:` <div> <comp-one><span slot-scope="props">{{props.value}} {{props.anothervalue}}</span></comp-one> //slot-scope 的對象即爲組件內slot傳遞值的對象 </div> `
複製代碼

跨級數據交流

如何越級拿到vue組件實例呢?

使用 provide屬性!

//子組件
const ChildComponent = {
    template: '<div>child component</div>',
    inject: ['grandfather']  //獲取實例向外提供的對象
}

//組件
const component = {
    name: 'comp',
    component: {
        ChildComponent //聲明子組件
    },
    template: ` <div> <child-component /> //若是爲空組件能夠這樣書寫 </div> `,
    
}

//實例
new Vue({
    components: {
        CompOne: component
    },
    provide (){
        return{
          grandfather: this  //將本身這個實例做爲對象向外提供,僅爲節點下的節點(子節點 & 子節點的子節點 $ ......)
        } //使用函數返回值的方式的緣由與data相同
    },
    ...
})
複製代碼

但通常provide只提供一次值,不會實現model模式,若要實現須要給provide的值提供得到方法,方法以下:

provide (){
        return{
          const data = {}  //先設置一個空對象
    
    Object.defineProperty(data,'value',{
        get: () => this.value, //沒次使用值時實際上是用了這個get方法
        enumerable: true //可讀屬性
    })
        } 
    }
複製代碼

這種方法雖然是實現了跨級model,但屬於一種hack方法,官方不建議使用。

Render方法

render方法是咱們渲染的一個方法,它內部會返回一個createElement方法,這個方法是Vue給咱們提供的建立節點的方法,使用render方法咱們就能夠不使用template

//組件
const component = {
    name: 'comp',
    props: ['props1'],
    render (createElement) {
        return createElement('div', {
            //data數據 data: this.data形式
        },[   //注意要傳遞數組
            this.$slots.default  //無名爲default,具名slot將default改成名字便可
            this.props1 //傳遞prop值
        ]) 
    }
}

//實例
new Vue({
    components: {
        CompOne: component
    },
    render( createElement ) {  //不必定爲createElement,能夠用其餘字母表示,但下面的方法名要保持一致
        return createElement(
            'comp-one',{
                ref: 'comp'     
            },[            //注意節點內在建立節點要傳遞一個數組
            createElement(
                'span',{
                    ref: 'span',
                    slot: 'header'  //能夠指定要渲染的slot插槽位置
                },this.value)
        ])  //Vue提供的建立節點的函數
    }
})
複製代碼

Render方法下的事件監聽,on 和 nativeOn

on形式的監聽,須要實例和組建中都使用on

//組件
const component = {
    name: 'comp',
    props: ['props1'],
    render (createElement) {
        return createElement('div', {
            on: {
                click: () => {this.$emit('click')} //監聽click事件,向父級觸發click事件
            }
        },[   //注意要傳遞數組
            this.$slots.default  //無名爲default,具名slot將default改成名字便可
            this.props1 //傳遞prop值
        ]) 
    }
}

//實例
new Vue({
    components: {
        CompOne: component
    },
    render( createElement ) {  //不必定爲createElement,能夠用其餘字母表示,但下面的方法名要保持一致
        return createElement(
            'comp-one',{
                ref: 'comp',
                on: {
                    click: this.handleClick //點擊組件會受到組件傳遞的click事件,並觸發handleClick方法 
                }
            },[            //注意節點內在建立節點要傳遞一個數組
            createElement(
                'span',{
                    ref: 'span'
                },this.value)
        ])  //Vue提供的建立節點的函數
    },
    methods: {
        handleClick() {
            //do something....
        }
})
複製代碼

nativeOn 有個很大的便捷,那就是咱們只須要在實例中聲明而組件中能夠不用聲明

//組件
const component = {
    name: 'comp',
    props: ['props1'],
    render (createElement) {
        return createElement('div', {
        },[   //注意要傳遞數組
            this.$slots.default  //無名爲default,具名slot將default改成名字便可
            this.props1 //傳遞prop值
        ]) 
    }
}

//實例
new Vue({
    components: {
        CompOne: component
    },
    render( createElement ) {  //不必定爲createElement,能夠用其餘字母表示,但下面的方法名要保持一致
        return createElement(
            'comp-one',{
                ref: 'comp',
                nativeOn: {
                    click: this.handleClick //nativeOn會自動綁定到組件根節點的dom上面
                }
            },[            //注意節點內在建立節點要傳遞一個數組
            createElement(
                'span',{
                    ref: 'span'
                },this.value)
        ])  //Vue提供的建立節點的函數
    },
    methods: {
        handleClick() {
            //do something....
        }
})
複製代碼

template實際上是render方法的一種編譯方式

V-router

router,顧名思義即爲路由,vue框架可讓咱們在前端實現路由功能,這個功能對WebApp這種應用來講是必不可少的。

使用路由以前須要先安裝模塊,npm install vue-router

通常咱們將路由分爲兩個文件,router.js 和 routes.js,一個用來存放路由信息,另外一個用來寫路由邏輯功能

//routes.js
import Todo from '../views/todo/todo.vue'  //引入要展現的頁面
import Login from '../views/login/login.vue'

export default [
    {
        path: '/', //網頁的路徑
        component: Todo //指定輸入上方路徑後顯示什麼頁面
    },
    {
        path: '/login',
        compoent: Login
    }
]
複製代碼
//router.js
import Router from 'vue-router'  //引入vue-router模塊
import routes from './routes' //引入咱們寫的路由信息


//每次引入路由文件時會返回一個路由對象
export default () => {
    return new Router({
        routes
    })
}
複製代碼

爲了實現跳轉,咱們還須要用router-view來實現對路由跳轉事後的展現

// app.vue
<template>
  <div id="app">
    <div id="cover"></div>
    <Header></Header>
    <router-view></router-view>  //這部分來進行跳轉,頁面內容展現在這部分
    <!-- <todo></todo> -->
    <Footer></Footer>
  </div>
</template>
複製代碼

咱們也能夠用路由來實現首頁重定向,在routes.js寫入這部份內容

//routes.js
import Todo from '../views/todo/todo.vue'  //引入要展現的頁面
import Login from '../views/login/login.vue'

export default [
    {
      path: '/',  
      redirect: '/app' //當輸入默認路徑時重定向到app頁面
    },
    {
        path: '/app', //網頁的路徑
        component: Todo //指定輸入上方路徑後顯示什麼頁面
    },
    {
        path: '/login',
        compoent: Login
    }
]
複製代碼

此時咱們會注意到網頁上的url是 http://localhost:8080/#/app,他默認會傳一個hash,咱們能夠更改這個東西須要更改router.js的內容

import Router from 'vue-router'  //引入vue-router模塊
import routes from './routes' //引入咱們寫的路由信息


//每次引入路由文件時會返回一個路由對象
export default () => {
    return new Router({
        routes,
        mode:'history'  //mode改成 'hash'即爲hash方式
    })
}
複製代碼

此時在此運行我就能夠發現那個#消失了

咱們還能夠經過base屬性設計基路徑

import Router from 'vue-router'  //引入vue-router模塊
import routes from './routes' //引入咱們寫的路由信息


//每次引入路由文件時會返回一個路由對象
export default () => {
    return new Router({
        routes,
        mode:'history',
        base: '/base/'  //設置基路徑爲base,經過vue-router的跳轉都會加入基路徑
    })
}
複製代碼

此時咱們再訪問localhost:8080發現他的路徑跳轉爲了

localhost:8080/base/app

但基路徑並非強制的,咱們把base去掉訪問依然能夠訪問到app

還有兩個屬性使咱們要配合router-link使用的

//app.vue
<template>
  <div id="app">
    <div id="cover"></div>
    <Header></Header>
    <router-link to="/app">app</router-link>
    <router-link to="/login">login</router-link>
    <router-view></router-view>
    <!-- <todo></todo> -->
    <Footer></Footer>
  </div>
</template>
複製代碼

咱們在app.vue中加入兩個router-link(與a標籤相似,原理是經過a標籤實現的),to的內容即爲他們要跳轉的路由,而後咱們能夠全局設置連接的樣式

export default () => {
    return new Router({
        routes,
        mode:'history',
        linkActuveCLass:'active-link', //只要有一部分被激活會加上
        linkExactActiveClass: 'exact-active-link' //當前路徑徹底匹配才加上
    
    })
}
複製代碼

可能會有點難理解,那咱們這樣想,你當前有一個/app的頁面,展現的是app.vue,而後app下面有個子頁面是childApp.vue,路徑是/app/childApp,當咱們在localhost:8080/app/childApp的路徑下時,此時routerlink to 爲childApp的連接的樣式爲'active-link' 和'exact-active-link',而app的routerlink的樣式爲'active-link' 而不會有'exact-active-link'

路徑的映射

咱們把路徑輸入url時,按下回車,會想服務器發送一個請求,若是此時咱們沒有在服務器中,添加路由映射時,瀏覽器會返回咱們一個錯誤信息

Cannot GET /xxx //xxx即爲url的內容

//webpack.config.client.js
const devServer = {
    port: 8000,
    host: '0.0.0.0',
    overlay: {
      errors: true,
    },
    historyApiFallback: {
        index: 'index.html'      //加上這個咱們輸入url後刷新頁面仍是會顯示出內容
    },
    hot: true
  }

複製代碼

頁面的跳轉時的滾動保留

咱們有時在跳轉頁面時,不想回到上一級時已經返回到了頂部而不是跳轉以前的位置,咱們能夠在Router裏設置一個scrollBehavior

export default () => {
    return new Router({
        routes,
        mode:'history',
        scrollBehavior (to, from, savedPosition){ //to -> 跳轉的路由 from -> 當前的路由即跳轉的起始點 savedPosition -> 保存當前滾動條滾動的位置 
            if(savedPosition) {  //若是是有滾動距離的,返回到以前的頁面位置
                return savedPosition
            } else { //不然,返回頂部
                return {x:0 , y:0}
            }
        }
    
    })
}
複製代碼

配置路由的參數

這部分主要講路由方面的參數

name

import Todo from '../views/todo/todo.vue'
import Login from '../views/login/login.vue'

export default [
  {
    path: '/',
    redirect: '/app' //當輸入默認路徑時重定向到app頁面
  },
  {
    path: '/app',
    component: Todo,
    name: 'app'  //給當前的路由設置一個姓名,能夠用來跳轉,與路徑和組件名無強制聯繫
  },
  {
    path: '/login',
    compoent: Login
  }
]

複製代碼

而後在routerlink上能夠進行經過name跳轉

<router-link :to="{name:'app'}"> </router-link>  //傳入對象,讓Vue來解析它
複製代碼

以後就能夠進行跳轉了,沒必要每次都要寫路徑

meta

用來存放一些元信息

import Todo from '../views/todo/todo.vue'
import Login from '../views/login/login.vue'

export default [
  {
    path: '/',
    redirect: '/app' //當輸入默認路徑時重定向到app頁面
  },
  {
    path: '/app',
    component: Todo,
    meta: {
          title:'this is app',  //與html的meta一樣的效果
          description: 'author Reaper Lee'
      }
  },
  {
    path: '/login',
    compoent: Login
  }
]
複製代碼

children

用來寫當前路徑下的子組件

import Todo from '../views/todo/todo.vue'
import Login from '../views/login/login.vue'

export default [
  {
    path: '/app',
    component: Todo,
   children: [ //注意是數組
       {
           path: 'child', //路徑信息,與父級相同
           component: Child 
       }
   ]
  }
]
複製代碼

但注意這個只會在 父組件即(Todo)下的routerview展現,不會和Todo搶佔同一個routerview

路由的Transition

transition顧名思義就是路由的過分,即爲一次過渡動畫,咱們使用時要配合routerview使用

//app.vue
<template>
  <div id="app">
    <router-link to="/app">app</router-link>
    <router-link to="/login">login</router-link>
      <transition name="fade"> //使用fade的動畫做爲過渡
          <router-view></router-view>
      </transition>
  </div>
</template>

<style> //定義這個fade動畫 .fade-enter-active, .fade-leave-active { transition: opacity .5s; } .fade-enter, .fade-leave-to { opacity: 0; } </style>
複製代碼

路由傳參

咱們能夠經過路由傳遞一些參數,這個會在咱們好比查看一個物品的詳情頁等場景使用會比較多。具體方法以下

// routes.js
export default [
  {
    path: '/app/:id', //這裏咱們就聲明瞭一個路由上的參數
    component: Todo,
    
  }
]
複製代碼

此時咱們直接訪問/app 是不會有內容的

但當咱們訪問/app/xxxx (xxxx爲要傳遞的參數),此時咱們就能夠正常的顯示頁面,咱們獲取這個參數能夠在父組件中使用this.$route來獲取參數

this.$router.params.id 就能夠拿到路徑中的參數了,id是咱們在上面的path中給的參數名爲id,要與參數名保持一致
複製代碼

還有一種更強大的方法,那就是把路徑中的參數做爲組件的props傳遞給組件

// routes.js
export default [
  {
    path: '/app/:id', //這裏咱們就聲明瞭一個路由上的參數
    props:true, //這裏咱們設置爲true便可讓參數做爲props傳遞給組件
    component: Todo
  }
]
複製代碼

而後在組件中咱們須要把參數的props聲明

//todo.vue
export default {
    props: ['id']  //聲明一個名爲 id 的props數據
}
複製代碼

而後咱們就能夠在組件中拿到這個參數了!並且經過props傳遞的參數咱們能夠更好的使用,因此若是真的須要經過路徑傳參數咱們儘量使用props。

咱們有時會碰見在主頁要使用多個router-view來展現組件的狀況,此時咱們須要給一些router-view提供name屬性

//app.vue
<template>
  <div id="app">
    <router-link to="/app">app</router-link>
    <router-link to="/login">login</router-link>
    <router-view />   //內部不放內容能夠寫成空標籤形式
    <router-view name="a" />
  </div>
</template>
複製代碼

與此同時,咱們也要修改路由信息的JavaScript文件的一些內容

//routes.js
export default [
  {
    path: '/app/:id', //這裏咱們就聲明瞭一個路由上的參數
      components:{ //注意由於要展現多個組件,因此咱們這裏定義爲components
          default: App   //在沒有給name屬性的router-view中展現的組件
          a: Another  //在name屬性爲a的router-view中展現
      } ,  
    
  }
]
複製代碼

路由導航守衛

當咱們觸發一個導航時,全局前置守衛按照穿件的順序調用,守衛是異步執行的。咱們能夠經過守衛來進行一些攔截,好比只有登陸以後才能進入的一些頁面或者使用的一些功能。

全局:路由守衛有三個鉤子函數
函數名 做用
beforeEach 通常在這個守衛方法中進行全局攔截,好比必須知足某種條件(用戶登陸等)才能進入路由的狀況
beforeResolve 和beforeEach相似,區別是在導航被確認以前,同時在全部組件內守衛和異步路由組件被解析以後,解析守衛就被調用
afterEach 在全部路由跳轉結束的時候調用這些鉤子不會接受 next 函數也不會改變導航自己
beforeEnter 可直接定義在路由配置上,和beforeEach方法參數、用法相同,調用位置在beforeEach 和 beforeResolve

大致的用法以下

//index.js
import createRouter from './config/router' //先導入咱們寫的路由信息

const router = createRouter()

router.beforeEach((to, from, next) >= { //to -> 跳轉的路由 from -> 當前的路由即跳轉的起始點,next爲這次跳轉的函數,調用他才能執行跳轉
    if(若是沒有登陸){
        next('/login')  //跳轉到登陸頁面
    }else if(沒有註冊) {
        next({path:'/register',replace:true});  //咱們也能夠傳遞一個對象,replace設置爲true就不會放在history的棧堆內
	}
})

router.beforeResolve((to, from, next) >= { 
    //do something
    next();
})

router.beforeEach((to, from) >= { 
    //do something
    next();
})
複製代碼

在路由上設置beforeEnter

//router.js
export default [
  {
    path: '/app',
    component: Todo,
    name: 'app', // 給當前的路由設置一個姓名,能夠用來跳轉,與路徑和組件名無強制聯繫
    meta: {
      title: 'this is app', // 與html的meta一樣的效果
      description: 'author Reaper Lee'
    },
      beforeEnter (to,from,next) { //只有在進入路由以前調用
          //dosomething
      }
  }
]
複製代碼
組件內路由守衛
函數名 做用
beforeRouteEnter 在渲染該組件的對應路由前調用,用法與參數和beforeEach相似, next須要被主動調用 ,此時實例並未被建立,不能使用this
beforeRouteUpdate 在當前路由改變,而且組件被複用時調用,此時實例已經建立,this能夠訪問實例,next須要被主動調用,不能傳回調
beforeRouteLeave 導航離開該組件的對應路由時調用。能夠訪問組件實例this,next須要被主動調用,不能傳回調
//comp.vue
export default {
    beforeRouteEnter (to, from, next) {
        //在這裏咱們由於沒有實例,因此不能用this,但咱們要用獲取的參數,就在next裏使用回調函數
        next( vm => {
            //在這裏能夠拿到參數
        })
    },
    beforeRouteUpdate (to,from, next){
      	next()  
    },
    beforeRouteLeave (to, from, next){ //咱們能夠經過下面的代碼來實現退出時的提示確認
        if(flobal.confirm('are you sure to leave?')){ 
            next()
        }
    }
    data() {
        return {
            
        }
    }
}
複製代碼

異步組件

咱們路由若是有很是多,一次性經過webpack把所有打包進去會致使js文件變得異常的大,而且初次加載的時間會變得很是長,顯然是不可取的。咱們可讓對應不一樣的路由只加載那一部分的組件的代碼。

使用這部分功能咱們須要安裝一個babel的插件

npm i babel-plugin-syntax-dynamic-import -D

以後在 .babelrc文件中咱們寫入

"plugins": [
    "syntax-dynamic-import"
  ]
複製代碼
//routes.js
//注意咱們不在開頭import組件

export default [
  {
    path: '/app',
    component:() => { import('組件的路徑')},  //注意要用一個函數
  }
]
複製代碼

VueX

VueX 是基於Vue框架的一個狀態管理工具

官網的介紹是:

Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。

加入VueX

npm install vuex -S

以後我麼你在項目的文件夾裏建一個新的文件夾爲stroe,並在內部建立stroe.js,他將做爲整個數據存儲的入口

//store.js
import Vuex from 'vuex'
import Vue from 'vue'

Vue.use(Vuex)

export default () => {
	return	new Vuex.store({
            state:{  //儲存的對象
                count: 0
            },
            mutations:{  //對state進行操做的方法
                updateCount(state,num){ //第一個參數都爲state,第二個參數爲你能夠傳的參數
                    state.count = num;
                }
            }
    })
}


複製代碼

咱們須要在index.js引入Vuex

//index.js
import Vuex from 'vuex'
import createStore from './store/store'

const store = createStore()

new Vue({
  router,
  store,
  render: (h) => h(App)
}).$mount(root)
複製代碼

到這裏以後咱們就已經把Vuex引入了

使用Vuex

//app.vue
<script>
    export default {
        components:{
        },
        mounted () {
            this.$router //咱們就能夠經過this.$store拿到所需的數據
            this.$store.commit('updateCount',參數) //咱們使用store的mutaitions時須要使用 commit方法,第一個參數
        }
    }
</script>
複製代碼

state

咱們能夠把state當作vue組件的data數據來使用

//state.js
export default {
    
}
複製代碼

咱們也要在store裏引入

//store.js
import defaultState from './state/state'

export default () => {
    return new Vuex.Store({
        state: defaultState,
        mutations: {
            updateCount(state,num){
                state.count = num;
            }
        }
    })
}
複製代碼

咱們也能夠把mutations也單獨寫個文件

//mutations.js
export default {
    updateCount (state, num){
        state.count = num;
    }
}
//store.js
import Vuex from 'vuex'

import defaultState from './state/state'
import mutations from './mutations/mutations'

export default () => {
    return new Vuex.Store({
        state: defaultState,
        mutations: mutations
    })
}

複製代碼

getters

咱們能夠把一些要直接在頁面用的數據放在getters,而後能夠直接方便使用

好比咱們在state.js裏寫入了咱們的名字信息

// state.js
export default {
    count: 0,
    firstName: 'Reaper',
    lastName: 'Lee'
}
複製代碼

咱們在getters裏寫入獲取全名的方法

//getters.js
export default {
    fullName (state) {
        return `${state.firstName} ${state.lastName}`
    }
}
複製代碼

而後咱們能夠經過Vuex提供的方法快速使用getters

//app.vue
<template>
	<p>
        {{fullName}}
    </p>
</template>


<script>
    export default {
        computed: {
            fullName () {
                return this.$store.getters.fullName
            }
        }
    }
</script>
複製代碼

mutations

咱們通常把修改state值的一些方法放在mutation中,而後在組件中經過調用修改state

注意,mutation 只能傳遞兩個參數,第一個是state對象,第二個是傳參的對象,單個參數能夠單獨放入,若是要傳遞多個參數,則要放在一個對象中

其實咱們在組件中能夠直接使用this.$store.state來進行修改,但這樣不夠規範,若是想防止這種狀況就在實例化時將strict屬性設置爲true

export default () => {
  return new Vuex.Store({
    strict:true
  })
}

複製代碼

actions

mutations只能同步操做,不能寫入異步的代碼,若是要執行異步操做,必需要寫入actions中

例如咱們要根據傳入的參數延時修改數據

//actions.js
export default {
    updateCountAsync (store, data) {
        setTimeout(() => {
            store.commit('updateCount',data.num) //觸發mutations的修改事件
        }, data.time)
    }
}
複製代碼

咱們在vue文件中觸發actions的方法與mutations有所不一樣,觸發mutation使用commit,觸發action使用dispatch

//app.vue
export default {
	...
    mounted() {
    	this.$store.dispatch('updateCountAsync',{ num:5,time:2000})
	}
}
複製代碼

模塊

咱們有時調用store要存在多種場景,須要劃分做用域,這時咱們就要使用到Vuex的模塊

//store.js
export default () => {
  return new Vuex.Store({
    modules: {
      a: {
         namespaced: true, //使用這個在不一樣的模塊中可使用相同命名的mutations
        state: {
          text :1
        },
          mutations: {
              updateText(state,text){
                  state.text = text;
              }
          },
          getters: {
          textPlus(state,getters,rootState){ //第二個參數是getter方法,第三個參數是全局state
          return state.text + 1
      		}
      	  },
      actions:{
          add({state,commit,rootState}){
              commit('updateText',rootState.count,{root:true}) //使用{root:true} 就可讓rootState爲全局
          }
      }
      },
      b: {
        text: 2
      }
    }
  })
}

複製代碼

在vue文件調用時

//app.vue
computed: {
    textA() {
        return this.$store.state.a.text //調用a模塊的text值
    },
    textB() {
        return this.$store.state.b.text //調用b模塊的text值
    }
}
複製代碼

Vuex熱更替

咱們在使用vuex時會發現,每當咱們修改vuex內的內容再保存時,vue不會熱更替顯示內容,而是會刷新一下,WTF,這麼好用的功能難道Vuex用不了:horse:?

固然不是,咱們只須要在store.js加入部分代碼便可

//store.js

import defaultState from './state/state'
import mutations from './mutations/mutations'
import getters from './getters/getters'
import actions from './actions/actions'

export default () => {
    const store = new Vuex.Store({
     	state: defaultState,
    	mutations: mutations,
    	getters: getters,
        actions: actions,
    })
        
        if (module.hot) {
        module.hot.accept([
        	'./state/state',
            './mutations/mutations',
            './actions/actions',
            './getters/getters'
        ],() => {
            const newState = require('./state/state').default,
            const newMutations = require('./mutations/mutations').default
            const newGetters = require('./getters/getters').default
            const newActions = require('./actions/actions').default
            
            store.hotUpdate({
                state:newState,
                mutations:newMutations,
                actions:newActions,
                getters:newGetters
            })
        })
    }
    
    return store
}
複製代碼

一些更多的有關Vuex的API 能夠查看

服務端渲染

服務端渲染的優點:

  • 更好的 SEO,因爲搜索引擎爬蟲抓取工具能夠直接查看徹底渲染的頁面。
  • 更快的內容到達時間(time-to-content),特別是對於緩慢的網絡狀況或運行緩慢的設備。無需等待全部的 JavaScript 都完成下載並執行,才顯示服務器渲染的標記,因此你的用戶將會更快速地看到完整渲染的頁面。一般能夠產生更好的用戶體驗,而且對於那些「內容到達時間(time-to-content)與轉化率直接相關」的應用程序而言,服務器端渲染(SSR)相當重要。

但同時也要注意一些權衡之處:

  • 開發條件所限。瀏覽器特定的代碼,只能在某些生命週期鉤子函數(lifecycle hook)中使用;一些外部擴展庫(external library)可能須要特殊處理,才能在服務器渲染應用程序中運行。
  • 涉及構建設置和部署的更多要求。與能夠部署在任何靜態文件服務器上的徹底靜態單頁面應用程序(SPA)不一樣,服務器渲染應用程序,須要處於 Node.js server 運行環境。
  • 更多的服務器端負載。在 Node.js 中渲染完整的應用程序,顯然會比僅僅提供靜態文件的 server 更加大量佔用 CPU 資源(CPU-intensive - CPU 密集),所以若是你預料在高流量環境(high traffic)下使用,請準備相應的服務器負載,並明智地採用緩存策略。
相關文章
相關標籤/搜索