资讯专栏INFORMATION COLUMN

怎么理解前端router? 当然是自己实现一个啦!

fsmStudy / 825人阅读

摘要:流行的今天不少同学会把前端路由跟后端路由弄混莫名其妙的怎么页面啦之类奇怪的问题其实这就是没弄清楚前端路由和后端路由的原因当然你用当我没说本文所有前端路由都是的情况下不存在后端渲染好变量的情况原理首先我们看看前后端路由在浏览器中是怎么工作的上

spa流行的今天不少同学会把前端路由跟后端路由弄混, 莫名其妙的怎么页面404啦之类"奇怪"的问题, 其实这就是没弄清楚前端路由和后端路由的原因(当然你用hash当我没说).

本文所有前端路由都是spa的情况下, 不存在后端渲染好变量的情况

原理

首先我们看看前后端路由在浏览器中是怎么工作的, 上图:

后端控制的路由:

我们可以知道后端其实返回的是html字符串, 也就是dom节点不出意外的话是确认的. 不管你请求多少次, 结果都是确定的(get 幂等). 所以也就不存在404的情况

前端控制的路由:

如果是spa的话, 我们可以知道不管你请求那个页面, 在后端处理好的情况下后端都会返回一个html文件(所谓单页的由来), 静态资源当然也是类似的. 那么我们可能有点疑问, 比如一个个人主页, 如果只返回一个html文件的话, 怎么得到不同的用户资料呢, 答案就是前端路由(大部分情况, 不排除本地存储?), js根据不同的路由再向服务器请求相关资料, 也就是说其实第一次服务端渲染我们的页面是空的, 后期ajax请求. 所以我们看到很多单页页面打开了首先要loading一会. 就是在向服务器请求渲染页面.

实现

后端路由我们暂且不去管它, 我们看看是怎么实现的:

在非hash的情况下, 前端路由的实现基础是window.history, 当然我们不用去管它的兼容性了, 反正现在大部分浏览器能用就是了:

history有个重要的方法就是pushState, 其它的方法暂时用不到不提, 它的作用呢就是改变浏览器地址栏里的地址, 以及在历史纪录里加上一条, 除此以外没啥别的副作用了, 比如:

var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");

上面的代码只会跳到一个 bar.html的地址, 但是页面本身并未跳转, 我们不是来讲history对象本身的, 有兴趣可以自行翻看mdn.

其实参考后端对路由的控制, 我们大略可以想像一个前端路由所具有的功能:

对路由做出响应

渲染

一些事件, 比如beforeChange之类的

当然我们现在一切从简, 上面那些说清楚了起实现无非就是苦力了, 先给大家看看效果吧:

还是有点意思的吧.

下面是html代码:




  
  
  
  Document
  


  
  
Panel heading without title
Panel content

index.js

const $routeController = $("a[data-role=custom-history]")

const app = new Route()

app.set("/1", function () {
  $("#app").html("1")
})

app.set("/2", function () {
  $("#app").html(2)
})

route.js

class Route {
  constructor () {
    this.urls = []
    this.handles = {}
    window.addEventListener("popstate", (e) => {
      const state = e.state || {}
      const url = state.url || null

      if (url) {
        this.refresh(url)
      }
    })

    const $routeController = $("a[data-role=custom-history]")

    $routeController.on("click", e => {
      e.preventDefault()
      const link = $(e.target).attr("href")
      history.pushState({ url: link }, "", link)
      this.refresh(link)
    })
  }

  set (route, handle) {
    if (this.urls.indexOf(route) === -1) {
      this.urls.push(route)
      this.handles[route] = handle
    }
  }

  refresh (route) {
    if (this.urls.indexOf(route) === -1) throw new Error("请不要这样调用, 路由表中不存在!")
    this.handles[route]()
  }
}

按我的本意是不想在一篇文章里贴这么多代码的, 但是因为也不可以直接嵌入jsbin之类的, 方便大家试试看效果, 就放进来把, 因为代码比较简单, 而且深度绑定到了dom上, 就不要嘲笑啦!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90561.html

相关文章

  • 手把手教你用vue搭建个人站

    摘要:在我转前端以来,一直想要实现一个愿望自己搭建一个可以自动解析文档的个人站今天终于实现啦,先贴上我的地址确认需求其实一个最简单的个人站,就是许多的页面,你只要可以用写出来就可以,然后挂到上。 在我转前端以来,一直想要实现一个愿望: 自己搭建一个可以自动解析Markdown文档的个人站 今天终于实现啦,先贴上我的blog地址 确认需求 其实一个最简单的个人站,就是许多的HTML页面,你只要...

    xietao3 评论0 收藏0
  • vue for contacts项目总结

    摘要:用来主要前台的请求,并处理返回相关的数据,做后台服务。总结做完这个项目,其中的过程还是挺艰辛的,毕竟都是边学边做,不过最后能完成还是挺开心的,终于有了一个从到的项目过程。虽然只是一个小小的练手项目,不过对于目前的我,感觉还是不错的。 showImg(https://oc1gyfe6q.qnssl.com/17-3-30/43434844-file_1490879850754_14751...

    tulayang 评论0 收藏0
  • vue for contacts项目总结

    摘要:用来主要前台的请求,并处理返回相关的数据,做后台服务。总结做完这个项目,其中的过程还是挺艰辛的,毕竟都是边学边做,不过最后能完成还是挺开心的,终于有了一个从到的项目过程。虽然只是一个小小的练手项目,不过对于目前的我,感觉还是不错的。 showImg(https://oc1gyfe6q.qnssl.com/17-3-30/43434844-file_1490879850754_14751...

    ralap 评论0 收藏0
  • vue for contacts项目总结

    摘要:用来主要前台的请求,并处理返回相关的数据,做后台服务。总结做完这个项目,其中的过程还是挺艰辛的,毕竟都是边学边做,不过最后能完成还是挺开心的,终于有了一个从到的项目过程。虽然只是一个小小的练手项目,不过对于目前的我,感觉还是不错的。 showImg(https://oc1gyfe6q.qnssl.com/17-3-30/43434844-file_1490879850754_14751...

    ARGUS 评论0 收藏0

发表评论

0条评论

fsmStudy

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<