玩轉Vue路由--前端小白也能開發vue電商項目(2)

路由是什麼?爲什麼要使用路由?路由有什麼功能?可以寫出路由跳轉的源碼嗎?

寫完路由部分,四連打擊讓我深思,一起來學習一下vue的翅膀Vue-Router吧~

這是一個基於 vue & axios & mock & token & stylus & Cube-UI的電商項目demo,面向 vue 初學者,場景雖簡單,但五臟俱全。涵蓋非常多的vue及其相關技術的基本操作。有詳細的註釋,幫助大家快速上手 vue 。

Github地址


正文部分

作爲VUE的初學者,創建一個項目後的demo裏面就有home頁面和about頁面的跳轉。在寫這個小項目的時候,我也是照葫蘆畫瓢沒有過多的思考。寫完路由部分的時候,反過來思考,心中也有許多疑問。路由是什麼?爲什麼要使用路由?路由有什麼功能?可以寫出路由跳轉的源碼嗎?
帶着這些問題我查閱了很多資料和文章,發現它們都比較散,往往只講述一個小點。如果你也有相同的問題就跟隨我來逐一擊破吧~

路由是什麼?

  1. 路由:即瀏覽器中的哈希值(# hash)與展示視圖內容(template)之間的對應規則。

在計算機網絡原理中,路由指的是根據上一接口的數據包中的IP地址,查詢路由錶轉發到另一個接口,它是決定一個端到端的網絡路徑。所以說路由就是用來解析URL以及調用對應的控制器的。

  1. vue中的路由是:hash 和component的對應關係。Vue路由即vue-router,在web開發中,“router”是指根據url分配到對應的處理程序。

通俗的來說,在web開發中,路由就是一套映射規則(一對一的對應規則),由開發人員制定規則。
當URL中的哈希值(# hash)發生改變後,路由會根據制定好的規則,展示對應的視圖內容。

爲什麼要使用路由?

在傳統的web開發中每一個請求地址都會請求服務器來進行處理,但是用戶有些操作則無需請求服務器,直接頁面端修改下邏輯就能達到目的,在這種方式下最好的方法是使用路由,因爲使用路由時,URL會隨着改變,用戶瀏覽一個網頁時可以直接複製或收藏當前頁面的URL給別人,這種方式對於搜索引擎和用戶來說都是友好的。

在 Web app 中,通過一個頁面來展示和管理整個應用的功能。
SPA(單頁應用程序)往往是功能複雜的應用,爲了有效管理所有視圖內容,前端路由 應運而生!

路由有什麼功能?

這個問題,我是通過Vue Router開發者文檔,進行了解的,但是我看完之後還是有點懵懵懂懂,沒有特別理解,之後我是通過查閱一些文章對路由的功能有了更深入的瞭解,下面跟隨作者一起結合項目來看看吧~

基本使用

安裝:npm i -S vue-router或者創建vue項目時就選擇了router

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

// 3 創建兩個組件  作者就不寫代碼啦vue項目一開始的demo有創建。

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

Vue.use(VueRouter)

// 4 創建路由對象
const routes = [
  {
    path: '/',
    name: 'login',
    redirect: '/login'
  },
   // 路徑和組件一一對應
  {
    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.
    //項目路由懶加載,秒開
    component: () => import(/* webpackChunkName: "about" */ '../views/Login.vue')
    },
]
 
<!-- main.js -->
// 1 導入 vue.js 
import Vue from 'vue'
import './cube-ui'
import App from './App.vue'
// 2 導入 路由文件 
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 將路由實例掛載到vue實例
  render: h => h(App)
}).$mount('#app')

通過代碼註釋中步驟,就完成路由基本功能的實現啦!

重定向

在這個小項目中,我是直接使用重定向,讓頁面一開始在根路徑的時候就跳轉到登陸頁面。

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

重定向還有兩種方式

  1. 重定向的目標可以是一個命名的路由:
{ path: '/', redirect: { name: 'login' }}
  1. 重定向的目標可以是一個方法,動態返回重定向目標:
{ path: '/', redirect: to => {
      // 方法接收 目標路由 作爲參數
      // return 重定向的 字符串路徑/路徑對象
    }}

注:導航守衛並沒有應用在跳轉路由上,而僅僅應用在其目標上。

懶加載(延遲加載)

  1. 定義:懶加載也叫延遲加載,即在需要的時候進行加載,隨用隨載。
  2. 作用:路由懶加載可以幫我們在進入首屏時不用加載過度的資源,從而減少首屏加載速度。也就是按需加載。使用第三方組件庫依賴過大,會給首屏加載帶來很大的壓力,一般解決方式是按需求引入組件。如果引用組件的組件,也是跳轉到相應路由,再進行加載需要使用的組件,可以提高性能。
  3. 實現懶加載的三種方式:
一、Vue異步組件技術:
	{
		path: '/home',
		name: 'Home',
		component: resolve => reqire(['path路徑'], resolve)
	}
二、es6提案的import()
	const Home = () => import('path路徑')
	//本項目使用的方式
   {
    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')
	}
總結來自:
作者:小夢喲
鏈接:https://juejin.im/post/5e4c0b856fb9a07ccb7e8eca
來源:掘金

可以手寫懶加載源碼嗎?

這個問題我也想了一下,實現懶加載肯定是要直接操作DOM。作爲前端小白的我能力有限,暫時無法完成,但是找到了一篇文章可以供大家參考。

懶加載的弊端

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

大項目中的路由懶加載不適用於開發環境(會導致保存代碼時熱更新代碼時間很長20s左右)

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

_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');

組件引入時寫入:

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

嵌套子路由

在我的小項目中也使用了嵌套路由。嵌套路由顧名思義,路由中又包含子路由。例如:

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

想要在botnav頁面中,切換index,list等多個頁面時,嵌套路由就派上用場啦,它的書寫規則如下:

注:childern子路由path一定不要加上‘\’,寫代碼時,寫路由路徑寫習慣了,很容易犯這個小錯誤

{
    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')
      },
    ]
}

實現效果:


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

過渡動效

在寫項目時,爲了增加用戶體驗感,加上路由切換時的過渡動效是必不可少的,下面先看一下過度動效的效果展示:

是基本的動態組件,所以我們可以用 組件給它添加一些過渡效果:

<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)
    },
    //點擊與自身不同的其他導航
    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
            <!--以下代碼實現過渡效果-->
      .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>

以上代碼建立了一個botnav,用包裹,並給transition起了一個名字,利用css中的leave和enter來完成頁面切換,在裏面寫上要實現的效果。這裏我引用VUE.js中的一張圖片來直觀的解釋:

本項目中用silde-right替換了v-。
路由還有其他很多功能,我就不一一介紹啦,大家有興趣可以去看看官方文檔。下面我們來解答最後一個疑問,?可以寫出路由跳轉的源碼嗎?

可以寫出路由跳轉的源碼嗎?

想要知道路由的源碼怎麼寫?一定要知道路由是怎麼實現的。我淺顯的理解是,對於路由的hush模式,我們切換一個頁面,就是對一個視圖的展示。需要對這個視圖進行展示,一定想要獲取這個頁面的huas值,然後去對這個視圖進行註冊,然後進行展示。這樣利用路由切換頁面就成功啦。我不知道我的理解是否正確,希望大佬指出。下面我對我的思路進行源碼的書寫,先放上效果圖。

我們先寫三個鏈接:

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

然後我們定義一個hashRouter方法,並實現進入首頁時,返回空。

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

接下來我們進行獲取hash和對頁面視圖進行註冊:

 class HashRouter {
    constructor() {
      this.routers = {}; //配置, 是設計關鍵點 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 後執行哪個函數
    // vue 組件 函數式組件 callback
    register(hash, callback){
      this.routers[hash] = callback;//進行視圖註冊
    } 
    //初始化時執行
    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';
  }) // 路由 對應執行事  //.vue template部分
  router.register('/page2', () => container.innerHTML = '/page2'); 
  router.register('/page3', () => container.innerHTML = '/page3'); 

路由簡單實現就完成啦,如有錯誤還望大佬指出。


寫在後面

引用小金魚的一句話,當然紙上學來終覺淺,絕知此事要躬行。學完理論就需要去實踐,大家看完之後一定要自己去操作一下,不然似懂非懂,第二天就忘啦。在此作者再次附上GitHub的地址vue-jingdong (不要吝惜你的小星星哦)。這是一個系列文章,未完待續,期待與你一起學習。如果對你有幫助的話,不妨送上你的star,送人玫瑰,手留餘香,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章