路由是什么桶唐?為什么要使用路由渠牲?路由有什么功能?可以寫出路由跳轉(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地址
- vue-jingdong (不要吝惜你的小星星哦)
- 話不多說上效果圖
正文部分
作為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)。如果你也有相同的問題就跟隨我來逐一擊破吧~
路由是什么是牢?
- 路由:即瀏覽器中的哈希值(# 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)的控制器的社搅。
- 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)容。
為什么要使用路由谈息?
在傳統(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'
},
重定向還有兩種方式
- 重定向的目標(biāo)可以是一個(gè)命名的路由:
{ path: '/', redirect: { name: 'login' }}
- 重定向的目標(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)上忘晤。
懶加載(延遲加載)
- 定義:懶加載也叫延遲加載宛蚓,即在需要的時(shí)候進(jìn)行加載,隨用隨載设塔。
- 作用:路由懶加載可以幫我們在進(jìn)入首屏?xí)r不用加載過度的資源凄吏,從而減少首屏加載速度。也就是按需加載闰蛔。使用第三方組件庫依賴過大,會給首屏加載帶來很大的壓力痕钢,一般解決方式是按需求引入組件。如果引用組件的組件序六,也是跳轉(zhuǎn)到相應(yīng)路由任连,再進(jìn)行加載需要使用的組件,可以提高性能例诀。
- 實(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)效果:
這幾個(gè)botnav就可以在同一個(gè)頁面切換啦。
過渡動效
在寫項(xiàng)目時(shí)胧华,為了增加用戶體驗(yàn)感寄症,加上路由切換時(shí)的過渡動效是必不可少的,下面先看一下過度動效的效果展示:
<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中的一張圖片來直觀的解釋:
本項(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)行源碼的書寫,先放上效果圖诅炉。
我們先寫三個(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树肃,送人玫瑰,手留余香瀑罗,謝謝胸嘴!