2021-4-27 前端達(dá)人
不管哪種模式,前端路由都是客戶端路由的實(shí)現(xiàn)方式,也就是當(dāng)路徑發(fā)生變化時(shí),不會(huì)向服務(wù)器發(fā)送請(qǐng)求,是利用js監(jiān)視路徑的變化。然后根據(jù)不同的地址渲染不同的內(nèi)容,如果需要服務(wù)器內(nèi)容,會(huì)發(fā)送Ajax請(qǐng)求來獲取。
https://music.163.com/#/discover/toplist
地址中會(huì)存在 # 號(hào)
https://music.163.com/discover/toplist
地址中沒有# 類似于普通的地址,但是需要服務(wù)端配置支持
在 node 環(huán)境下,啟用對(duì)history模式的支持可以通過 connect-history-api-fallback 這個(gè)中間件來完成
// 導(dǎo)入處理 history 模式的模塊 const history = require('connect-history-api-fallback') // 導(dǎo)入 express const express = require('express') const app = express() // 注冊(cè)處理 history 模式的中間件 app.use(history())
運(yùn)行nginx服務(wù)器基本指令
啟動(dòng)
start nginx
重啟
nginx -s reload
停止
nginx -s stop
location / { root html; index index.html index.htm; #新添加內(nèi)容
#嘗試讀取$uri(當(dāng)前請(qǐng)求的路徑),如果讀取不到讀取$uri/這個(gè)文件夾下的首頁
#如果都獲取不到返回根目錄中的 index.html
try_files $uri $uri/ /index.html; }
從上圖,可以大致了解一下 VueRouter 這個(gè)類中的結(jié)構(gòu):
上半部分是屬性,下半部分是方法,其中+ 是實(shí)例方法,- 是靜態(tài)方法。
install 是用來實(shí)現(xiàn)Vue.use 插件機(jī)制的方法。
要實(shí)現(xiàn)install方法,首先先分析一下該方法要做的事情:
let _Vue; export default class VueRouter { static install(Vue) { // 1. 判斷當(dāng)前插件是否已經(jīng)被安裝 if(VueRouter.install.installed) return VueRouter.install.installed = true // 2. 把Vue構(gòu)造函數(shù)記錄到全局變量 _Vue = Vue // 3. 把創(chuàng)建Vue實(shí)例時(shí)候傳入的router對(duì)象注入到所有的Vue實(shí)例上 // 利用混入讓所有的vue實(shí)例加載router _Vue.mixin({ beforeCreate(){ // this.$options.name用來獲取vue實(shí)例 data以外的屬性 // new Vue( { router } ) if(this.$options.router) { _Vue.prototype.$router = this.$options.router } } }) } }
VueRouter 的構(gòu)造函數(shù)要初始化三個(gè)屬性,分別是: options、data、routeMap。
constructor(options){ this.options = options this.data = _Vue.observable({ current:'/' }) this.routeMap = {} }
接下來我們來實(shí)現(xiàn)VueRouter類中 createRouterMap 這個(gè)方法,它的作用就是把 options 中rules 路由規(guī)則解析出來以鍵值對(duì)的形式存儲(chǔ)在routeMap上。
createRouterMap() { this.options.rules.forEach(route => this.routeMap[route.path] = route.component) }
下一步,來創(chuàng)建initComponents 方法,這個(gè)方法里我們要?jiǎng)?chuàng)建兩個(gè)組件。分別是:RouterLink 和 RouterView
let _Vue; export default class VueRouter { static install(Vue) { // 1. 判斷當(dāng)前插件是否已經(jīng)被安裝 if (VueRouter.install.installed) return VueRouter.install.installed = true // 2. 把Vue構(gòu)造函數(shù)記錄到全局變量 _Vue = Vue // 3. 把創(chuàng)建Vue實(shí)例時(shí)候傳入的router對(duì)象注入到所有的Vue實(shí)例上 // 利用混入讓所有的vue實(shí)例加載router _Vue.mixin({ beforeCreate() { // this.$options.name用來獲取vue實(shí)例 data以外的屬性 // new Vue( { router } ) if (this.$options.router) { _Vue.prototype.$router = this.$options.router this.$options.router.init() } } }) } constructor(options) { this.options = options this.routeMap = {} this.data = _Vue.observable({ current: '/' }) } createRouterMap() { this.options.routes.forEach(route => this.routeMap[route.path] = route.component) } initComponents(Vue) { // 創(chuàng)建RouterLink組件 Vue.component('router-link', { props: { 'to': { type: String } }, template: `<a :href="to"><slot></slot></a>` }) } init() { this.createRouterMap() this.initComponents(_Vue) } }
用自己的VueRouter 替換掉官方的運(yùn)行后,發(fā)現(xiàn)報(bào)錯(cuò)
報(bào)錯(cuò)的意思是,運(yùn)行時(shí)版本的Vue 不支持 tempalte 模板,需要打包的時(shí)候提前編譯。
如果要讓我們的template被支持可以使用完整版的Vue,完整包包含運(yùn)行時(shí)和編譯器,體積比運(yùn)行時(shí)版本大10k左右,程序運(yùn)行的時(shí)候把模板轉(zhuǎn)換成render函數(shù)
@vue/cli 自動(dòng)安裝的就是 運(yùn)行時(shí)版本
第一種方案——引入完整版Vue,可以在vue.config.js中 加入配置
module.exports = { runtimeCompiler: true }
第二種方案——使用render函數(shù)替換掉tempalte
render(h) { return h('a', { attrs: { href: this.to } }, [this.$slots.default]) } // template: `<a :href="to"><slot></slot></a>`
// 記錄一下this let self = this Vue.component('router-view',{ render(h){ // routeMap以key value形式記錄了path和component // data.current 記錄了當(dāng)前頁面的path return h(self.routeMap[self.data.current]) } })
為了能夠讓鏈接成功完成跳轉(zhuǎn)展示組件,我們需要對(duì)routerlink中的a標(biāo)簽添加點(diǎn)擊事件
并且要在點(diǎn)擊的時(shí)候,把最新的path更新到router實(shí)例的current上.
我們借助于history的pushState方法 該方法會(huì)修改瀏覽器地址欄中的地址,但不會(huì)向服務(wù)器發(fā)起請(qǐng)求,并且還可以將新地址記錄在歷史中
Vue.component('router-link', { props: { 'to': { type: String } }, render(h) { return h('a', { attrs: { href: this.to }, on: { click: this.clickHandle } }, [this.$slots.default]) }, methods: { clickHandle(e) { history.pushState({}, "", this.to) // 把點(diǎn)擊的鏈接地址 更新到 current 上 this.$router.data.current = this.to
e.preventDefault() } } // template: `<a :href="to"><slot></slot></a>` })
現(xiàn)在功能基本上已經(jīng)差不多了,但是還存在一個(gè)小問題,就是當(dāng)我們點(diǎn)擊瀏覽器的前進(jìn)或者后退按鈕的時(shí)候,組件不能實(shí)現(xiàn)切換展示,主要思路就是通過添加popstate監(jiān)聽地址變化,下面我們來完善該功能
initEvent(){ // window.addEventListener("popstate",()=>{ this.data.current = window.location.pathname }) }
完整代碼
let _Vue; export default class VueRouter { static install(Vue) { // 1. 判斷當(dāng)前插件是否已經(jīng)被安裝 if (VueRouter.install.installed) return VueRouter.install.installed = true // 2. 把Vue構(gòu)造函數(shù)記錄到全局變量 _Vue = Vue // 3. 把創(chuàng)建Vue實(shí)例時(shí)候傳入的router對(duì)象注入到所有的Vue實(shí)例上 // 利用混入讓所有的vue實(shí)例加載router _Vue.mixin({ beforeCreate() { // this.$options.name用來獲取vue實(shí)例 data以外的屬性 // new Vue( { router } ) if (this.$options.router) { _Vue.prototype.$router = this.$options.router console.log(this.$options.router.init); this.$options.router.init() } } }) } constructor(options) { this.options = options this.routeMap = {} this.data = _Vue.observable({ current: '/' }) } createRouterMap() { this.options.routes.forEach(route => this.routeMap[route.path] = route.component) } initComponents(Vue) { // 創(chuàng)建RouterLink組件 Vue.component('router-link', { props: { 'to': { type: String } }, render(h) { return h('a', { attrs: { href: this.to }, on: { click: this.clickHandle } }, [this.$slots.default]) }, methods: { clickHandle(e) { history.pushState({}, "", this.to) // 把點(diǎn)擊的鏈接地址 更新到 current 上 this.$router.data.current = this.to
e.preventDefault() } } // template: `<a :href="to"><slot></slot></a>` }) let self = this Vue.component('router-view', { render(h) { // routeMap以key value形式記錄了path和component // data.current 記錄了當(dāng)前頁面的path return h(self.routeMap[self.data.current]) } }) } init() { this.createRouterMap() this.initComponents(_Vue) this.initEvent() } initEvent() { // window.addEventListener("popstate", () => { this.data.current = window.location.pathname }) } }
轉(zhuǎn)自:csdn 作者:Holyforsaken_FHC
藍(lán)藍(lán)設(shè)計(jì)( www.yvirxh.cn )是一家專注而深入的界面設(shè)計(jì)公司,為期望卓越的國(guó)內(nèi)外企業(yè)提供卓越的UI界面設(shè)計(jì)、BS界面設(shè)計(jì) 、 cs界面設(shè)計(jì) 、 ipad界面設(shè)計(jì) 、 包裝設(shè)計(jì) 、 圖標(biāo)定制 、 用戶體驗(yàn) 、交互設(shè)計(jì)、 網(wǎng)站建設(shè) 、平面設(shè)計(jì)服務(wù)
藍(lán)藍(lán)設(shè)計(jì)的小編 http://www.yvirxh.cn