vue.js備忘記錄(五) vue-router

如果我們采用SPA(單網(wǎng)頁應(yīng)用)的設(shè)計方式,服務(wù)器會把前端文件一次性發(fā)過來,前端通過監(jiān)聽url的改變,選擇展示那些內(nèi)容,也就是前端路由

一. 如何改變url但是頁面不刷新?

方式一: 改變哈希值hash

比如,我們隨便找一個網(wǎng)頁

我們在瀏覽器控制臺輸入

發(fā)現(xiàn)網(wǎng)站的url有了些改變

查看network卻沒有任何請求

方式二 history模式的方法

(1). history.pushState()壓棧式

比如,我們隨便找一個網(wǎng)頁

我們在瀏覽器控制臺輸入

history.pushState({},'','home')

發(fā)現(xiàn)網(wǎng)站的url有了些改變

image

查看network卻沒有任何請求

image

這種壓棧式方法,可以使用瀏覽器返回上一頁按鈕彈棧,實(shí)際上是在調(diào)用

history.back()

也可以使用history.go() 操作棧

history.forward() 等價于  history.go(1) 
history.back() 等價于  history.go(-1)

(2): history.replaceState()非壓棧式

history.replaceState({},'','home')

二. 認(rèn)識vue-router

1.安裝 vue-router

cnpm install vue-router --save

我們也可以在用CLi項目創(chuàng)建時就選擇好 vue-router 這樣項目創(chuàng)建時會送我們一個hello world的例子,我們可以先體驗(yàn)一下

2.創(chuàng)建文件夾router,創(chuàng)建index.js

用來存放我們的路由配置

3.路由創(chuàng)建過程

首先,我們在index.js創(chuàng)建一個vuerouter并暴露

//1.導(dǎo)入VueRouter
import VueRouter from 'vue-router'
//2.導(dǎo)入Vue   (因?yàn)楹竺嬉肰ue.use())
import Vue from 'vue'


//3.通過Vue.use安裝一下插件
Vue.use(VueRouter)

//4.創(chuàng)建路由對象
routes=[]

const router = new VueRouter({
  routes
})

//5.暴露路由對象
export default router

在main.js中,我們掛載這個vuerouter

import Vue from 'vue'
import App from './App.vue'
import router from './router'     //6.導(dǎo)入暴露的vuerouter (/index.js是默認(rèn),路徑中省略了)

Vue.config.productionTip = false

new Vue({
  router,      //7. 將導(dǎo)入的router傳給自己的router屬性
  render: h => h(App),
}).$mount('#app')

4.配置映射關(guān)系

上面的模板中,routes=[], 我們沒有配置映射關(guān)系, 現(xiàn)在我們來配置一下:

  • 第一步,導(dǎo)入頁面組件

  • 第二步,創(chuàng)建映射關(guān)系

  • 第三步,在app.vue模板中(上級組件),添加router-link標(biāo)簽,這是一個觸發(fā)url改變的入口

  • 第四步,在app.vue模板中(上級組件),添加router-view占位符標(biāo)簽,確定請求過來的內(nèi)容的占位

在router/index.js中

import VueRouter from 'vue-router'
import Vue from 'vue'
import Home from '../components/Home'  //1. 導(dǎo)入第一個組件Home
import About from '../components/About' //1. 導(dǎo)入第二個組件About

Vue.use(VueRouter)
const routes = [
  {
    path: '/',       //2.添加映射關(guān)系
    component: Home
  },
  {
    path: '/about',  //2.添加映射關(guān)系
    component: About
  }
]

const router = new VueRouter({
  routes
})

export default router

在App.js中

<template>
  <div id="app">
    <router-link to="/home">首頁</router-link>   
    <!-- 3.使用路由 通過router-link標(biāo)簽,配置to屬性提供鏈接目標(biāo),點(diǎn)擊此標(biāo)簽會觸發(fā)對應(yīng)的url請求-->
    <router-link to="/about">關(guān)于</router-link>
    <!-- 3.使用路由 通過router-link標(biāo)簽,配置to屬性提供鏈接目標(biāo),點(diǎn)擊此標(biāo)簽會觸發(fā)對應(yīng)的url請求-->
    <router-view></router-view>
    <!-- 4.使用路由 通過router-view占位符標(biāo)簽,確定請求過來的內(nèi)容的占位-->
  </div>
</template>

<script>
export default {
  name: 'App',
}
</script>

<style scoped>
</style>

路由重定向:

const routes = [
  {
    path:'',
    redirect:'home'
  },
]

5.將默認(rèn)的哈希方式改為history模式

vue默認(rèn)是使用hash方式的,

我們可以給它改成history模式,

這需要,我們在router/index.js中創(chuàng)建VueRouter時傳入另一個參數(shù)

const router = new VueRouter({
  routes,
  mode:'history'
})

此外我們在cli初始化項目時,也可以默認(rèn)history模式

6.router-link 屬性

  • to屬性 :指向的url地址

  • tag屬性: 默認(rèn)是a標(biāo)簽,如果tag='button',則渲染成標(biāo)簽.此外還可以是 <li>等

  • replace屬性: 采用非壓棧式跳轉(zhuǎn),不可返回

同時,我們注意到,當(dāng)某個標(biāo)簽被點(diǎn)擊時,他的class會自動添加兩個類:router-link-exact-active和router-link-active

image

有了這兩個class,我們可以方便的寫樣式了

image

7. 不用router-link,通過代碼修改路徑 $router.push

上面的我們都是使用的 <router-link>來觸發(fā)的url改變 有沒有辦法用普通的表單元素觸發(fā)呢?

有的.比如一個button 我們綁定了他的單擊事件 btnClick,則我們可以在方法里寫:

每個組件都有一個全局對象叫$router,這個

btnClick(){
    this.$router.push('/home')
}

上面是壓棧式,當(dāng)然也有非壓棧式

btnClick(){
    this.$router.replace('/home')
}

三. 動態(tài)路由 /:參數(shù)

很多時候我們的url可能是不固定的,訪問的頁面的具體信息也會隨著url改變,這就稱之為動態(tài)路由. 例如: 我們訪問張三的資料 /user/zhangsan 李四的是 /user/lisi

注冊動態(tài)路由的方法是 /:參數(shù)

我們注冊映射關(guān)系時,這樣注冊

  {
    path:"/user/:userId",
    component:User
  }

我們觸發(fā)url時這樣觸發(fā)

//在<router-link>上動態(tài)綁定
<router-link :to="'/user/'+userId">用戶</router-link> 

//或者通過普通標(biāo)簽的事件:
    btnClick(){
      this.$router.push('/user/'+this.userId)
    }

那么url跳轉(zhuǎn)后如何在先頁面中拿到跳轉(zhuǎn)的參數(shù)呢? 用$route

$route   :當(dāng)前活躍路由 每個組件都有一個全局對象$route
一定要和$router區(qū)分開!!!!!

每個組件都有一個route全局對象 (不是router,少了一個r)

image

我們看到這個 對象里有一個屬性params ,里面有一個鍵值對 就是我們想要的,這時我們制作一個計算屬性放在我們想顯示的位置就好了

  computed: {
    userId(){
      return this.$route.params.userId 
    }
  },

四. 路由的懶加載

當(dāng)我們打包時,我們的bundle.js會變得特別大,太大的bundle會使得加載變慢,從而出現(xiàn)瀏覽器空白.但其實(shí)即使是單頁程序,也無需浪費(fèi)這段時間,同時給用戶不好的體驗(yàn).我們完全可以使用懶加載,將剛開始用不到的代代碼先不加載,等用戶觸發(fā)了相關(guān)路由時再加載

懶加載說白了就是不同的路由打包到不同的js里去

懶加載如何實(shí)現(xiàn)??

我們不要在一開始就import 而是在用到的地方,用箭頭函數(shù)直接匿名import

    path: '/about',  //2.添加映射關(guān)系
    component: ()=>import('../components/About')
  },

這樣,我們可以讓首頁之外的路由選擇懶加載,都懶加載也可以

五. 路由的嵌套

為什么要路由嵌套?看下圖:

我們想在home頁面請求路由,把路徑改為/home/news, 但是頁面還是在home頁,只不過綠框里的內(nèi)容改為了news組件的內(nèi)容

如何實(shí)現(xiàn)路由嵌套?

1.映射路由

因?yàn)檫€是在home頁面,所以不能直接寫路由映射,而是將路由映射嵌套在home的映射中

具體做法是,將子映射寫在父映射的children屬性里

 {
    path: '/home',       //這是home的映射
    component: Home,
    children:[           //它里面可以定義一個children,里面放子映射
      {
        path: '',       //添加默認(rèn)子映射
        redirect:'news'
      },
      {
        path: 'news',                   //添加子映射關(guān)系 路徑只寫名字 news
        component: ()=>import('../components/HomeNews')
      },
      {
        path: 'msgs',                   //添加子映射關(guān)系
        component: ()=>import('../components/HomeMsg')
      },
    ]
  },

接下來我們在home.vue中確定顯示位置 路徑照實(shí)寫

<template>
  <div>
    <h2>我是首頁</h2>
    <p>我是首頁內(nèi)容</p>
    <router-link to="/home/news">看看新聞</router-link>
    <router-link to="/home/msgs">看看消息</router-link>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: "Home"
};
</script>

<style scoped>
</style>

六. 傳遞參數(shù)的路由

傳遞參數(shù)的兩種方式

  • 配置動態(tài)路由 /router/:參數(shù)

  • query類型的傳遞 請求路徑還是/router 但是同時會傳一個query,如: /router?id=123

如果只需要傳遞一個符號,則選擇第一種,如果信息較多,傳遞第二種

第一種我們之前已經(jīng)接觸了,現(xiàn)在看

1. 如何用query傳遞參數(shù)

只需要在<router-link> 的to屬性里綁定一個對象,對象有如下屬性:

<router-link :to="{
  path:'/profile',     <--path屬性還是路由鏈接-->
  query:{              <--query屬性里面?zhèn)魅胍粋€對象,對象里都是鍵值對--> 
      id:'lili',
      age:20,
      gender:'girl'
    }}">Profile</router-link>

新頁面里如何取?還是用之前用過的$route對象

this.$route.query

2.不用<router-link>怎么傳query??

router.push和router.replace傳入上述對象即可

  methods: {
    btnClick(){
      this.$router.push({
        path:'/profile',
        query:{
          name:"lili",
          age:18,
          gender:'girl'
        }
      })
    }
  }

七. keep-alive

一個頁面如果跳轉(zhuǎn)到了另一個頁面,那么這個頁面會被銷毀,此時如果用戶又返回這個頁面,又需要重新加載.

keep-alive主要解決離開頁面又返回時,頁面需要重構(gòu)的問題,這種重構(gòu)很多時候都是沒必要的

1. 如何使用keep-alive?

  • <router-view>其實(shí)也是個組件,如果它直接被包在<keep-alive>里面,所有涉及到的視圖組件都會被緩存

  • <keep-alive>是定義在Vue中的內(nèi)置組件,目的是為了避免重新渲染

例:我們想讓home的兩個次級路由的組件來回切換時不重新構(gòu)建,可以給控制他們顯示的<router-view>用<keep-alive>包起來

<template>
  <div>
    <h2>我是首頁</h2>
    <p>我是首頁內(nèi)容</p>
    <router-link to="/home/news">看看新聞</router-link>
    <router-link to="/home/msgs">看看消息</router-link>
    <keep-alive>
      <router-view></router-view>
    </keep-alive>
  </div>
</template>

<script>
export default {
  name: "Home"
};
</script>

<style>
</style>

2. 因?yàn)楸籯eep-alive,子組件多了兩個屬性

被keep-alive的組件都會多兩個屬性 activated 和 deactivated,里面可以傳入方法,當(dāng)活躍/不活躍時調(diào)用

舉例:

<template>
  <div>
    <h1>您有4條短消息</h1>
    <ul>
      <li>短消息1</li>
      <li>短消息2</li>
      <li>短消息3</li>
      <li>短消息4</li>
    </ul>
  </div>
</template>

<script>
export default {
  name:"HomeMsg",
  activated() {
    console.log("我真活躍");
  },
  deactivated() {
    console.log("我不活躍了");
  },
}
</script>

<style>

</style>

3.<keep-alive> 的包含和例外

如果又4個標(biāo)簽,我們想其中3個keep-alive怎么辦???

這時我們需要用keep-alive的屬性

    <keep-alive exclude="HomeMsg,User">    這會排除這兩個組件的keep-alive
      <router-view></router-view>
    </keep-alive>

八. 導(dǎo)航守衛(wèi)

有時我們需要監(jiān)聽頁面跳轉(zhuǎn)

比如,我們要監(jiān)聽頁面跳轉(zhuǎn),跳轉(zhuǎn)時,將我們的網(wǎng)站的title該為對應(yīng)頁面的名稱

1.前置守衛(wèi)

前置守衛(wèi)是跳轉(zhuǎn)前的守衛(wèi)

我們可以在index.js里,給我們的router調(diào)用一個前置守衛(wèi)(鉤子)函數(shù):router.beforeEach()

router.beforeEach((to,from,next)=>{   //這就是頁面跳轉(zhuǎn)過程
  document.title= to.meta.matched[0].title  //將頁面標(biāo)題改為了to路由的meta信息里的標(biāo)題
  next()  // 必須調(diào)用next(),以維護(hù)鏈?zhǔn)?})

前提是to路由里有meta,如: meta(描述信息)

  {
    path:"/profile",
    component:()=>import('../components/Profile'),
    meta:{
      title:'檔案'
    },
  },

為什么有個 .matched[0], 因?yàn)橛袝r我們進(jìn)入嵌套路由,比如, home/news,

但此時我們還想顯示home的meta, 就可以通過這種方法找到它的第一級路由的meta
比如: 如果用戶登錄了,其他頁面可以正常跳轉(zhuǎn)和訪問,如果沒登錄,跳轉(zhuǎn)到登錄界面

// 掛載路由導(dǎo)航守衛(wèi)
router.beforeEach((to, from, next) => { // 這就是頁面跳轉(zhuǎn)過程
  if (to.path === '/login') next()
  const token = window.sessionStorage.getItem('token')
  if (!token) return next('/login')
  next()
})

2.后置守衛(wèi)

其實(shí)還有后置守衛(wèi)(鉤子):

router.afterEach(to,from)

后置守衛(wèi)沒有next

3.next有大用

  • next(): 進(jìn)行管道中的下一個鉤子片择。如果全部鉤子執(zhí)行完了啰挪,則導(dǎo)航的狀態(tài)就是 confirmed (確認(rèn)的)亡呵。

  • next(false): 中斷當(dāng)前的導(dǎo)航锰什。如果瀏覽器的 URL 改變了 (可能是用戶手動或者瀏覽器后退按鈕)梭姓,那么 URL 地址會重置到 from 路由對應(yīng)的地址嫩码。

  • next('/') 或者 next({ path: '/' }): 跳轉(zhuǎn)到一個不同的地址释牺。當(dāng)前的導(dǎo)航被中斷回挽,然后進(jìn)行一個新的導(dǎo)航。你可以向 next 傳遞任意位置對象祭刚,且允許設(shè)置諸如 replace: true涡驮、name: 'home' 之類的選項以及任何用在 router-link 的 to proprouter.push 中的選項。

  • next(error): (2.4.0+) 如果傳入 next 的參數(shù)是一個 Error 實(shí)例棒口,則導(dǎo)航會被終止且該錯誤會被傳遞給 router.onError() 注冊過的回調(diào)无牵。

4.路由獨(dú)享守衛(wèi)

你可以在路由配置上直接定義 beforeEnter 守衛(wèi):

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

5.組件內(nèi)守衛(wèi)

你可以在路由組件內(nèi)直接定義以下路由導(dǎo)航守衛(wèi):

const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在渲染該組件的對應(yīng)路由被 confirm 前調(diào)用
    // 不茎毁!能七蜘!獲取組件實(shí)例 `this`
    // 因?yàn)楫?dāng)守衛(wèi)執(zhí)行前崔梗,組件實(shí)例還沒被創(chuàng)建
  },
  beforeRouteUpdate (to, from, next) {
    // 在當(dāng)前路由改變,但是該組件被復(fù)用時調(diào)用
    // 舉例來說,對于一個帶有動態(tài)參數(shù)的路徑 /foo/:id谈为,在 /foo/1 和 /foo/2 之間跳轉(zhuǎn)的時候,
    // 由于會渲染同樣的 Foo 組件秕脓,因此組件實(shí)例會被復(fù)用吠架。而這個鉤子就會在這個情況下被調(diào)用傍药。
    // 可以訪問組件實(shí)例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 導(dǎo)航離開該組件的對應(yīng)路由時調(diào)用
    // 可以訪問組件實(shí)例 `this`
  }
}
beforeRouteEnter 守衛(wèi) 不能 訪問 this拐辽,因?yàn)槭匦l(wèi)在導(dǎo)航確認(rèn)前被調(diào)用,因此即將登場的新組件還沒被創(chuàng)建俱诸。

不過睁搭,你可以通過傳一個回調(diào)給 next來訪問組件實(shí)例。在導(dǎo)航被確認(rèn)的時候執(zhí)行回調(diào)遇伞,并且把組件實(shí)例作為回調(diào)方法的參數(shù)鸠珠。

beforeRouteEnter (to, from, next) {
  next(vm => {
    // 通過 `vm` 訪問組件實(shí)例
  })
}
注意 beforeRouteEnter 是支持給 next 傳遞回調(diào)的唯一守衛(wèi)渐排。對于 beforeRouteUpdate 和 beforeRouteLeave 來說驯耻,this 已經(jīng)可用了霎迫,所以不支持傳遞回調(diào),因?yàn)闆]有必要了涩赢。

beforeRouteUpdate (to, from, next) {
  // just use `this`
  this.name = to.params.name
  next()
}
這個離開守衛(wèi)通常用來禁止用戶在還未保存修改前突然離開。該導(dǎo)航可以通過 next(false) 來取消赃阀。

beforeRouteLeave (to, from, next) {
  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
  if (answer) {
    next()
  } else {
    next(false)
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市懂缕,隨后出現(xiàn)的幾起案子搪柑,更是在濱河造成了極大的恐慌工碾,老刑警劉巖渊额,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異垒拢,居然都是意外死亡旬迹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門求类,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奔垦,“玉大人,你說我怎么就攤上這事尸疆〈涣裕” “怎么了惶岭?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵阔逼,是天一觀的道長危融。 經(jīng)常有香客問我楷怒,道長,這世上最難降的妖魔是什么烘贴? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任酪捡,我火速辦了婚禮永罚,結(jié)果婚禮上羞福,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好饶深,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布额湘。 她就那樣靜靜地躺著衍腥,像睡著了一般尚骄。 火紅的嫁衣襯著肌膚如雪需五。 梳的紋絲不亂的頭發(fā)上边琉,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天怒竿,我揣著相機(jī)與錄音,去河邊找鬼咏花。 笑死浸踩,一個胖子當(dāng)著我的面吹牛瑰钮,可吹牛的內(nèi)容都是我干的扶檐。 我是一名探鬼主播杈湾,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼署驻,長吁一口氣:“原來是場噩夢啊……” “哼杭攻!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起勋桶,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎惊楼,沒想到半個月后裁良,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體座硕,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡持寄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了熟空。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡非剃,死狀恐怖疯坤,靈堂內(nèi)的尸體忽然破棺而出飞苇,到底是詐尸還是另有隱情栖忠,我是刑警寧澤捐川,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布菇用,位于F島的核電站,受9級特大地震影響悍缠,放射性物質(zhì)發(fā)生泄漏卦绣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一飞蚓、第九天 我趴在偏房一處隱蔽的房頂上張望滤港。 院中可真熱鬧,春花似錦趴拧、人聲如沸溅漾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽添履。三九已至,卻和暖如春脑又,著一層夾襖步出監(jiān)牢的瞬間暮胧,已是汗流浹背锐借。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叔壤,地道東北人瞎饲。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像炼绘,于是被迫代替她去往敵國和親嗅战。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容