朋友们,美好的一天!基于React,Vue或纯JavaScript的简单单页应用程序无处不在。一个好的“一页”假定有适当的路由机制。诸如“ navigo”或“ react-router”之类的库非常有用。但是它们如何工作?我们需要导入整个库吗?还是某个部分足够了,例如10%?实际上,您可以自己轻松地编写一个快速且有用的路由器,这将花费一些时间,并且该程序将包含少于100行的代码。要求
我们的路由器应该是:通常,一个Web应用程序使用一个路由器实例,但是在许多情况下,我们需要多个实例,因此我们将无法使用Singleton作为模板。要工作,我们的路由器需要以下属性:- 路由器:已注册路由器的列表
- 模式:哈希或历史记录
- 根元素:应用程序的根元素,如果我们处于历史使用模式
- 构造函数:用于创建新路由器实例的主要功能
class Router {
routes = []
mode = null
root = '/'
constructor(options) {
this.mode = window.history.pushState ? 'history' : 'hash'
if (options.mode) this.mode = options.mode
if (options.root) this.root = options.root
}
}
export default Router
添加和删除路由器
添加和删除路由器是通过添加和删除阵列元素完成的:class Router {
routes = []
mode = null
root = '/'
constructor(options) {
this.mode = window.history.pushState ? 'history' : 'hash'
if (options.mode) this.mode = options.mode
if (options.root) this.root = options.root
}
add = (path, cb) => {
this.routes.push({
path,
cb
})
return this
}
remove = path => {
for (let i = 0; i < this.routes.length; i += 1) {
if (this.routes[i].path === path) {
this.routes.slice(i, 1)
return this
}
}
return this
}
flush = () => {
this.routes = []
return this
}
}
export default Router
获取当前路径
我们需要在特定的时间点知道我们在应用程序中的位置。为此,我们需要处理两种模式(历史记录和哈希)。在第一种情况下,我们需要从window.location中删除到根元素的路径,在第二种情况下为“#”。我们还需要(clearSlash)函数来删除所有路由器(从头到尾的行):[...]
clearSlashes = path =>
path
.toString()
.replace(/\/$/, '')
.replace(/^\//, '')
getFragment = () => {
let fragment = ''
if (this.mode === 'history') {
fragment = this.clearSlashes(decodeURI(window.location.pathname + window.location.search))
fragment = fragment.replace(/\?(.*)$/, '')
fragment = this.root !== '/' ? fragment.replace(this.root, '') : fragment
} else {
const match = window.location.href.match(/#(.*)$/)
fragment = match ? match[1] : ''
}
return this.clearSlashes(fragment)
}
}
export default Router
导航
好的,我们有一个用于添加和删除URL的API。我们也有机会获得当前地址。下一步是浏览路由器。我们使用“ mode”属性:[...]
getFragment = () => {
let fragment = ''
if (this.mode === 'history') {
fragment = this.clearSlashes(decodeURI(window.location.pathname + window.location.search))
fragment = fragment.replace(/\?(.*)$/, '')
fragment = this.root !== '/' ? fragment.replace(this.root, '') : fragment
} else {
const match = window.location.href.match(/#(.*)$/)
fragment = match ? match[1] : ''
}
return this.clearSlashes(fragment)
}
navigate = (path = '') => {
if (this.mode === 'history') {
window.history.pushState(null, null, this.root + this.clearSlashes(path))
} else {
window.location.href = `${window.location.href.replace(/#(.*)$/, '')}#${path}`
}
return this
}
}
export default Router
观察变化
现在,我们需要使用链接或使用我们创建的“导航”方法来跟踪地址更改的逻辑。我们还需要确保首次访问时呈现正确的页面。我们可以使用应用程序的状态来注册更改,但是,出于研究目的,我们将使用setInterval进行此操作:class Router {
routes = [];
mode = null;
root = "/";
constructor(options) {
this.mode = window.history.pushState ? "history" : "hash";
if (options.mode) this.mode = options.mode;
if (options.root) this.root = options.root;
this.listen();
}
[...]
listen = () => {
clearInterval(this.interval)
this.interval = setInterval(this.interval, 50)
}
interval = () => {
if (this.current === this.getFragment()) return
this.current = this.getFragment()
this.routes.some(route => {
const match = this.current.match(route.path)
if (match) {
match.shift()
route.cb.apply({}, match)
return match
}
return false
})
}
}
export default Router
结论
我们的图书馆随时可以使用。它仅包含84行代码!Github上的代码和用法示例。
感谢您的关注。