簡單分析Vue路由--前端小白也能開發(fā)vue電商項(xiàng)目(2)

image

路由是什么桶唐?為什么要使用路由渠牲?路由有什么功能?可以寫出路由跳轉(zhuǎn)的源碼嗎泌参?

寫完路由部分脆淹,四連打擊讓我深思,一起來學(xué)習(xí)一下vue的翅膀Vue-Router吧~

這是一個(gè)基于 vue & axios & mock & token & stylus & Cube-UI的電商項(xiàng)目demo及舍,面向 vue 初學(xué)者未辆,場景雖簡單,但五臟俱全锯玛。涵蓋非常多的vue及其相關(guān)技術(shù)的基本操作。有詳細(xì)的注釋兼蜈,幫助大家快速上手 vue 攘残。

Github地址

image

正文部分

作為VUE的初學(xué)者,創(chuàng)建一個(gè)項(xiàng)目后的demo里面就有home頁面和about頁面的跳轉(zhuǎn)为狸。在寫這個(gè)小項(xiàng)目的時(shí)候歼郭,我也是照葫蘆畫瓢沒有過多的思考。寫完路由部分的時(shí)候辐棒,反過來思考病曾,心中也有許多疑問牍蜂。路由是什么?為什么要使用路由泰涂?路由有什么功能鲫竞?可以寫出路由跳轉(zhuǎn)的源碼嗎?
帶著這些問題我查閱了很多資料和文章逼蒙,發(fā)現(xiàn)它們都比較散从绘,往往只講述一個(gè)小點(diǎn)。如果你也有相同的問題就跟隨我來逐一擊破吧~

路由是什么是牢?

  1. 路由:即瀏覽器中的哈希值(# hash)與展示視圖內(nèi)容(template)之間的對應(yīng)規(guī)則僵井。

在計(jì)算機(jī)網(wǎng)絡(luò)原理中,路由指的是根據(jù)上一接口的數(shù)據(jù)包中的IP地址驳棱,查詢路由表轉(zhuǎn)發(fā)到另一個(gè)接口批什,它是決定一個(gè)端到端的網(wǎng)絡(luò)路徑。所以說路由就是用來解析URL以及調(diào)用對應(yīng)的控制器的社搅。

  1. vue中的路由是:hash 和component的對應(yīng)關(guān)系驻债。Vue路由即vue-router,在web開發(fā)中罚渐,“router”是指根據(jù)url分配到對應(yīng)的處理程序却汉。

通俗的來說,在web開發(fā)中荷并,路由就是一套映射規(guī)則(一對一的對應(yīng)規(guī)則)合砂,由開發(fā)人員制定規(guī)則。
當(dāng)URL中的哈希值(# hash)發(fā)生改變后源织,路由會根據(jù)制定好的規(guī)則翩伪,展示對應(yīng)的視圖內(nèi)容。

image

為什么要使用路由谈息?

在傳統(tǒng)的web開發(fā)中每一個(gè)請求地址都會請求服務(wù)器來進(jìn)行處理缘屹,但是用戶有些操作則無需請求服務(wù)器,直接頁面端修改下邏輯就能達(dá)到目的侠仇,在這種方式下最好的方法是使用路由轻姿,因?yàn)槭褂寐酚蓵r(shí),URL會隨著改變逻炊,用戶瀏覽一個(gè)網(wǎng)頁時(shí)可以直接復(fù)制或收藏當(dāng)前頁面的URL給別人互亮,這種方式對于搜索引擎和用戶來說都是友好的。

在 Web app 中余素,通過一個(gè)頁面來展示和管理整個(gè)應(yīng)用的功能豹休。
SPA(單頁應(yīng)用程序)往往是功能復(fù)雜的應(yīng)用,為了有效管理所有視圖內(nèi)容桨吊,前端路由 應(yīng)運(yùn)而生威根!

路由有什么功能凤巨?

這個(gè)問題,我是通過Vue Router開發(fā)者文檔洛搀,進(jìn)行了解的敢茁,但是我看完之后還是有點(diǎn)懵懵懂懂,沒有特別理解姥卢,之后我是通過查閱一些文章對路由的功能有了更深入的了解卷要,下面跟隨作者一起結(jié)合項(xiàng)目來看看吧~

基本使用

安裝:npm i -S vue-router或者創(chuàng)建vue項(xiàng)目時(shí)就選擇了router

<!-- app.vue -->
<template>
  <div id="app">
  <!-- 5 路由入口 指定跳轉(zhuǎn)到只定入口 -->
    <div id="nav">
      <router-link to="/login">登陸</router-link> |
      <router-link to="/register">注冊</router-link>
    </div>
    <!-- 7 路由出口:用來展示匹配路由視圖內(nèi)容 -->
    <router-view/>
  </div>
</template>

// 3 創(chuàng)建兩個(gè)組件  作者就不寫代碼啦vue項(xiàng)目一開始的demo有創(chuàng)建独榴。

//router中的index.js
import Register from '../views/Register.vue'
import Login from '../views/Login.vue'

Vue.use(VueRouter)

// 4 創(chuàng)建路由對象
const routes = [
  {
    path: '/',
    name: 'login',
    redirect: '/login'
  },
   // 路徑和組件一一對應(yīng)
  {
    path: '/register',
    name: 'register',
    component: Register
  },
  {
    path: '/login',
    name: 'login',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    //項(xiàng)目路由懶加載僧叉,秒開
    component: () => import(/* webpackChunkName: "about" */ '../views/Login.vue')
    },
]
 
<!-- main.js -->
// 1 導(dǎo)入 vue.js 
import Vue from 'vue'
import './cube-ui'
import App from './App.vue'
// 2 導(dǎo)入 路由文件 
import router from './router'
import store from './store'
import axios from 'axios'
import 'amfe-flexible'
import steaxios from './setaxios'

steaxios();
Vue.config.productionTip = false
Vue.prototype.$http=axios//掛載axios
new Vue({
  router,
  store,
  // 6 將路由實(shí)例掛載到vue實(shí)例
  render: h => h(App)
}).$mount('#app')

通過代碼注釋中步驟,就完成路由基本功能的實(shí)現(xiàn)啦棺榔!

重定向

在這個(gè)小項(xiàng)目中瓶堕,我是直接使用重定向,讓頁面一開始在根路徑的時(shí)候就跳轉(zhuǎn)到登陸頁面症歇。

 {
    //  將path 重定向到 redirect
    path: '/',
    name: 'login',
    redirect: '/login'
  },

重定向還有兩種方式

  1. 重定向的目標(biāo)可以是一個(gè)命名的路由:
{ path: '/', redirect: { name: 'login' }}
  1. 重定向的目標(biāo)可以是一個(gè)方法郎笆,動態(tài)返回重定向目標(biāo):
{ path: '/', redirect: to => {
      // 方法接收 目標(biāo)路由 作為參數(shù)
      // return 重定向的 字符串路徑/路徑對象
    }}

注:導(dǎo)航守衛(wèi)并沒有應(yīng)用在跳轉(zhuǎn)路由上,而僅僅應(yīng)用在其目標(biāo)上忘晤。

懶加載(延遲加載)

  1. 定義:懶加載也叫延遲加載宛蚓,即在需要的時(shí)候進(jìn)行加載,隨用隨載设塔。
  2. 作用:路由懶加載可以幫我們在進(jìn)入首屏?xí)r不用加載過度的資源凄吏,從而減少首屏加載速度。也就是按需加載闰蛔。使用第三方組件庫依賴過大,會給首屏加載帶來很大的壓力痕钢,一般解決方式是按需求引入組件。如果引用組件的組件序六,也是跳轉(zhuǎn)到相應(yīng)路由任连,再進(jìn)行加載需要使用的組件,可以提高性能例诀。
  3. 實(shí)現(xiàn)懶加載的三種方式:
一随抠、Vue異步組件技術(shù):
    {
        path: '/home',
        name: 'Home',
        component: resolve => reqire(['path路徑'], resolve)
    }
二、es6提案的import()
    const Home = () => import('path路徑')
    //本項(xiàng)目使用的方式
   {
    path: '/login',
    name: 'login',
    component: () => import(/* webpackChunkName: "about" */ '../views/Login.vue')
    },
三繁涂、webpack提供的require.ensure()
    {
        path: '/home',
        name: 'Home',
        component: r => require.ensure([],() =>  r(require('path路徑')), 'demo')
    }
總結(jié)來自:
作者:小夢喲
鏈接:https://juejin.im/post/5e4c0b856fb9a07ccb7e8eca
來源:掘金

可以手寫懶加載源碼嗎暮刃?

這個(gè)問題我也想了一下,實(shí)現(xiàn)懶加載肯定是要直接操作DOM爆土。作為前端小白的我能力有限,暫時(shí)無法完成诸蚕,但是找到了一篇文章可以供大家參考步势。

懶加載的弊端

所有的東西都是一把雙刃劍氧猬,有利也有弊,只能按需使用坏瘩,切不可過度使用盅抚。

大項(xiàng)目中的路由懶加載不適用于開發(fā)環(huán)境(會導(dǎo)致保存代碼時(shí)熱更新代碼時(shí)間很長20s左右)

解決辦法
在 router/ 文件夾中加入2個(gè)文件夾:

_import_development.js

module.exports = file => require('@/' + file + '.vue').default

_import_production.js

module.exports = file => resolve => require(['@/' + file + '.vue'], resolve)

index.js

const IMPORT = require('./_import_' + process.env.NODE_ENV + '.js');

組件引入時(shí)寫入:

component: IMPORT('pages/mainPage')  //  組件

嵌套子路由

在我的小項(xiàng)目中也使用了嵌套路由。嵌套路由顧名思義倔矾,路由中又包含子路由妄均。例如:

/botnav/index                         /botnav/list
+------------------+                  +-----------------+
| botnav           |                  | botnav          |
| +--------------+ |                  | +-------------+ |
| | index        | |  +------------>  | | list        | |
| |              | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+

想要在botnav頁面中,切換index,list等多個(gè)頁面時(shí)哪自,嵌套路由就派上用場啦丰包,它的書寫規(guī)則如下:

注:childern子路由path一定不要加上‘\’,寫代碼時(shí)壤巷,寫路由路徑寫習(xí)慣了邑彪,很容易犯這個(gè)小錯(cuò)誤

{
    path: '/botnav',
    name: 'botnav',
    component: () => import('../views/Botnav.vue'),
 children:[
      {
        path: 'index',
        name: 'index',
        component: () => import('../views/index.vue')
      },
      {
        path: 'list',
        name: 'list',
        component: () => import('../views/List.vue')
      },
      {
        path: 'search',
        name: 'search',
        component: () => import('../views/Search.vue')
      },
      {
        path: 'cart',
        name: 'cart',
        component: () => import('../views/Cart.vue')
      },
      {
        path: 'mine',
        name: 'mine',
        component: () => import('../views/Mine.vue')
      },
    ]
}

實(shí)現(xiàn)效果:

image

這幾個(gè)botnav就可以在同一個(gè)頁面切換啦。

過渡動效

在寫項(xiàng)目時(shí)胧华,為了增加用戶體驗(yàn)感寄症,加上路由切換時(shí)的過渡動效是必不可少的,下面先看一下過度動效的效果展示:

image

<router-view> 是基本的動態(tài)組件矩动,所以我們可以用 <transition> 組件給它添加一些過渡效果:

<template>
    <div>
      <transition :name="transitionName">
        <router-view class="Router"></router-view>
      </transition>
        <cube-tab-bar
            v-model="selectedLabelDefault"
            :data="tabs"
            @click="clickHandler"
            @change="changeHandler"
            class="botnav">
        </cube-tab-bar>
  </div>
</template>
<script>
export default {
  data () {
    return {
      transitionName:'slide-right',
      selectedLabelDefault: '首頁',
      tabs: [{
        label: '首頁',
        icon: 'cubeic-home'
      }, {
        label: '分類',
        icon: 'cubeic-tag'
      }, {
        label: '搜索',
        icon: 'cubeic-search'
      }, {
        label: '購物車',
        icon: 'cubeic-mall'
      }, {
        label: '我的',
        icon: 'cubeic-person'
      }]
    }
  },
  methods: {
    clickHandler (label) {
      // if you clicked home tab, then print 'Home'
      console.log(label)
    },
    //點(diǎn)擊與自身不同的其他導(dǎo)航
    changeHandler (label) {
      // if you clicked different tab, this methods can be emitted
      switch(label){
          case '首頁':
          this.$router.push('/botnav/index');
          break;
          case '分類':
          this.$router.push({path:'/botnav/list'});
          break;
          case '搜索':
          this.$router.push({path:'/botnav/search'});
          break;
          case '購物車':
          this.$router.push({path:'/botnav/cart'});
          break;
          case '我的':
          this.$router.push({path:'/botnav/mine'});
          break;
      }
    }
  }
}
</script>

<style lang="stylus" scoped>
    .cube-tab-bar.botnav
        position  fixed
        bottom  0
        left 0
        z-index 1000
        width 100%
        background #fff
        font-size  25px
        .cube-tab div
            font-size  16px
            padding-top  3px
        i 
            font-size 20px
            <!--以下代碼實(shí)現(xiàn)過渡效果-->
      .Router
        position absolute
        width 100%
        transition all 0.8s ease 
      .silde-left-ender,.slide-right-leave-active
        opacity 0
        -webkit-transform translate(100%,0)
        transform translate(100%,0)
      .slide-left-leave-active,.silde-right-enter
        opacity 0
        -webkit-transform translate(-100%,0)
        transform translate(-100%,0)
</style>

以上代碼建立了一個(gè)botnav有巧,用<transition>包裹<router-view>,并給transition起了一個(gè)名字悲没,利用css中的leave和enter來完成頁面切換篮迎,在里面寫上要實(shí)現(xiàn)的效果。這里我引用VUE.js中的一張圖片來直觀的解釋:

image

本項(xiàng)目中用silde-right替換了v-檀训。
路由還有其他很多功能柑潦,我就不一一介紹啦,大家有興趣可以去看看官方文檔峻凫。下面我們來解答最后一個(gè)疑問渗鬼,?可以寫出路由跳轉(zhuǎn)的源碼嗎荧琼?

可以寫出路由跳轉(zhuǎn)的源碼嗎譬胎?

想要知道路由的源碼怎么寫?一定要知道路由是怎么實(shí)現(xiàn)的命锄。我淺顯的理解是堰乔,對于路由的hush模式,我們切換一個(gè)頁面脐恩,就是對一個(gè)視圖的展示镐侯。需要對這個(gè)視圖進(jìn)行展示,一定想要獲取這個(gè)頁面的huas值驶冒,然后去對這個(gè)視圖進(jìn)行注冊苟翻,然后進(jìn)行展示韵卤。這樣利用路由切換頁面就成功啦。我不知道我的理解是否正確崇猫,希望大佬指出沈条。下面我對我的思路進(jìn)行源碼的書寫,先放上效果圖诅炉。

image

我們先寫三個(gè)鏈接:

 <div id="nav">
    <a href="#/page1">page1</a>
    <a href="#/page2">page2</a>
    <a href="#/page3">page3</a>
  </div>
  <div id="container"></div>

然后我們定義一個(gè)hashRouter方法蜡歹,并實(shí)現(xiàn)進(jìn)入首頁時(shí),返回空涕烧。

class HashRouter {
//初始化時(shí)執(zhí)行
    registerIndex(cb = () => {}) {
      this.routers.index = cb;
    }
  }

接下來我們進(jìn)行獲取hash和對頁面視圖進(jìn)行注冊:

 class HashRouter {
    constructor() {
      this.routers = {}; //配置月而, 是設(shè)計(jì)關(guān)鍵點(diǎn) routes 
      //存儲路由配置的 hash key  val Component
      window.addEventListener('hashchange', () => {
        let hash = window.location.hash.slice(1),//獲取頁面hash
          handler;
        if(!hash) {
          handler = this.routers.index;
        } else {
          handler = this.routers[hash];
        }
        handler.call(this);//將hash拋出去
      })
    }
    // hahschange 后執(zhí)行哪個(gè)函數(shù)
    // vue 組件 函數(shù)式組件 callback
    register(hash, callback){
      this.routers[hash] = callback;//進(jìn)行視圖注冊
    } 
    //初始化時(shí)執(zhí)行
    registerIndex(cb = () => {}) {
      this.routers.index = cb;
    }
  }

最后我們將注冊后的視圖,插入到id="container"澈魄,讓頁面顯示

let router = new HashRouter(); //路由對象景鼠, 類型為hash
  let container =
   document.getElementById('container'); // 根組件
  router.registerIndex(() => container.innerHTML = '首頁')
  router.register('/page1', function ()  
  {
    console.log(this.routers);
    container.innerHTML = '/page1';
  }) // 路由 對應(yīng)執(zhí)行事  //.vue template部分
  router.register('/page2', () => container.innerHTML = '/page2'); 
  router.register('/page3', () => container.innerHTML = '/page3'); 

路由簡單實(shí)現(xiàn)就完成啦,如有錯(cuò)誤還望大佬指出痹扇。


寫在后面

引用小金魚的一句話铛漓,當(dāng)然紙上學(xué)來終覺淺,絕知此事要躬行鲫构。學(xué)完理論就需要去實(shí)踐浓恶,大家看完之后一定要自己去操作一下,不然似懂非懂结笨,第二天就忘啦包晰。在此作者再次附上GitHub的地址vue-jingdong (不要吝惜你的小星星哦)。這是一個(gè)系列文章炕吸,未完待續(xù)伐憾,期待與你一起學(xué)習(xí)。如果對你有幫助的話赫模,不妨送上你的star树肃,送人玫瑰,手留余香瀑罗,謝謝胸嘴!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市斩祭,隨后出現(xiàn)的幾起案子劣像,更是在濱河造成了極大的恐慌,老刑警劉巖摧玫,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件耳奕,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)吮铭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進(jìn)店門时迫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人谓晌,你說我怎么就攤上這事●啵” “怎么了纸肉?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長喊熟。 經(jīng)常有香客問我柏肪,道長,這世上最難降的妖魔是什么芥牌? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任烦味,我火速辦了婚禮,結(jié)果婚禮上壁拉,老公的妹妹穿的比我還像新娘谬俄。我一直安慰自己,他們只是感情好弃理,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布溃论。 她就那樣靜靜地躺著,像睡著了一般痘昌。 火紅的嫁衣襯著肌膚如雪钥勋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天辆苔,我揣著相機(jī)與錄音算灸,去河邊找鬼。 笑死驻啤,一個(gè)胖子當(dāng)著我的面吹牛菲驴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播街佑,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼谢翎,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了沐旨?” 一聲冷哼從身側(cè)響起森逮,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎磁携,沒想到半個(gè)月后褒侧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年闷供,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了烟央。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,865評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡歪脏,死狀恐怖疑俭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情婿失,我是刑警寧澤钞艇,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站豪硅,受9級特大地震影響哩照,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜懒浮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一飘弧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧砚著,春花似錦次伶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至秧骑,卻和暖如春版确,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背乎折。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工绒疗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人骂澄。 一個(gè)月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓吓蘑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親坟冲。 傳聞我的和親對象是個(gè)殘疾皇子磨镶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評論 2 361

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

  • SPA單頁應(yīng)用 傳統(tǒng)的項(xiàng)目大多使用多頁面結(jié)構(gòu)私痹,需要切換內(nèi)容的時(shí)候我們往往會進(jìn)行單個(gè)html文件的跳轉(zhuǎn)脐嫂,這個(gè)時(shí)候受網(wǎng)...
    視覺派Pie閱讀 11,851評論 1 55
  • 前言 在上篇中主要敘述了 vue-router 的注冊和實(shí)例化過程统刮,以及如何生成 $router, $route ...
    心_c2a2閱讀 935評論 0 1
  • 一、vue-router實(shí)現(xiàn)原理 SPA(single page application):單一頁面應(yīng)用程序账千,只有...
    walycode閱讀 1,054評論 1 3
  • Vue八個(gè)生命周期 beforeCreate【創(chuàng)建前】created【創(chuàng)建后】 beforeMount【載入前】 ...
    艾薩克菊花閱讀 1,321評論 0 12
  • 據(jù)說侥蒙,村子里來了位道士!說來這道士也奇匀奏,一不看地二不面相鞭衩,只做一件事,專賣密制丹藥攒射,村民大多是中老年人醋旦,哄...
    木老頭兒閱讀 751評論 6 16