Vue-router的使用姿勢

chavesgu發表於2018-07-27

雖然有很多router的相關文章了,但是那又怎麼樣,我就是要寫。

歡迎來我的Vue技術群交流:Vue887516034

其實vuejs有一個叫做動態元件的東西,效果和路由有點相似,根據需求顯示不同的元件,但是在實際使用上,很小氣,就給人玩不爽,沒辦法像路由一樣程式設計式導航(push,replace),也沒有瀏覽器路徑的語義引導,動態元件更適合小規模的區域性tab,給大家秀一波用法

<template>
    <div>
        ul>li>tab1+tab2     @click=""  <!-- >>>此處改變下面data中的tab值就可以切換了 -->
        <!-- 此處相當於router-link效果,雖然沒有瀏覽器的url引導,但是可以自己寫麵包屑 -->
        <component :is="tab"></component>  <!-- 這裡就是router-view顯示區了 -->
    </div>
</template>

<script>
import tab1 from 'path/to/tab1.vue' //相比vue-router要引入很多檔案  麻煩
import tab2 from 'path/to/tab2.vue'
//其實vue-router也引入檔案,但是在.vue檔案裡面引入那麼多就很難看

export default {
    data(){
        tab:'tab1' //預設顯示tab1
    },
    components:{
        tab1,
        tab2   //es6語法   物件中,鍵值相同可以這樣寫
    }
}
</script>
複製程式碼

我們不提動態元件了,開始router了。常用的api,官網介紹的很詳細了。記得看官方教程,別忘了官方的api

路由的配置

不管是什麼路由的配置 還是vuex的配置等等,都有相應的規範,在普通js檔案,不按規範也不會怎麼樣,在ts檔案,就會報錯了。前提是有興趣玩ts。

//  router/index.js
// 此處省略一堆 import
const router = new Router({
    base:'/',
    mode:'history',//default-->hash
    routes:[],
    scrollBehavior:()=>{
        return {x:0,y:0}
    }
})
複製程式碼

其實配置很簡單,就這麼一點。

base

瀏覽器url的字首,預設為'/',如果設定為'/some/',則執行專案,瀏覽器url都是'/some/...',不會對靜態檔案的引用產生影響,一般寫網站都會有域名,都可以把域名指向某個伺服器目錄,所以預設'/'即可,如果是寫公司內部後臺管理,那麼不一定會用域名,可能就是某個ip下的某個目錄,比如打包後的檔案在111.22.33.44/admin,這個時候路由的配置匹配瀏覽器路徑的時候,會從這個/admin開始算,如果base還是預設的/,那麼路由配置的routespath就要全部加上/admin/字首,並且router-linkpush方法也要加上這個/admin,很麻煩,但是隻要設定base'/admin/',路由內部配置以及所有相關的方法都可以忽視伺服器ip下的目錄名。這種情況,同樣也要配置webpackpublicPath也為/admin/,這裡不細說了。

mode

這個太簡單了,一共三種模式,

hash:瀏覽器會有‘#’符號,參考錨點效果,缺點很醜,但是相容性棒棒

history:去除‘#’符號,讓url變好看,下面會講服務端配置。

abstract:非瀏覽器環境,會強制使用這個模式,例如weex

history模式服務端配置

我個人和公司都是用nginx,這裡就講nginx,配置這個的原因是當你進入某個路由之後,再次重新整理頁面時(或者是瀏覽器直接輸入某個路由路徑時),當重新整理頁面,瀏覽器就會重新dns解析,tcp協議,這個時候會根據瀏覽器的url去伺服器找對應資源,當然我們vue-router是為單頁面服務的,對應的url在服務端是肯定沒有靜態資源的,就會出現404,當配置了以下url重寫語句,注意是重寫,不是重定向,不改變url的情況重寫瀏覽器內容,重寫到index.html,因為這個index.html使我們專案的入口,index.html裡面會讀取當時打包好的app.js,就可以讀取到路由配置,以實現我們瀏覽器的url對應的路由頁面。

hash模式不需要配置,因為瀏覽器會忽略#和?後面的引數

打包檔案在根目錄時,

location / { 
  try_files $uri $uri/ /index.html;
}
複製程式碼

打包檔案在非根目錄時,

location /admin {
  try_files $uri $uri/ /admin/index.html;
}
複製程式碼

routes

核心路由配置,官網講的很詳細,我就講幾個注意點,所有自定義的配置,例如是否需要鑑權或者對應的icon等,需要規範化的話都寫在meta物件中, 不規範的話 ,就和path同級咯,隨意玩,玩壞了我不背鍋。

path是必須指定的,name需要唯一,不是必須。

routes的配置遵循順序匹配,當url成功匹配,就不會再往下匹配,所以像403,404的頁面應當寫在最後。

alias別名的使用,當需要在指定router-view顯示某個元件,並且希望瀏覽器url是自己想要的語義時使用

redirect重定向,引數可以是路徑,也可以是物件(重定向到某個name),注意重定向是改變內容+改變url

scrollBehavior

這個滾動行為,老實說,感覺很蹩腳,本人基本沒有使用過,他控制的是body的滾動, 很多需求都是區域性滾動。如果的確是需要控制body滾動,參考官方文件即可。

路由的使用

路由的配置一開始只有根目錄/,每寫一層children就要寫一層router-view,否則元件不顯示。每一個巢狀children的層級和router-view的層級都是一一對應的。

// router/index.js
const router = new Router({
    routes:[
        {
            path:'/',   //此時配置陣列的第一層級,即對應app.vue中的router-view
            component:Home,//   <<<----------------------------
            children:[//                                       |
                {   //                                         |
                    //此時第一層級出現children第二層級,------------
                    //那麼在這個第二層級所屬的第一層級 Home元件中,就要寫一層router-view,以此類推
                    path:'user', 
                    component:User,
                }
            ]
        }
    ]
})
複製程式碼

路由配置生成menu選單

menu其實就是路由的導航,就是router-link,有很多小夥伴會另外建一個叫做menu.js的檔案,然後模擬路由配置的結構去寫一個陣列,然後根據這個檔案遍歷生成dom,是不是有多此一舉的感覺,並且當使用第三方的menu的ui元件時,這種靜態檔案是沒有狀態 (當前訪問路由的對應menu高亮,重新整理頁面或者輸入路由的url進入頁面會丟失高亮) 的。

menu有很多種情況,

  1. 固定層級,比如固定2層,或者3層,一般後臺管理系統,固定層級較多,因為美觀,整潔。這種就比較方便了。template的dom結構也比較方便。
  2. “個性”的產品經理,“定製化”的menu選單,未知的層級,這裡就要用到render函式去寫dom。

固定層級

<template>
    <div class="menu">
        <div class="first-menu" v-for="item,index in menus" :key="item.name">
            <router-link :to="item.name">{{ item.meta.zhName }}</router-link>
            <template v-if="item.children.length">
                <div class="sub-menu" v-for="subItem.subIndex in item.children"
                        :key="subItem.name">
                    <img :src="subItem.meta.icon" />
                    <router-link :to="subItem.name">
                    {{subItem.meta.zhName}}
                    </router-link>
                </div>
            </template>
        </div>
    </div>
</template>
<script>
export default {
    computed:{
        menus(){
            return this.$router.options.routes
            //獲取路由配置
        }
    }
}
</script>
<style>
.router-link-active{
    /* 啟用樣式 */
}
</style>
複製程式碼

這裡我只寫了2層,並且沒有寫樣式,如果使用了像element-ui這樣的menu元件,他底層沒有渲染成router-link,那就要程式設計式導航了,click的時候,pushitem.name,並且當前路由的導航樣式需要根據$route.name(當前路由配置)來判斷

未知層級

因為不知道是幾層選單,所以在template的html標籤沒辦法自由的遍歷,所以需要js去操作路由配置的遞迴,因為render函式式js操作,所以需要用render函式渲染。

<script>
export default {
    computed:{
        menus(){
            return this.$router.options.routes
            //獲取路由配置
        }
    },
    // 使用render函式就不需要寫template標籤的dom了
    render(h){ 
        //這個 h 引數,原來的語義是createElement ,這裡使用 h 是方便操作,也是官方建議
        // ...... 這裡是操作 menus 的遞迴程式碼,再通過render函式迴圈出來
        return h('div','這是一個div')
        //這裡必須return 對應的語法
    }
}
</script>
複製程式碼

render函式的語法參見官方文件即可 render函式

這裡有個注意點,如果router做了許可權控制,那麼路由配置不能通過$router.options.routes獲取,因為addRoutes方法不改變原先的配置,需要在addRoutes的同時,把完整的路由配置儲存在vuex,再獲取。許可權控制不細講了,有很多相關文章,但是不建議copy,建議加入自己的理解,沒有絕對的方案。

路由的快取和過渡動畫

過渡動畫應該都用了,一般使用opacity過渡一下。

<template>
    <transition mode="out-in" name="fade">
        <!-- 這裡如果在行內直接用$route.meta去v-if判斷快取 dom結構會變複雜 -->
        <keep-alive :include="aliveRoutes">
            <router-view :key="$route.fullPath" />
            <!-- 此處通過路由的完整路徑加上key,當為動態路由時,觸發路由元件重新渲染 -->
        </keep-alive>
    </transition>
    <!-- 都是些官方用法 不細說了-->
</template>
<script>
export default {
    computed:{
        aliveRoutes(){
            // this.$router.options.routes  獲取路由配置
            //可以配置meta 是否快取 根據 meta 欄位  push到陣列裡
            return [/* ... */]
        }
    }
}
</script>
複製程式碼

路由的鉤子

官網講的超詳細的。觸發順序也講清楚了,官方的說法叫導航守衛

注意點:要搞清楚哪些是全域性鉤子,哪些是元件內的鉤子。並且所有的前置鉤子,需要呼叫next() 才會正常進入路由,在寫鉤子函式內部邏輯時,需要注意,不能形成死迴圈

例如

router.beforeEach((to,from,next)=>{
    if (from.name === 'login'){
        next({
            name:'login'  //死迴圈
        })
        //更多next回撥方法可以檢視官方文件
    }
})
複製程式碼

元件內鉤子使用情況,要看業務需求,比如動態路由↓↓↓。

動態路由

動態路由,使用場景是一個固定的路由檢視元件,配合一個動態的瀏覽器url,在檢視中顯示不同的資料,同時希望url中有當前詳情的語義,例如詳情頁,使用者資訊頁。

先看下路由如何配置動態,這裡用詳情頁舉例

// router/index.js
const router = new Router({
    routes:[
        {
            path:'/list',
            name:'list',
            component:List
        },
        {
            path:'/detail/:id',//此處id對應params.id
            name:'detail',
            component:Detail
        }
    ]
})
複製程式碼
<!-- List.vue -->
<template>
    <div>
        <ul>
            <li @click="goDetail(item.id)" v-for="item in someData" :key="item.id">
            </li>
        </ul>
    </div>
</template>

<script>
export default{
    methods:{
        goDetail(_id){
            this.$router.push({
                name:'detail',
                //此處注意只有通過name跳轉路由,params才會生效
                //query不受影響
                params:{
                    id:_id  //此處對應routes配置的/:id
                }
            })
        }
    }
}
</script>
複製程式碼
<!-- Detail.vue -->

<script>
export default {
    beforeRouteEnter (to, from, next) {
        //此處為路由元件內的鉤子,可以通過判斷 to.params.id 是否 undefined,
        //進行一些操作,因為即使 to.params.id 是 undefined,路由也能匹配成功
        //因為這些id可能是用來獲取資料的,不會在頁面顯示,不一定能察覺是 undefined
    }
}
</script>
複製程式碼

關於路由傳參

  1. params就如上面動態路由所講,只有通過路由配置的name跳轉,才會生效,即使沒有使用動態路由,也可以通過params傳參

這裡有注意點:

  • 如果使用動態路由,那麼在動態路由頁面重新整理路由,params引數依然存在,

  • 如果沒有使用動態路由,params引數只在跳轉路由時有效,重新整理頁面則會丟失params

  1. query引數,可以通過pathname跳轉都可以傳參,並且引數會和ajaxget請求一樣,附加到瀏覽器的url上,重新整理頁面依然保留

路由的懶載入

路由元件打包單獨的js,當訪問路由時,載入對應js檔案,加快首頁載入時間,會增加專案的總體積。

  1. npmyarn安裝babel-plugin-syntax-dynamic-import
  2. .babelrcbabel.config.js配置
module.exports = {
    plugins:["syntax-dynamic-import"]
}
複製程式碼
  1. 路由檔案使用
// router/index.js
const router = new Router({
    routes:[
        {
            path:'/list',
            name:'list',
            component:()=>import(/* webpackChunkName:"SOME_NAME" */'path/to/List.vue')
            //此處 import 是方法  和 es6 的 import 不一樣
            //特殊註釋語法 相同chunkName 打包到一個js中  可省略
        }
    ]
})
複製程式碼

路由的命名檢視

我從來沒用到過命名檢視,不給大家誤導了,我能解釋的就是命名檢視的作用是一個瀏覽器url,匹配多個router-view。有需求的移步官方文件。

部分api

  1. .vue檔案中this.$router是指掛載的路由例項,可以使用push等方法。
  2. .vue檔案中this.$route當前路由資訊物件,包括pathquery等,只讀屬性。
  3. router.approuter所掛載的vue例項,可以通過router.app.$options.store訪問vuex,前提是main.js中,要先引入vuex,後引入router,否則報錯。
  4. router.push()常用路由跳轉方法,引數為{path?:string,name?:string,params?:object,query?:object},需要注意的是,push為方法名,與陣列沒有聯絡。
  5. router.replace()替換當前路由,引數和push一致,區別是替換當前路由,即點選瀏覽器的返回,不會回到之前被替換的路由。
  6. router.go()router.back(),引數為整數,前進或後退幾步。
  7. router.addRoutes()引數是需要符合routes配置的資料,動態新增路由配置到原有配置。

結束

有疑問或者講錯的可以提出

tips:懂得分享才能走的更遠。

歡迎來我的Vue技術群交流:Vue887516034

如果覺得對你有用,就打賞一下吧。

Vue-router的使用姿勢 Vue-router的使用姿勢

相關文章