1. 程式人生 > >原生js實現路由跳轉

原生js實現路由跳轉

var regexps = [
  /[\-{}\[\]+?.,\\\^$|#\s]/g,
  /\((.*?)\)/g,
  /(\(\?)?:\w+/g,
  /\*\w+/g, 
]

function extractRoute (route) {
  var matchs = []
  route = route.replace(regexps[0], '\\$&')
    .replace(regexps[1], '(?:$1)?')
    .replace(regexps[2], function (match, optional) {
      if (match) matchs.push(match.replace(':'
, '')) return optional ? match : '([^/?]+)' }).replace(regexps[3], function (match, optional) { if (match) matchs.push(match.replace('*', '')) return '([^?]*?)' }) return { regexp: new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$'), matchs: matchs } } function extractParams
(route, path) {
var params = route.exec(path).slice(1) var results = [] for (var i = 0; i < params.length; i++) { results.push(decodeURIComponent(params[i]) || null) } return results } // borwser function extractQuery() { var url = location.search var pattern = /(\w+)=([^\?|^\&]+)/ig
var query = {} url.replace(pattern, function(a, b, c) { query[b] = c; }) return query; } async function exec() { var match = false for (var i = 0; i < data.routes.length; i++) { var route = extractRoute(data.routes[i].path); if (!route.regexp.test(data.req.path)) { continue } match = true var results = extractParams(route.regexp, data.req.path) data.req.params = data.req.params || {} for (var j = 0; j < route.matchs.length; j++) { data.req.params[route.matchs[j]] = results[j] } await data.routes[i].fn.call(data, data.req, data.res, data.next) } if (!match && typeof data.next === 'function') await data.next() } // borwser function emit() { if (data.req.url === location.href) return data.req.url = location.href data.req.path = location.pathname data.req.query = extractQuery() exec() } var data = {routes: [], resMethods: {}} async function Router(req, res, next) { if (typeof document === 'object') { // browser data.env = 'browser' data.req = {query: {}} data.res = {} window.addEventListener('popstate', emit, false) }else if (next) { // express data.req = req data.req.url = data.req.originalUrl data.res = res data.next = next data.env = 'express' } else { // koa data.ctx = req data.req = data.ctx.request // 替換掉問號後面的引數 data.req.path = data.req.url.replace(/\?.*/g, '') data.res = data.ctx.response data.next = res data.env = 'koa' } for (var m in data.resMethods) { data.res[m] = data.resMethods[m].bind(data) } data.env === 'browser' ? emit() : await exec() } Router.get = function(path, fn) { data.routes.push({ path: path, fn: fn }) } Router.addResMethod = function(name, fn) { data.resMethods[name] = fn } /** * browser * 需要注意的是呼叫history.pushState()或history.replaceState()不會觸發popstate事件, * 只有在做出瀏覽器動作時,才會觸發該事件,如使用者點選瀏覽器的回退按鈕(或者在Javascript程式碼中呼叫history.back()) */ Router.go = function(path, isReplace) { if (isReplace) { history.replaceState({ path: path }, null, path); } else { history.pushState({ path: path }, null, path); } emit() } // browser Router.back = function() { history.back() } // browser, 代理連結功能 Router.proxyLinks = function(nodes) { for (var i = 0; i < nodes.length; i++) { nodes[i].addEventListener('click', function(e) { Router.go(e.target.href) e.preventDefault() }) } } module.exports = Router