Router

路由

<body>
<div id="box">
    <div>
        <router-link to="/home">Home</router-link>
        <!--router-link用來展示組件導航-->
        <!--to屬性用于指定鏈接-->
        <!--<router-link>標簽會默認被渲染成a標簽-->
        <!--當前被點擊的路由會自帶.router-link-active屬性-->
        <router-link to="/news">News</router-link>
    </div>
    <div>
        <!--路由出口,路由默認會被渲染在這里-->
        <router-view></router-view>
    </div>
</div>
</body>
<script>
    //創建路由組件
    var Home = {
            template: "<h4>我是主頁</h4>"
        },
        News = {
            template: "<h4>我是新聞</h4>"
        };
    //定義組件
    var routes=[
        {path:"/home",component:Home},
        {path:"/news",component:News},
        {path:"*",redirect:"/home"}
    ]
    //創建路由實例,配置路由實例
    var router=new VueRouter({
        routes:routes,
        linkActiveClass:"color"
    })
    //創建并將路由掛載到根實例
    new Vue({
        el:"#box",
        router:router
    })
</script>
動態路由匹配

我們經常需要把某種模式匹配到的所有路由,全部映射到同一個組件,例如我們有一個user組件用來展示用戶信息,那么對于不同ID的用戶,我們都需要使用這個組件來渲染,那么我們就可以在vue-router的路由路勁中使用動態路徑參數來達到這個效果

body>
<div id="box">
    <div>
        <router-link to="/home/1">Home</router-link>
        <router-link to="/home/2">News</router-link>
    </div>
    <div>
        <router-view></router-view>
    </div>
</div>
<template id="home">
    <div>
        <h4>this's homr</h4>
    </div>
</template>
<template id="news">
    <div>
        <h4>this's news</h4>
    </div>
</template>
<script>
    var Home = {
            template: "#home"
        },
        News = {
            template: "#news"
        };
    var routes=[
        {path:"/home/:id",component:Home},
        {path:"/news",component:News}
    ];
   //在routes中路徑參數使用:標記,那么在匹配路由時,所有 /home/參數  格式的路徑都會被匹配到Home組件,當然也可以同時使用一個或多個 例如 /home/:id/name/:id  路徑參數使用:標記那么表示這個參數可以是任意值,:id的作用只是一個占位符,也可以使用正則來匹配,如:/:id(\\d+)
    var router=new VueRouter({
        routes:routes
    });
    new Vue({
        el:"#box",
        router:router
    })
    
//在路由中設置多段路徑參數,對應的值都會設置到$route.params中,例如:
//   /user/:username匹配到路徑/user/tom,那么我們可以通過$router.params獲取到{username:"tom"}
</script>
</body>

當我們使用路由參數時,例如從/user/foo跳轉到/user/bar時,原來的組件會被復用,這樣更加高效,但是同時也意味著組件的生命周期函數不是再被調用,如果想要對路由參數的變化做出響應的話,可以所使用watch監測$route對象

<script>
var User = {
            template: "#user",
            watch:{
                '$route'(to,from){
                    console.log(to);
                    console.log(from);
                    //to表示從哪個路由開始跳轉
                    //from表示跳轉到哪個路由
                    //在跳轉時會觸發$route函數
                }
            }
        }
</script>
路由嵌套

實例一

<body>
<div id="box">
    <div>
        <router-link to="/home">Home</router-link>
        <router-link to="/news">News</router-link>
    </div>
    <div>
        <router-view></router-view>
    </div>
</div>
<template id="home">
    <div>
        <h4>this's home</h4>
        <ul>
            <li>
                <router-link to="/home/tom">Tom</router-link>
                <router-link to="/home/aix">Aix</router-link>
            </li>
            <li>
                <router-view></router-view>
            </li>
        </ul>
    </div>
</template>
<template id="news">
    <div>
        <h4>this's news</h4>
    </div>
</template>

<script>
    var Home = {
            template:"#home"
        },
        News = {
            template: "#news"
        },
        Tom={
            template:`
                <p>my name's tom</p>
            `
        },
        Aix={
            template:`
                <p>my name's aix</p>
            `
        };
    var routes=[
        {
            path:"/home",
            component:Home,
            children:[
                {
                    path:"tom",
                    component:Tom
                },
                {
                  path:"aix",
                    component:Aix
                }
            ]
        },
        {path:"/news",component:News}
    ]

    var router=new VueRouter({
        routes
    })

    new Vue({
        router
    }).$mount("#box")
</script>
</body>

實例二

<body>
<div id="box">
    <div>
        <h5>
            <router-link to="/user/foo">A</router-link>
            <router-link to="/user/foo/bar">B</router-link>
            <router-link to="/user/foo/cat">C</router-link>
        </h5>
        <router-view></router-view>
    </div>
</div>
<script>
    const User = {
        template: `
        <div>
            <p>{{$route.params.id}}</p>
            <router-view></router-view>
        </div>
        `
    }
    const userHome = {
        template: `
        <div>Home</div>
    `
    }
    const bar = {
        template: `
        <div>A</div>
        `
    }
    const cat = {
        template: `
            <div>
                 <div>{{$route.matched}}</div>
                 <div>B</div>
            </div>
       `
    }
    const router = new VueRouter({
        routes: [
            {
                path: "/user/:id",
                component: User,
                children: [
                    {path: "", component: userHome},
                    {path: "bar", component: bar},
                    {path: "cat", component: cat}
                ]
            }
        ]

    })

    new Vue({
        router
    }).$mount("#box")
</script>
</body>
編程式導航

在vue中我們除了使用<router-link>創建a標簽來定義導航鏈接,還可以杰作router的實例方法,通過編寫代碼來實現,我們使用router-link標簽時,實際在內部會調用router.push方法,所以說點擊<router-link :to="/home">等同于調用router.push("/home")

<body>
<div id="box">
    <div>
        <li @click="home">Home</li>
        <li @click="news">News</li>
    </div>
    <div>
        <router-view></router-view>
    </div>
</div>

<script>
    const Home = {
        template: `
                <div>
                    <h3>this's Home</h3>
                 </div>
            `
    };
    const News = {
        template: `
                <div>
                    <h3>this's News</h3>
                </div>
            `
    };

    const router = new VueRouter({
        routes: [
            {path: "/home", component: Home},
            {path: "/news", component: News}
        ]
    })

    new Vue({
        router,
        methods: {
            home() {
                router.push("/home")
            },
            news() {
                router.push("/news")
            }
        }
    }).$mount("#box")
</script>
</body>
  • router.push()

    該方法回想histiry棧添加一個新的記錄,所以當用戶點擊瀏覽器后退按鈕時,會回到之前的URL

  • router.repalce()

    該方法和router.push相似,唯一不同在于,它不會向history添加新紀錄,而是替換掉當前的history記錄,所以用戶不能點擊瀏覽器后退按鈕,該方法相當于<router-link :to="..." replace>

  • router.go(n)

    該方法的參數是一個整數,意思實在history記錄中向前或者后退多掃不,類似window.history.go(n),如果瀏覽器history記錄本身小于n,那么會失敗,并且不會返回失敗信息

push以及replate的參數可以是一個字符串路徑,或則一個描述的對象:

//字符串
router.push("/home")
//對象
router.push({psth:"/home"})
//命名的路由
router.push({name:"user",params:{userId:123}})
//帶查詢參數,變成/register?plan=private
router.push({path:'register',query:{plan:'private'}})
命名路由

有時候,通過一個名稱來表示一個路由顯的更方便一些,特別是在鏈接一個路由或執行一些跳轉的時候,我們可以在創建Router實例的時候,在routers配置中給某個路由設置名稱

<body>
<div id="box">
    <div>
        <router-link :to="{name:'home',params:{homeId:123}}">Hmoe</router-link>
        <!--params表示傳入的動態路由homeId的參數123,該參數會傳入到路由的url地址中-->
        <router-link :to="{name:'news'}">ews</router-link>
    </div>
    <div>
        <router-view></router-view>
    </div>
</div>
<script>
    const Home = {
            template: `
            <div>
                <h5>this's Home</h5>
            </div>
        `
        },
        News = {
            template: `
            <div>
                <h5>this's News</h5>
            </div>
        `
        };

    var router = new VueRouter({
        routes: [
            {
                path: "/home/:homeId",
                name: "home",
              //在router中為路由設置名稱后,在router-link中:to 直接接受路由名稱即可
                component: Home
            },
            {
                path:"/news",
                name:"news",
                component:News
            }
        ]
    })

    new Vue({
      router
    }).$mount("#box")
</script>
</body>
命名視圖

如果我們想要同時在統計展示多個視圖,而不是嵌套展示,例如創建一個布局,有導航欄和主內容兩個視圖,我們可以使用命名視圖,利用命名視圖我們可以在界面中擁有多個單獨命名的視圖,而不是只有一個單獨的出口,如果router-view標簽沒有設置名字,那么默認為default

<style>
    .nav {
        width: 100%;
        height: 40px;
        color: forestgreen;
        }
    .main {
        width: 100%;
        height: 100px;
        color: forestgreen;
        border: 1px solid #000;
        }
</style>
</head>
<body>
<div id="box">
    <div>
        <router-link to="/nav">Nav</router-link>
        <router-link to="/main">Main</router-link>
    </div>
    <div>
        <router-view name="navView" class="nav"></router-view>
        <router-view name="mainView" class="main"></router-view>
    </div>
</div>
<script>
    const Nav = {
            template: `
                <div>
                    <h5>this's nav</h5>
                </div>
            `
        },
        Main = {
            template: `
                <div>
                    <h5>this's main</h5>
                </div>
            `
        };
    const router=new VueRouter({
        routes:[
            {
                path:"/nav",
                components:{
                    "navView":Nav
                }
            },
            {
                path:"/main",
                components:{
                    "mainView":Main
                }
            }
        ]
    })
    new Vue({
        router
    }).$mount("#box")
</script>
</body>
重定向和別名

重定向是指將當前路由的指向重新定位到其它路由上,使用redirect來實現

const router=new VueRouter({
  routes:[
    {path:"/a",
    redirect:"/b"}
    //此時的/a的路由點擊會被重定向到/b路由上
  ]
})
//一般我們使用重定向來進行初始化頁面的展示
{ path:"*",redirect:"/b"}
//重定向也可以傳入一個路由名稱
{path:"/a",redirect:"{name:'b'}"}

別名和重定向的大致作用是類似的,但是區別在與

使用重定向時當用戶訪問/a時,匹配路由為/b,URL地址中也會被替換為/b

使用別名時當用戶訪問/a時,匹配的路由為/b,但是URL地址中不會被替換,依然是/a,就像用戶訪問/a一樣

const router=new VueRouter({
  routes:[
    path:"/a",
    alias:"/b"
  ]
})
導航鉤子

vue-router提供了導航鉤子主要用來攔截導航,或則完成跳轉或取消,vue-router的導航鉤子會在路由發生改變時執行,有多種方式可以在路由發生改變時執行鉤子:全局的,單個路由獨享的,或者是組件級的

  • 全局鉤子

    使用router.beforeEach注冊一個全局的before鉤子

    const router=new VueRouter({...})
    router.beforeEach((to,form,next)=>{
      .....
    })
    

    當一個導航觸發時,全局的before鉤子會按照創建順序調用,鉤子是異步解析執行,此時導航在所有鉤子執行完之前一直處于等待中

    每個鉤子接收三個參數:

    • to 表示將要進入的目標路由對象
    • form 表示當前導航將要離開的路由
    • next 如果了解node的話可以理解為node中的next()中間件,next()表示進行下一個導航,next(false)表示中斷當前的導航,也就是不再執行下一個跳轉導航的操作,next("/")或者next({path:"/",...})表示跳轉到我們指定的導航

    一定要注意,一定要調用next()方法,否則之后的操作都不會被執行

    同樣可以注冊一個全局的after鉤子,不過它沒有next方法,不能改變導航

    router.afterEach(function (to,form) {
      console.log(to);
      console.log(form);
      alert("離開"+form.fullPath+",進入"+to.fullPath);
    })
    
  • 單個路由的鉤子

    通過為單個路由設置beforeEnter方法,該方法接收的參數和beforeEach是一樣的

     const router = new VueRouter({
            routes: [
                {
                    path: "/home",
                    component: Home,
                    children: [
                        {
                            path: "info",
                            component: Info,
                            meta: { requiresAuth: true,age:18 },
                            beforeEnter:function (to,form,next){
                                console.log(to);
                                console.log(form);
                                next();
                            }
                        },
                        {path: "set", component: Set}
                    ]
                },
                {path: "/news", component: News}
            ]
        })
    

    同樣需要注意一定調用next(),否則不會進入到該導航

  • 組件內的鉤子

    也可以在路由組件內直接定義導航鉤子

    • beforeRouteEnter
    • beforeRouteUpdata(2.2)
    • beforeRouteLeave
 News = {
            template: `
            <div>
                <h4>this's News</h4>
            </div>
        `,
            data() {
                return {
                    msg: 1
                }
            },
            beforeRouteEnter: function (to, form, next) {
                //注意在這里不能調用實例的this,因為該方法是在組件被創建之前調用的,所以此時實例是不存在的
                next(vm => {
                    console.log(vm.$data.msg);
                });
                //但是可以通過為next傳入一個回調,把組件實例作為回調參數的方法來訪問組件的實例
            },
            beforeRouteUpdate:function (to,form,next) {
                //該方法只有在當前組件被復用時會調用
                //例如,對于一個帶有動態參數的路徑,foo/:id,在foo/1和foo/2之間跳轉的時候
                //由于會渲染同樣的foo組件,因此逐漸實例會被復用,而這個鉤子會被調用,類似動態組件中的watch
                //可以訪問實例的this
            },
            beforeRouteLeave:function(to,form,next) {
                //在導航離開組件的對應路由時調用
                //可以訪問組件實例this
                //這個鉤子通常用于在用戶還未保存修改錢突然離開,可以通過next(false)來取消導航
            }
        }
路由元信息

定義路由的時候可以定義路由的meta字段,在meta中定義的字段,可以在路由記錄中獲取,可以用來對對每個路由進行配置,在vue中,我們稱呼router配置中的每個路由對象為路由記錄,路由記錄可以是嵌套的,因此,當一個路由匹配成功后,它可能匹配多個路由記錄,例如我們匹配到/foo/bar這個URL將會匹配副路由記錄以及自路由記錄,一個路由匹配到的所有路由記錄會暴露為$route.matched數組,因此,我們可以遍歷$$router.matched來檢查路由記錄中的meta字段

  const router = new VueRouter({
    routes: [
            {
               path: "/home",
                  component: Home,
                  children: [
                      {
                          path: "info",
                          component: Info,
                          meta: {
                              requiresAuth: true,
                              title:"主頁"
                          }
                      },
                      {path: "set", component: Set}
                  ]
              },
              {path: "/news", component: News}
          ]
    })
  ...........

  router.beforeEach((to,form,next)=>{
    if(to.matched.some(record => record.meta.requiresAuth)){
        //if的判斷條件是用來判斷meta中設置的requiresAuth變量是否為true
        //可以用來判斷該頁面是否需要用戶登錄才能進入該頁面
        //如果我們設置一個路由的meta中requiresAuth變量為true,在全局路由鉤子函數執行的時候都會進入if判斷
        console.log(to.matched.some(record => record.meta.requiresAuth));//true
        //meta中設置的值也可以用來保存該路由中的信息,例如在meta中設置title屬性和值,在進入該頁面的時候獲取該title值設置到頁面中等操作
             document.getElementById("test").innerText=to.meta.title;
        if(用戶沒有登錄){
            next("/login"); //跳轉到登錄頁面
        }else {
            next()
        }
    }else{
        next()
          //如果該頁面不需要登錄操作,執行用戶操作
    }
  })

注意,在to和form中我們可以獲取到跳轉的路由的信息,下面是打印的to的信息:

{name: undefined, meta: {…}, path: "/home/info", hash: "", query: {…}, …}

滾動行為

使用前端路由,當我們切換到新路由時,想要頁面滾動到頂部,或者是保持原先的滾動位置,就像重新加載頁面那樣,vue-router提供了更好的方法來讓自定義路由切換頁面是如何滾動

注意,這個功能只在HTML5 history模式下可用

在創建一個router實例的時候,可以提供一個scrollBehavior方法,該方法會在用戶進行路由切換時觸發

const router=new VueRouter({
        routes:[
            {
                path:"/",
                component:Home
            }
        ],
        scrollBehavior(to,form,savedPosition){
        //scrollBehavior方法接收to,form路由對象,第三個參數savedPosition當且僅當在瀏覽器前進后退按鈕觸發時才可用
        //該方法會返回滾動位置的對象信息,如果返回一個布爾假肢,或者是一個空的對象,那么不會發生滾動
        //我們可以在該方法中設置返回值來指定頁面的滾動位置,例如:
         return {x:0,y:0}
        //表示在用戶切換路由時讓是所有頁面都返回到頂部位置
        //如果返回savedPosition,那么在點擊后退按鈕時就會表現的像原生瀏覽器一樣,返回的頁面會滾動過到之前按鈕點擊跳轉的位置,大概寫法如下:
         if(savedPosition){
            return savedPosition
         }else{
           return {x:0,y:0}
         }
         //如果想要模擬滾動到錨點的行為:
         if(to.hash){
           return {
             selector:to.hash
           }
         }
     }
})
router-link屬性
  • to

    表示目標路由的鏈接,當被點擊時,內部會立刻把to的值傳到router.push(),通過to傳遞的鏈接會被保存在history記錄中,所以可以使用瀏覽器回退

  • replace

    如果設置replace屬性的話,當路由被點擊時,會調用router.replace(),本次操作不會留下history記錄

    <router-link to="/home" replace></router-link>
    
  • append

    在設置append屬性后,則表示正在當前相對路徑前添加路徑,例如我們是從/a導航到/b,那么在設置了append屬性后路由導航會跳轉到/a/b,而不是/b

    <router-link to="a" append>a</router-link>  //注意不要寫/a的形式
    
  • tag

    如果想要把router-link渲染成除a外的其它標簽,可以使用tag來指定渲染之后應該是哪種標簽,同樣他還是會監聽點擊,觸發導航

    <router-link to="/home" tag="li"></router-link>
    
  • exact

    表示是否激活全局,可以理解為如果一個導航的路徑是/home開頭的,并且我們設置了點擊樣式,在/home路徑的導航設置了exact的情況下所有以、home開頭的路徑的導航的樣式都會同時改變

    https://jsfiddle.net/8xrk1n9f/ 這是vue官方的一個簡單直觀的例子

  • 將激活時的css類名應用在外層元素

    有時候我們需要讓css類應用在外層元素,而不是a標簽本身,那么可以用router-link渲染外層元素,包裹著內層原生a標簽

    <router-link tag="li" to="/home">
      <a>Home</a>
    </router-link>
    

    這種情況下,a將作為真實的鏈接,它會獲得正確的href,而激活時的css類名則會設置到外層的li

  • events
    用來可以用來觸發導航的事件,默認是"click"

router-view屬性
  • name
    如果 <router-view>設置了名稱,則會渲染對應的路由配置中 components 下的相應組件
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內容