成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

自己動手實(shí)現(xiàn)一個前端路由

psychola / 770人閱讀

摘要:單頁面應(yīng)用利用了動態(tài)變換網(wǎng)頁內(nèi)容避免了頁面重載路由則提供了瀏覽器地址變化網(wǎng)頁內(nèi)容也跟隨變化兩者結(jié)合起來則為我們提供了體驗(yàn)良好的單頁面應(yīng)用前端路由實(shí)現(xiàn)方式路由需要實(shí)現(xiàn)三個功能瀏覽器地址變化切換頁面點(diǎn)擊瀏覽器后退前進(jìn)按鈕,網(wǎng)頁內(nèi)容跟隨變化刷新瀏

單頁面應(yīng)用利用了JavaScript動態(tài)變換網(wǎng)頁內(nèi)容,避免了頁面重載;路由則提供了瀏覽器地址變化,網(wǎng)頁內(nèi)容也跟隨變化,兩者結(jié)合起來則為我們提供了體驗(yàn)良好的單頁面web應(yīng)用
前端路由實(shí)現(xiàn)方式

路由需要實(shí)現(xiàn)三個功能:

? ①瀏覽器地址變化,切換頁面;

? ②點(diǎn)擊瀏覽器【后退】、【前進(jìn)】按鈕,網(wǎng)頁內(nèi)容跟隨變化;

? ③刷新瀏覽器,網(wǎng)頁加載當(dāng)前路由對應(yīng)內(nèi)容

在單頁面web網(wǎng)頁中,單純的瀏覽器地址改變,網(wǎng)頁不會重載,如單純的hash網(wǎng)址改變網(wǎng)頁不會變化,因此我們的路由主要是通過監(jiān)聽事件,并利用js實(shí)現(xiàn)動態(tài)改變網(wǎng)頁內(nèi)容,有兩種實(shí)現(xiàn)方式:

hash路由: 監(jiān)聽瀏覽器地址hash值變化,執(zhí)行相應(yīng)的js切換網(wǎng)頁
history路由: 利用history API實(shí)現(xiàn)url地址改變,網(wǎng)頁內(nèi)容改變

hash路由

首先定義一個Router

class Router {
  constructor(obj) {
    // 路由模式
    this.mode = obj.mode
    // 配置路由
    this.routes = {
      "/index"                : "views/index/index",
      "/index/detail"         : "views/index/detail/detail",
      "/index/detail/more"    : "views/index/detail/more/more",
      "/subscribe"            : "views/subscribe/subscribe",
      "/proxy"                : "views/proxy/proxy",
      "/state"                : "views/state/stateDemo",
      "/state/sub"            : "views/state/components/subState",
      "/dom"                  : "views/visualDom/visualDom",
      "/error"                : "views/error/error"
    }
    this.init()
  }
}

路由初始化init()時監(jiān)聽load,hashchange兩個事件:

window.addEventListener("load", this.hashRefresh.bind(this), false);
window.addEventListener("hashchange", this.hashRefresh.bind(this), false);

瀏覽器地址hash值變化直接通過a標(biāo)簽鏈接實(shí)現(xiàn)


hash值變化后,回調(diào)方法:

/**
 * hash路由刷新執(zhí)行
 */
hashRefresh() {
  // 獲取當(dāng)前路徑,去掉查詢字符串,默認(rèn)"/index"
  var currentURL = location.hash.slice(1).split("?")[0] || "/index";
  this.name = this.routes[this.currentURL]
  this.controller(this.name)
}
/**
  * 組件控制器
  * @param {string} name 
  */
controller(name) {
  // 獲得相應(yīng)組件
  var Component = require("../" + name).default;
  // 判斷是否已經(jīng)配置掛載元素,默認(rèn)為$("#main")
  var controller = new Component($("#main"))
}

有位同學(xué)留言要實(shí)現(xiàn)路由懶加載,參考vue的實(shí)現(xiàn)方式,這里貼出來,希望大家多提意見:

  /**
   * 懶加載路由組件控制器
   * @param {string} name 
   */
  controller(name) {
    // import 函數(shù)會返回一個 Promise對象,屬于es7范疇,需要配合babel的syntax-dynamic-import插件使用
    var Component = ()=>import("../"+name);
    Component().then(resp=>{
      var controller = new resp.default($("#main"))
    })
  }

考慮到存在多級頁面嵌套路由的存在,需要對嵌套路由進(jìn)行處理:

直接子頁面路由時,按父路由到子路由的順序加載頁面

父頁面已經(jīng)加載,再加載子頁面時,父頁面保留,只加載子頁面

改造后的路由刷新方法為:

hashRefresh() {
  // 獲取當(dāng)前路徑,去掉查詢字符串,默認(rèn)"/index"
  var currentURL = location.hash.slice(1).split("?")[0] || "/index";  
  // 多級鏈接拆分為數(shù)組,遍歷依次加載
  this.currentURLlist = currentURL.slice(1).split("/")
  this.url = ""
  this.currentURLlist.forEach((item, index) => {
    // 導(dǎo)航菜單激活顯示
    if (index === 0) {
      this.navActive(item)
    }
    this.url += "/" + item
    this.name = this.routes[this.url]
    // 404頁面處理
    if (!this.name) {
      location.href = "#/error"
      return false
    }
    // 對于嵌套路由的處理
    if (this.oldURL && this.oldURL[0]==this.currentURLlist[0]) {
      this.handleSubRouter(item,index)
    } else {
      this.controller(this.name)
    }
  });
  // 記錄鏈接數(shù)組,后續(xù)處理子級組件
  this.oldURL = JSON.parse(JSON.stringify(this.currentURLlist))
}
/**
  * 處理嵌套路由
  * @param {string} item 鏈接list中當(dāng)前項(xiàng)
  * @param {number} index 鏈接list中當(dāng)前索引
  */
handleSubRouter(item,index){
  // 新路由是舊路由的子級
  if (this.oldURL.length < this.currentURLlist.length) {
    // 相同路由部分不重新加載
    if (item !== this.oldURL[index]) {
      this.controller(this.name)
    }
  }
  // 新路由是舊路由的父級
  if (this.oldURL.length > this.currentURLlist.length) {
    var len = Math.min(this.oldURL.length, this.currentURLlist.length)
    // 只重新加載最后一個路由
    if (index == len - 1) {
      this.controller(this.name)
    }
  }
}                

這樣,一個hash路由組件就實(shí)現(xiàn)了

使用時,只需new一個Router實(shí)例即可:new Router({mode:"hash"})

history 路由

window.history屬性指向 History 對象,是瀏覽器的一個屬性,表示當(dāng)前窗口的瀏覽歷史,History 對象保存了當(dāng)前窗口訪問過的所有頁面地址。更多了解History對象,可參考阮一峰老師的介紹: History 對象

webpack開發(fā)環(huán)境下,需要在devServer對象添加以下配置:

historyApiFallback: {
  rewrites: [
    { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, "index.html") },
  ],
}

history路由主要是通過history.pushState()方法向?yàn)g覽記錄中添加一條歷史記錄,并同時觸發(fā)js回調(diào)加載頁面

當(dāng)【前進(jìn)】、【后退】時,會觸發(fā)history.popstate 事件,加載history.state中存放的路徑

history路由實(shí)現(xiàn)與hash路由的步驟類似,由于需要配置路由模式切換,頁面中所有的a鏈接都采用了hash類型鏈接,history路由初始化時,需要攔截a標(biāo)簽的默認(rèn)跳轉(zhuǎn):

  /**
   * history模式劫持 a鏈接
   */
  bindLink() {
    $("#nav").on("click", "a.nav-item", this.handleLink.bind(this))
  }
 /**
   * history 處理a鏈接
   * @param  e 當(dāng)前對象Event
   */
  handleLink(e) {
    e.preventDefault();
    // 獲取元素路徑屬性
    let href = $(e.target).attr("href")
    // 對非路由鏈接直接跳轉(zhuǎn)
    if (href.slice(0, 1) !== "#") {
      window.location.href = href
    } else {
      let path = href.slice(1)
      history.pushState({
        path: path
      }, null, path)
      // 加載相應(yīng)頁面
      this.loadView(path.split("?")[0])
    }
  }

history路由初始化需要綁定load、popstate事件

this.bindLink()
window.addEventListener("load", this.loadView.bind(this, location.pathname));
window.addEventListener("popstate", this.historyRefresh.bind(this));

瀏覽是【前進(jìn)】或【后退】時,觸發(fā)popstate事件,執(zhí)行回調(diào)函數(shù)

/**
  * history模式刷新頁面
  * @param  e  當(dāng)前對象Event
  */
historyRefresh(e) {
  const state = e.state || {}
  const path = state.path.split("?")[0] || null
  if (path) {
    this.loadView(path)
  }
}

history路由模式首次加載頁面時,可以默認(rèn)一個頁面,這時可以用history.replaceState方法

if (this.mode === "history" && currentURL === "/") {
  history.replaceState({path: "/"}, null, "/")
  currentURL = "/index"
}

對于404頁面的處理,也類似

history.replaceState({path: "/error"}, null, "/error")
this.loadView("/error")

點(diǎn)擊預(yù)覽

更多源碼請?jiān)L問Github

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/108677.html

相關(guān)文章

  • 自己動手實(shí)現(xiàn)一個前端路由

    摘要:監(jiān)聽的變動省略其他代碼省略其他代碼這樣,我們就初步實(shí)現(xiàn)了一個路由,那么接下來,我們來看看路由怎么實(shí)現(xiàn)。 前言 用過現(xiàn)代前端框架的同學(xué),對前端路由一定不陌生, vue, react, angular 都有自己的 router, 那么你對 router 的工作原理了解嗎?如果還不了解, 那么請跟我一起來手寫一個簡單的前端路由, 順便了解一下. 實(shí)現(xiàn)路由的2種方式 hash模式 histo...

    longshengwang 評論0 收藏0
  • webpack+vue項(xiàng)目實(shí)戰(zhàn)(三,配置功能操作頁和組件的按需加載)

    摘要:但是實(shí)際上,回款管理和開票管理的組件文件也是加載了。所以下面引用按需加載來處理。是不是小很多了,然后和是按需加載的,就是需要的時候才加載。 1.前言 上篇文章(webpack+vue項(xiàng)目實(shí)戰(zhàn)(二,開發(fā)管理系統(tǒng)主頁面)),實(shí)現(xiàn)了,側(cè)邊欄的一個操作,點(diǎn)擊側(cè)邊欄的一些操作,最重要的就是路由的切換??戳松弦黄幕锇橐膊浑y發(fā)現(xiàn),除了點(diǎn)擊側(cè)邊欄‘首頁’之外,點(diǎn)擊其它的都是白色的一片。原因我想大家都...

    endless_road 評論0 收藏0
  • 記一次vue仿網(wǎng)易云音樂的單頁面應(yīng)用

    摘要:說明一直想做一個基于的項(xiàng)目但是因?yàn)轫?xiàng)目往往要涉及到后端的知識不會后端真的苦所以就沒有一直真正的動手去做一個項(xiàng)目。直到發(fā)現(xiàn)上有網(wǎng)易云音樂的才開始動手去做。僅僅完成了首頁登入,歌單,歌曲列表頁。 說明 一直想做一個基于VUE的項(xiàng)目,但是因?yàn)轫?xiàng)目往往要涉及到后端的知識(不會后端真的苦),所以就沒有一直真正的動手去做一個項(xiàng)目。直到發(fā)現(xiàn)GitHub上有網(wǎng)易云音樂的api NeteaseCloud...

    hqman 評論0 收藏0
  • 使用next.js結(jié)合GITHUB ISSUE實(shí)現(xiàn)博客。

    摘要:而更多的應(yīng)用采用的是簡單的同構(gòu)實(shí)現(xiàn)。請使用動態(tài)路由進(jìn)行處理。后來用布署頻繁調(diào)試,發(fā)現(xiàn)自定義在上并不能用,看建議使用動態(tài)路由。如果要取消這種行為可以使用方法。利用動態(tài)實(shí)現(xiàn)代碼塊切片。如果使用的話,建議使用動態(tài)路由去做布署啦。 使用next.js結(jié)合GITHUB ISSUE實(shí)現(xiàn)博客。 起因 。。。。起因是因?yàn)樵谀尘W(wǎng)站看到有一些類似實(shí)現(xiàn)。打算自己也做個side-project。 習(xí)慣性的對自...

    SillyMonkey 評論0 收藏0
  • JS或Jquery

    摘要:大潮來襲前端開發(fā)能做些什么去年谷歌和火狐針對提出了的標(biāo)準(zhǔn),顧名思義,即的體驗(yàn)方式,我們可以戴著頭顯享受沉浸式的網(wǎng)頁,新的標(biāo)準(zhǔn)讓我們可以使用語言來開發(fā)。 VR 大潮來襲 --- 前端開發(fā)能做些什么 去年谷歌和火狐針對 WebVR 提出了 WebVR API 的標(biāo)準(zhǔn),顧名思義,WebVR 即 web + VR 的體驗(yàn)方式,我們可以戴著頭顯享受沉浸式的網(wǎng)頁,新的 API 標(biāo)準(zhǔn)讓我們可以使用 ...

    CatalpaFlat 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<