一区二区日本_久久久久久久国产精品_无码国模国产在线观看_久久99深爱久久99精品_亚洲一区二区三区四区五区午夜_日本在线观看一区二区

自己動(dòng)手實(shí)現(xiàn)一個(gè)前端路由,自己動(dòng)手實(shí)現(xiàn)路由

前前言

最近工作比較忙,寫的比較慢,當(dāng)我寫完這一篇準(zhǔn)備發(fā)布的時(shí)候,發(fā)現(xiàn)掘金剛好也有一篇關(guān)于前端路由的,而且寫的比我詳細(xì),不過(guò)辛辛苦苦寫的總不能刪掉吧,再說(shuō)我的路由風(fēng)格是純個(gè)人思路實(shí)現(xiàn)的,所以還是硬著頭皮發(fā)了哈。愛(ài)掏網(wǎng) - it200.com

前言

用過(guò)現(xiàn)代前端框架的同學(xué),對(duì)前端路由一定不陌生, vue, react, angular 都有自己的 router, 那么你對(duì) router 的工作原理了解嗎? 如果還不了解, 那么請(qǐng)跟我一起來(lái)手寫一個(gè)簡(jiǎn)單的前端路由, 順便了解一下.

實(shí)現(xiàn)路由的2種方式

  1. hash模式
  2. history模式

缺點(diǎn):

hash:丑(地址欄要多一個(gè)#), 某些特殊場(chǎng)景有坑 ,如微信支付回調(diào)

history: 兼容性較差, 直接訪問(wèn)會(huì)400 ,除非后端或者服務(wù)器有做處理

基本原理

hash是基于 監(jiān)聽(tīng) hashchange 事件實(shí)現(xiàn)的,history 是基于 pushState 和 popState,

實(shí)現(xiàn)

由于history兼容性較差,而且實(shí)現(xiàn)方式基本沒(méi)多大區(qū)別,本文就以hash模式來(lái)實(shí)現(xiàn),history的實(shí)現(xiàn)方式只實(shí)現(xiàn)不同的部分。愛(ài)掏網(wǎng) - it200.com

html>
head>
    meta charset="UTF-8">
    title>Documenttitle>
head>
body>
input type="button" onclick="hashPush('index')" value="goto index">
body>
script>
    // 頁(yè)面跳轉(zhuǎn)
    function hashPush(url) {
        location.hash = "#" + url
    }

    // 監(jiān)聽(tīng)hash的變動(dòng)
    window.addEventListener('hashchange', function (e) {
        console.log('當(dāng)前的hash地址', location.hash.slice(1) || "/")
    })
script>
html>

以上就是hash模式的最簡(jiǎn)單實(shí)現(xiàn),查看控制臺(tái),可以看到不管是點(diǎn)擊跳轉(zhuǎn)按鈕,還是點(diǎn)擊瀏覽器的前進(jìn)/后退按鈕,控制臺(tái)都會(huì)輸出當(dāng)前頁(yè)面對(duì)應(yīng)的 'url',有了 'url',我們就可以對(duì)內(nèi)容做條件渲染了

我們?cè)谏厦娴拇a的基礎(chǔ)上,稍作修改一下,增加2個(gè)div,一個(gè)是login,一個(gè)是index

html>
head>
    meta charset="UTF-8">
    title>Documenttitle>
    style>
        body{
            margin: 0;
            padding: 0;
        }
        #login, #index{
            width: 100%;
            height: 100%;
            display: none;
        }

        #login{
            background: #f5f5f5;
            display: block;
        }

        #index{
            background: #aaddff;
        }
    style>
head>
body>


div id="login" class="component">
    input type="button" onclick="hashPush('index')" value="登陸">
div>


div id="index" class="component">
    input type="button" onclick="hashPush('login')" value="退出登陸">
div>

body>
script>

    // 頁(yè)面跳轉(zhuǎn)
    function hashPush(url) {
        location.hash = "#" + url
    }

    // 監(jiān)聽(tīng)hash的變動(dòng)
    window.addEventListener('hashchange', function (e) {
        let url = location.hash.slice(1) || "/"
        console.log('當(dāng)前的hash地址', url)
        setVisible(url)
    })

    // 顯示跟路由地址對(duì)應(yīng)的內(nèi)容,隱藏其他內(nèi)容
    function setVisible(url) {
        let components = Array.from(document.body.querySelectorAll(".component"))
        components.map(item => {
            if(item.id===url) {
                console.log('顯示',item.id)
                item.style.display = 'block'
            } else {
                console.log('隱藏',item.id)
                item.style.display = 'none'
            }

        })
    }
script>
html>

這樣,我們就能根據(jù)不同的hash地址,顯示不同的內(nèi)容,是不是已經(jīng)有點(diǎn)路由的味道了呢?但是目前還無(wú)法傳參,傳參的方式有很多種,最常見(jiàn)最通俗的,應(yīng)該是query string 了吧? query string 其實(shí)很簡(jiǎn)單,解析url即可。愛(ài)掏網(wǎng) - it200.com

    // 監(jiān)聽(tīng)hash的變動(dòng)
    window.addEventListener('hashchange', function (e) {
        let url = location.hash.slice(1) || "index"
        // 解析url
        let questionIndex = url.indexOf("?")
        let path, query
        if(questionIndex >= 0){
            path = url.substr(0,questionIndex)
            let queryString = url.substr(questionIndex+1)
            let queryArray = queryString.split("&")
            let queryObject = {}
            queryArray.map(str => {
                let equalIndex = str.indexOf("=")
                if(equalIndex > 0) {
                    let key = str.substr(0,equalIndex)
                    let value = str.substr(equalIndex+1)
                    queryObject[key] = value
                }
            })
            query = queryObject
        } else {
            path = url
            query = {}
        }
        
        console.log('接收到的參數(shù)', query)
        setVisible(path)
    })

這樣,我們就能獲取到URL上傳遞的query string , 還順便解決了傳參會(huì)導(dǎo)致路由解析不正確的bug.

傳參其實(shí)還有個(gè)更簡(jiǎn)單的方法,就是 設(shè)置一個(gè)全局變量 param,然后在需要傳值的時(shí)候,直接對(duì)param 賦值即可

    // 設(shè)置一個(gè)全局變量
    var param = {}
    // 頁(yè)面跳轉(zhuǎn)
    // 這個(gè)多了個(gè)參數(shù) args
    function hashPush(url, args) {
        location.hash = "#" + url
        param = args
    }

由于是全局變量,所以可以在任意位置使用 param,不過(guò)這樣直接使用全局變量的方式,也有它的弱點(diǎn),就是點(diǎn)擊返回按鈕的時(shí)候無(wú)法保存變量,而query string 因?yàn)槭窃?url 里面的,所以返回的時(shí)候,可以拿到上個(gè)頁(yè)面的 query string, 那我們有沒(méi)有辦法讓全局變量的方式也能保存上一個(gè)頁(yè)面的參數(shù)呢? 我們來(lái)稍微修改一下代碼

    // 設(shè)置一個(gè)全局變量
    var param = {}
    // 頁(yè)面跳轉(zhuǎn)
    // 這個(gè)多了個(gè)參數(shù) args
    function hashPush(url, args) {
        location.hash = "#" + url
        // 如果有傳args參數(shù),就在 param 對(duì)象下建一個(gè)名字跟當(dāng)前url一樣的對(duì)象,并把a(bǔ)rgs賦值給它
        if(args) {
            param[url] = args
        }
    }

那我們?cè)?hashchange 的時(shí)候,可以根據(jù)url來(lái)定位該頁(yè)面的參數(shù)。愛(ài)掏網(wǎng) - it200.com

    // 監(jiān)聽(tīng)hash的變動(dòng)
    window.addEventListener('hashchange', function (e) {
        // 省略其他代碼
        args = param[path] || {}
        // 省略其他代碼
    })

這樣,我們就初步實(shí)現(xiàn)了一個(gè)hash路由,那么接下來(lái),我們來(lái)看看history路由怎么實(shí)現(xiàn)。愛(ài)掏網(wǎng) - it200.com

history 模式

history 模式主要依靠 調(diào)用 history.pushState() 方法 和 監(jiān)聽(tīng) popstate 事件。愛(ài)掏網(wǎng) - it200.com

history.pushState() 方法接收3個(gè)參數(shù):

  1. 要傳遞的數(shù)據(jù)(參數(shù))
  2. 給頁(yè)面設(shè)置的標(biāo)題(兼容性差,幾乎沒(méi)用)
  3. url

我們看看調(diào)用實(shí)例

    history.pushState({id:1}, '我是頁(yè)面標(biāo)題', url)

需要注意的是 pushState 的時(shí)候,并不會(huì)觸發(fā) popstate 事件,只有在前進(jìn)后退的時(shí)候,才會(huì)觸發(fā),所以 pushState 之后,需要手動(dòng)去設(shè)置頁(yè)面的相關(guān)狀態(tài)。愛(ài)掏網(wǎng) - it200.com如上面的例子,我們需要這樣做

    history.pushState({id:1}, '我是頁(yè)面標(biāo)題', url)
    setVisible(url)

然后監(jiān)聽(tīng) popstate 事件,捕獲 前進(jìn)/后退

 window.addEventListener('popstate',function (e) {
     // e.state 就是你 pushState 的時(shí)候,傳的第一個(gè)參數(shù)
     let state = e.state || {}  
     let url = state.target.location.pathName
     //  根據(jù)參數(shù) 做一些其他操作
  })

最后

本文最終實(shí)現(xiàn)代碼已經(jīng)放在 github上,想要直接看效果的同學(xué),可以上去直接copy,運(yùn)行。愛(ài)掏網(wǎng) - it200.com

如果覺(jué)得本文對(duì)您有用,請(qǐng)給本文的github加個(gè)star,萬(wàn)分感謝

另外,github上還有其他一些關(guān)于前端的教程和組件,有興趣的童鞋可以看看,你們的支持就是我最大的動(dòng)力。愛(ài)掏網(wǎng) - it200.com


其他鏈接

  1. 用proxy實(shí)現(xiàn)一個(gè)更優(yōu)雅的vue
  2. 3行代碼實(shí)現(xiàn)一個(gè)簡(jiǎn)易版promise
  3. vuex其實(shí)超簡(jiǎn)單,只需3步
  4. vuex其實(shí)超簡(jiǎn)單,喝完這3步,還有3步
  5. 從零開始徒手?jǐn)]一個(gè)vue的toast彈窗組件
  6. JS中的繼承(上)
  7. JS中的繼承(下)
  8. JS中的原型對(duì)象
  9. JS中創(chuàng)建對(duì)象的方法
  10. moment太重? 那就試試miment--一個(gè)超輕量級(jí)的js時(shí)間庫(kù)
  11. 美團(tuán)小程序框架mpvue入門教程
  12. 美團(tuán)小程序框架mpvue(花名:沒(méi)朋友)蹲坑指南
  13. 一個(gè)基于mpvue的toast彈窗組件mptoast



原文發(fā)布時(shí)間為:2024年06月29日

本文作者:noahlam

本文來(lái)源:掘金?如需轉(zhuǎn)載請(qǐng)聯(lián)系原作者
聲明:所有內(nèi)容來(lái)自互聯(lián)網(wǎng)搜索結(jié)果,不保證100%準(zhǔn)確性,僅供參考。如若本站內(nèi)容侵犯了原著者的合法權(quán)益,可聯(lián)系我們進(jìn)行處理。
發(fā)表評(píng)論
更多 網(wǎng)友評(píng)論0 條評(píng)論)
暫無(wú)評(píng)論

返回頂部

主站蜘蛛池模板: 国内精品视频在线 | 欧美看片 | 天天操天天摸天天干 | 91免费视频 | 亚洲高清一区二区三区 | 国产第一区二区 | 91久久看片 | 国产一区二区三区免费观看在线 | 成人毛片视频免费 | 性一交一乱一透一a级 | 三级视频在线观看电影 | 免费看国产一级特黄aaaa大片 | 久久成人免费视频 | 色一情一乱一伦一区二区三区 | 欧美综合视频在线 | 久久一区二区三区免费 | 国产色片在线 | 国产精品1区2区 | 亚洲欧美网 | 久久99久久98精品免观看软件 | 久久99精品久久久久久国产越南 | 欧洲一级毛片 | 国产精品久久久久久妇女6080 | 免费看的av| 老头搡老女人毛片视频在线看 | 成人a免费 | 99免费视频 | 久久国产视频网 | 91精品国产一区二区 | 国产精品69av | 亚洲国产一区二区三区 | 亚洲精品一区二区 | 99re视频在线观看 | 先锋资源站 | 99re在线免费视频 | 日韩在线综合 | 免费在线观看黄网站 | 9191成人精品久久 | 亚洲一区免费 | 日韩欧美在线播放 | 免费国产黄网站在线观看视频 |