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


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

日歷

鏈接

個人資料

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

存檔

92国产精品视频_亚洲a级在线观看_国产精品电影观看_国产精品免费观看在线_精品伊人久久97_亚洲人成在线观_尤物九九久久国产精品的特点_成人激情在线播放_成人黄色大片在线免费观看_亚洲成人精品久久久_久久免费视频在线观看_久久精品国产一区_国产一区二区三区18_亚洲欧美中文字幕在线一区_日韩美女中文字幕_日韩视频免费在线
欧美寡妇偷汉性猛交| 国产精品大陆在线观看| 欧美巨乳在线观看| 中文字幕亚洲一区二区三区五十路| 欧美成人性生活| 一区二区三区www| 欧美精品www| 最近中文字幕mv在线一区二区三区四区| 91av在线影院| 黑人巨大精品欧美一区二区一视频| 亚洲国产欧美自拍| 国产欧美日韩专区发布| 在线免费观看羞羞视频一区二区| 伊人伊成久久人综合网小说| 久久九九国产精品怡红院| 欧美激情喷水视频| 日本久久久a级免费| 亚洲色图五月天| 亚洲一区二区三区四区在线播放| 久久久久久久999| 欧美久久精品午夜青青大伊人| 久久精品91久久久久久再现| 91a在线视频| 福利视频第一区| 亚洲成人网av| 亚洲精品在线视频| 欧美大尺度激情区在线播放| 国产欧美一区二区三区在线| 国产精品久久77777| 国产精品美女久久久久av超清| 理论片在线不卡免费观看| 国产亚洲视频在线观看| 欧美精品18videosex性欧美| 欧美激情影音先锋| 国产suv精品一区二区三区88区| 日韩成人激情影院| 亚洲免费中文字幕| 亚洲国产精品va在线看黑人动漫| 亚洲人成在线观| 欧美视频在线视频| 成人国产精品久久久久久亚洲| 亚洲xxxx视频| 91成人免费观看网站| 欧美在线观看一区二区三区| 日韩国产欧美区| 国产精品青青在线观看爽香蕉| 亚洲三级 欧美三级| 韩国精品久久久999| 日韩精品免费在线播放| 中文字幕成人在线| 欧美一级淫片丝袜脚交| 深夜福利国产精品| 亚洲第一视频网站| 亚洲色图激情小说| 日本19禁啪啪免费观看www| 97在线视频免费观看| 黑人狂躁日本妞一区二区三区| 国产精品视频一区二区高潮| 成人精品久久一区二区三区| 北条麻妃在线一区二区| 国色天香2019中文字幕在线观看| 亚洲精品mp4| 国产日韩在线视频| 欧美日韩成人黄色| 欧美乱人伦中文字幕在线| 91网站在线免费观看| 国产视频精品免费播放| 久久亚洲精品中文字幕冲田杏梨| 日韩av电影在线播放| 538国产精品一区二区免费视频| 精品国产乱码久久久久久天美| 国产91成人video| 国产欧美精品久久久| 97视频在线观看视频免费视频| 久久久午夜视频| 午夜精品免费视频| 久久久噜噜噜久噜久久| 精品视频9999| 在线播放日韩av| 国产精品久久久久久久电影| 91精品免费看| 国产亚洲aⅴaaaaaa毛片| 这里只有精品在线观看| 久久精品99国产精品酒店日本| 久久高清视频免费| 国产亚洲欧洲在线| 日韩av免费在线播放| 91免费看国产| 亚洲精品一二区| 亚洲第一福利网| 国产精品成人观看视频国产奇米| 日韩成人av在线| 日本欧美黄网站| 国产精品久久久久久久久久免费| 欧美日韩高清区| 亚洲精品白浆高清久久久久久| 欧美激情精品久久久久| 在线精品视频视频中文字幕| 91综合免费在线| 精品久久久久久国产91| 中文字幕在线精品| 91亚洲午夜在线| 97国产真实伦对白精彩视频8| 成人激情春色网| 精品久久香蕉国产线看观看亚洲| www国产亚洲精品久久网站| 亚洲国产日韩精品在线| 亚洲成人久久一区| 精品国产欧美一区二区三区成人| 午夜精品99久久免费| 欧美激情视频播放| 国产精品一区二区av影院萌芽| 日韩电影大全免费观看2023年上| 成人羞羞国产免费| 欧美激情日韩图片| 91网站在线免费观看| 欧美一级淫片videoshd| 亚洲精品久久久久久下一站| 国语自产精品视频在免费| 亚洲精美色品网站| 日韩欧美在线视频日韩欧美在线视频| 久久精品91久久香蕉加勒比| 欧美日韩在线观看视频小说| 国语自产精品视频在线看抢先版图片| 国产欧美婷婷中文| 91国产在线精品| 国产精品免费一区二区三区都可以| 亚洲xxxxx| 亚洲大尺度美女在线| 在线亚洲男人天堂| 中文字幕日韩专区| 亚洲精品在线91| 国产精品美女在线观看| 国产欧美精品一区二区三区介绍| 国产精品日本精品| 精品欧美一区二区三区| 俺去了亚洲欧美日韩| 欧美视频13p| 亚洲人成电影网| 中文精品99久久国产香蕉| yellow中文字幕久久| 国产午夜精品全部视频在线播放| 国产精品视频免费观看www| 亚洲欧美国产制服动漫| 国模私拍视频一区| 国产成人精品综合久久久| 久久99精品久久久久久琪琪| 韩剧1988在线观看免费完整版| 中文日韩在线观看| 成人黄色av网站| 亚洲午夜国产成人av电影男同| 欧美成人免费观看| 国产精品96久久久久久又黄又硬| 国产精品美女午夜av| 亚洲欧美变态国产另类| 91亚洲精品一区| 色爱精品视频一区| 欧美性受xxxx黑人猛交| 久久久女人电视剧免费播放下载| 91久久久精品| 国产精品视频26uuu| 亚洲欧美日韩综合| 欧美亚洲一区在线| 欧美日韩一区二区免费视频|