92国产精品视频_亚洲a级在线观看_国产精品电影观看_国产精品免费观看在线_精品伊人久久97_亚洲人成在线观_尤物九九久久国产精品的特点_成人激情在线播放_成人黄色大片在线免费观看_亚洲成人精品久久久_久久免费视频在线观看_久久精品国产一区_国产一区二区三区18_亚洲欧美中文字幕在线一区_日韩美女中文字幕_日韩视频免费在线

VueRouter的實現原理——封裝簡易功能的VueRouter

2021-4-27    前端達人

Hash模式和History模式的區別

不管哪種模式,前端路由都是客戶端路由的實現方式,也就是當路徑發生變化時,不會向服務器發送請求,是利用js監視路徑的變化。然后根據不同的地址渲染不同的內容,如果需要服務器內容,會發送Ajax請求來獲取。

表現形式的區別

  • hash 模式
    https://music.163.com/#/discover/toplist 地址中會存在 # 號
  • history 模式
    https://music.163.com/discover/toplist 地址中沒有# 類似于普通的地址,但是需要服務端配置支持

原理的區別

  • hash 模式是基于錨點, 以及onhashchange 事件
  • history 模式是基于 HTML5 中的 History API
    • history.pushState() IE10 以后才支持
    • history.replaceState() \

History 模式的使用

  • History 需要服務器的支持
  • 單頁應用中,如果刷新頁面,會向服務器發起請求,而服務器不存在這樣的地址就會返回找不到該頁面從而出現404
  • 在服務端應該除了靜態資源外都返回單頁應用的 index.html

node 環境下支持 history

在 node 環境下,啟用對history模式的支持可以通過 connect-history-api-fallback 這個中間件來完成

// 導入處理 history 模式的模塊 const history = require('connect-history-api-fallback') // 導入 express const express = require('express') const app = express() // 注冊處理 history 模式的中間件 app.use(history()) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Nginx 下支持 history

  • 從官網下載 nginx 的壓縮包
  • 把壓縮包解壓到 c 盤根目錄,c:\nginx-1.18.0 文件夾
  • 修改 conf\nginx.conf 文件

運行nginx服務器基本指令

啟動
start nginx
重啟
nginx -s reload
停止
nginx -s stop

  • 修改 conf\nginx.conf 文件
location / { root  html; index  index.html index.htm; #新添加內容
     #嘗試讀取$uri(當前請求的路徑),如果讀取不到讀取$uri/這個文件夾下的首頁
     #如果都獲取不到返回根目錄中的 index.html
     try_files $uri $uri/ /index.html; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

VueRouter 兩種模式的實現原理

Hash 模式

  • URL 中 # 后面的內容作為路徑地址
  • 監聽 hashchange 事件
  • 根據當前路由地址找到對應組件重新渲染

History 模式

  • 通過 history.pushState() 方法改變地址欄
  • 監聽 popstate 事件
  • 根據當前路由地址找到對應組件重新渲染

實現思路

在這里插入圖片描述
從上圖,可以大致了解一下 VueRouter 這個類中的結構:
上半部分是屬性,下半部分是方法,其中+ 是實例方法,- 是靜態方法。
install 是用來實現Vue.use 插件機制的方法。

VueRouter-install 方法實現

要實現install方法,首先先分析一下該方法要做的事情:

  1. 判斷當前插件是否已經被安裝
  2. 把Vue構造函數記錄到全局變量
  3. 把創建Vue實例時候傳入的router對象注入到所有的Vue實例上
 let _Vue; export default class VueRouter { static install(Vue) { // 1. 判斷當前插件是否已經被安裝 if(VueRouter.install.installed) return VueRouter.install.installed = true // 2. 把Vue構造函數記錄到全局變量 _Vue = Vue // 3. 把創建Vue實例時候傳入的router對象注入到所有的Vue實例上 // 利用混入讓所有的vue實例加載router _Vue.mixin({ beforeCreate(){ // this.$options.name用來獲取vue實例 data以外的屬性 // new Vue( { router } ) if(this.$options.router) { _Vue.prototype.$router = this.$options.router } } }) } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

添加 VueRouter 的constructor

VueRouter 的構造函數要初始化三個屬性,分別是: options、data、routeMap。

  • options 是路由的構造配置對象
  • data 應該是一個響應式的對象,其中有一個屬性 current 用來記錄當前我們的路由地址,這里我們該如何才能創建一個響應式的對象呢?可以使用Vue的observable方法
  • routeMap 中記錄了 options里的rules,rules解析出來 會以鍵值對的形式存在 routeMap中 ,key 就是路由地址,value 就是路由組件
constructor(options){ this.options = options this.data = _Vue.observable({ current:'/' }) this.routeMap = {} } 
  • 1
  • 2
  • 3
  • 4
  • 5

createRouterMap

接下來我們來實現VueRouter類中 createRouterMap 這個方法,它的作用就是把 options 中rules 路由規則解析出來以鍵值對的形式存儲在routeMap上。

 createRouterMap() { this.options.rules.forEach(route => this.routeMap[route.path] = route.component) } 
  • 1
  • 2
  • 3

initComponents

下一步,來創建initComponents 方法,這個方法里我們要創建兩個組件。分別是:RouterLink 和 RouterView

創建RouterLink 組件

let _Vue; export default class VueRouter { static install(Vue) { // 1. 判斷當前插件是否已經被安裝 if (VueRouter.install.installed) return VueRouter.install.installed = true // 2. 把Vue構造函數記錄到全局變量 _Vue = Vue // 3. 把創建Vue實例時候傳入的router對象注入到所有的Vue實例上 // 利用混入讓所有的vue實例加載router _Vue.mixin({ beforeCreate() { // this.$options.name用來獲取vue實例 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) { // 創建RouterLink組件 Vue.component('router-link', { props: { 'to': { type: String } }, template: `<a :href="to"><slot></slot></a>` }) } init() { this.createRouterMap() this.initComponents(_Vue) } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

用自己的VueRouter 替換掉官方的運行后,發現報錯
在這里插入圖片描述
報錯的意思是,運行時版本的Vue 不支持 tempalte 模板,需要打包的時候提前編譯。
如果要讓我們的template被支持可以使用完整版的Vue,完整包包含運行時和編譯器,體積比運行時版本大10k左右,程序運行的時候把模板轉換成render函數
@vue/cli 自動安裝的就是 運行時版本

報錯的解決

第一種方案——引入完整版Vue,可以在vue.config.js中 加入配置

module.exports = { runtimeCompiler: true } 
  • 1
  • 2
  • 3

第二種方案——使用render函數替換掉tempalte

 render(h) { return h('a', { attrs: { href: this.to } }, [this.$slots.default]) } // template: `<a :href="to"><slot></slot></a>` 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

創建RouterView組件

 // 記錄一下this let self = this Vue.component('router-view',{ render(h){ // routeMap以key value形式記錄了path和component // data.current 記錄了當前頁面的path return h(self.routeMap[self.data.current]) } }) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在routerlink中添加點擊事件,修改地址

為了能夠讓鏈接成功完成跳轉展示組件,我們需要對routerlink中的a標簽添加點擊事件

并且要在點擊的時候,把最新的path更新到router實例的current上.

我們借助于history的pushState方法 該方法會修改瀏覽器地址欄中的地址,但不會向服務器發起請求,并且還可以將新地址記錄在歷史中

 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) // 把點擊的鏈接地址 更新到 current 上 this.$router.data.current = this.to
                    e.preventDefault() } } // template: `<a :href="to"><slot></slot></a>` }) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

initEvent

現在功能基本上已經差不多了,但是還存在一個小問題,就是當我們點擊瀏覽器的前進或者后退按鈕的時候,組件不能實現切換展示,主要思路就是通過添加popstate監聽地址變化,下面我們來完善該功能

 initEvent(){ // window.addEventListener("popstate",()=>{ this.data.current = window.location.pathname }) } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

完整代碼

let _Vue; export default class VueRouter { static install(Vue) { // 1. 判斷當前插件是否已經被安裝 if (VueRouter.install.installed) return VueRouter.install.installed = true // 2. 把Vue構造函數記錄到全局變量 _Vue = Vue // 3. 把創建Vue實例時候傳入的router對象注入到所有的Vue實例上 // 利用混入讓所有的vue實例加載router _Vue.mixin({ beforeCreate() { // this.$options.name用來獲取vue實例 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) { // 創建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) // 把點擊的鏈接地址 更新到 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 記錄了當前頁面的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 }) } }

轉自:csdn 作者:Holyforsaken_FHC


藍藍設計m.skdbbs.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務

日歷

鏈接

個人資料

藍藍設計的小編 http://m.skdbbs.com

存檔

92国产精品视频_亚洲a级在线观看_国产精品电影观看_国产精品免费观看在线_精品伊人久久97_亚洲人成在线观_尤物九九久久国产精品的特点_成人激情在线播放_成人黄色大片在线免费观看_亚洲成人精品久久久_久久免费视频在线观看_久久精品国产一区_国产一区二区三区18_亚洲欧美中文字幕在线一区_日韩美女中文字幕_日韩视频免费在线
妖精视频成人观看www| 日韩欧美国产精品一区| 精品一区久久久| 亚洲欧美日韩国产成人综合一二三区| 欧美一区二区三区四区夜夜大片| 欧美色视频日本高清在线观看| av不卡在线观看| 国产私拍福利精品视频二区| 日本大胆欧美| 宅男在线国产精品| 国产精品久久久久久久久免费桃花| 欧美日韩在线播放三区| 懂色av一区| 一区中文字幕| 亚洲精品1234| 亚洲精品美女久久久| 一本大道av一区二区在线播放| 亚洲电影第1页| 欧美壮男野外gaytube| 亚洲人成网站999久久久综合| 日日欢夜夜爽一区| 国产精品女主播av| 欧美va在线播放| 9191在线播放| 欧美爱爱网站| 国产精品一区二区电影| gogogo高清在线观看免费完整版| 国产高清不卡一区二区| 亚洲激情中文字幕| 国产日产久久高清欧美一区| 69xxx在线| 国产清纯在线一区二区www| 在线观看av不卡| 午夜免费播放观看在线视频| 日韩一区二区免费高清| 亚洲性av网站| 精品一区在线看| 亚洲人成网7777777国产| 午夜在线视频观看日韩17c| 成人午夜国产| 精品欧美国产一区二区三区不卡| 国产精品99久久久久久动医院| 懂色av一区二区三区在线播放| 最新日韩三级| 在线电影福利片| 麻豆影院在线观看| 国产精品欧美在线观看| 国产成人免费在线观看不卡| 精品1区2区在线观看| 国产盗摄在线观看| 久久久不卡网国产精品二区| 国产精品一区二区免费福利视频| 欧美色播在线播放| 国产第一页在线视频| 色哟哟亚洲精品一区二区| 国产一区精品视频| 蜜桃在线一区二区三区精品| 色偷偷av亚洲男人的天堂| 91成人精品观看| 97在线观看视频| jizz在线观看中文| 91麻豆成人久久精品二区三区| 亚洲美女av黄| 国产亚洲一二三区| 精品欧美一区二区精品久久| av网站在线免费观看| 久久久综合香蕉尹人综合网| 精品电影一区二区| 亚洲淫片在线视频| 国产精品久久777777毛茸茸| 国产综合在线看| 亚洲欧洲一区二区三区| 欧美a级成人淫片免费看| 成人av在线播放网站| 欧美剧情电影在线观看完整版免费励志电影| 亚洲a∨精品一区二区三区导航| 粉嫩高潮美女一区二区三区| 成人av在线播放| 韩国国内大量揄拍精品视频| 青青久久aⅴ北条麻妃| 91精品国产调教在线观看| 午夜精品区一区二区三| 国内视频一区| 狠狠一区二区三区| 欧美r级在线观看| 国产精品高清网站| 羞羞答答一区二区| 亚洲精品ww久久久久久p站| 91麻豆国产福利在线观看宅福利| 亚洲女成人图区| 2024国产精品视频| 日韩av在线看| 99精品美女视频在线观看热舞| 国产福利视频一区| 亚洲国内自拍| 国产精品va| 麻豆传媒视频在线观看免费| 在线一区二区三区四区| 丁香高清在线观看完整电影视频| 久久久精品亚洲| 国产精品欧美一区喷水| 欧美美女一区| 黄色网址在线免费播放| 夜色激情一区二区| 97精品国产97久久久久久春色| 午夜久久久久久| 亚洲成a人片在线不卡一二三区| 色戒汤唯在线观看| 中日韩视频在线观看| 视频一区免费在线观看| 999在线精品| 99v久久综合狠狠综合久久| 亚洲人成欧美中文字幕| 免费成人网www| 国产精品三级视频| 欧美国产日韩xxxxx| 国产精品三区四区| 欧美日韩一区在线| 色婷婷狠狠五月综合天色拍| 视频一区二区三区在线| 久久尤物电影视频在线观看| 日韩成人亚洲| 91情侣偷在线精品国产| 亚洲另类av| 九色91在线| 久久久这里只有精品视频| julia一区二区中文久久94| 一区二区欧美在线| 欧美亚洲网站| 国产欧美一级| 青青草原综合久久大伊人精品优势| 中文字幕精品影院| 精品国产欧美一区二区三区成人| 亚洲欧美日韩国产另类专区| 亚洲欧洲美洲国产香蕉| 精品中文av资源站在线观看| 丁香花电影在线观看完整版| 不卡的av网站| 亚洲精蜜桃久在线| 亚洲人体影院| 99久久99久久综合| 日韩理论片av| 色狠狠一区二区三区香蕉| 欧美乱人伦中文字幕在线| 欧美日韩www| 99久久久久免费精品国产| 成人免费在线视频网| 在线观看中文| 91视频免费在线| 久久久999国产| 欧美性猛交xxxx免费看久久久| www欧美在线观看| 亚洲女人被黑人巨大进入al| 欧美xnxx| caoporn国产精品免费视频| 欧美在线一级视频| 欧美一级免费大片| 亚洲淫性视频| 国产色综合一区二区三区| 午夜在线激情影院| 蜜桃av噜噜一区| 水蜜桃亚洲精品| 国产在线88av| 国产精品一区二区三区四区五区|