网站运营方案案例/短视频推广策略
模拟 vue-router hash 模式的基础功能实现
- 模拟 vue-router 的实现
- 实现 vue-router 的核心步骤
- 构建类
- 构建响应式数据属性 current
- install方法
- 初始化 router-link,router-view 组件
- match 匹配路由
- 监听 hash 改变
模拟 vue-router 的实现
以下内容基于 vue-router hash 模式来实现
实现 vue-router 的核心步骤
- 构建 vue-router 类
- 构建响应式数据属性 current,动态渲染 dom
- 添加静态方法 install,完成 Vue 模块的注册
- 初始化 router-link,router-view 组件,负责路由跳转和组件渲染
- 通过 match 函数匹配路由,找到需要渲染的组件
- 监听 hash 的变化,动态改变 current 属性
构建类
class MiniRouter {constructor(options) {// 存储参数this.options = options// 存储路由this.routes = options.routes// 初始化函数this.init()}init() {// 所有初始化操作放在这里}
}
构建响应式数据属性 current
为了可以在路由发生变化的时候去更新视图,我们可以实例化一个响应式对象 data,并给定 响应式属性 current 来记录当前的 hash,当 current 发生变化的时候,vue 就会动态更新视图
class MiniRouter {constructor(options) {...// 创建一个响应式的属性 current,当 current 改变的时候就会重新渲染 domthis.data = $Vue?.observable({// 给定初始 hashcurrent: window.location.hash.replace(/#/, '')})}
}
install方法
当使用 Vue.use(MiniRouter)
的时候,他要求传入的对象,必须存在一个 install
方法,它会自动帮我们执行这个方法,并将 Vue 构造函数传入该方法。所以我们可以在 install 方法中编写一些初始化代码。
而且因为 MiniRouter 是一个类,所以 install 方法应该是一个静态方法
let $Vue = null
let installed = false
class MiniRouter {// install 方法,是用于 vue 来注册该组件的必备方法static install(Vue) {// 判断当前插件是否被安装if (installed) {return}// 这里我使用局部变量来缓存模块安装判断installed = true// 局部保存 Vue 构造函数,将来会用到$Vue = Vue// console.log('route installed')// 当 vue 实例化之后,将 router 实例注入到 vue 实例中$Vue.mixin({beforeCreate() {if (this.$options.router) {// 将 router 实例保存到 Vue 的 prototype 上$Vue.prototype.$router = this.$options.router}}})}...
}
初始化 router-link,router-view 组件
router-link 组件是用于改变当前url hash 值和改变属性 current 值的组件
router-view 组件则是负责在 hash 发生变化后,将匹配到的路由组件渲染到页面上
class MiniRouter {...initComponents() {// 初始化一个 route-link 组件$Vue.component('router-link', {// 接收 to 参数,指定跳转连接props: {to: String},// 渲染 domrender(h) {return h('a', {attrs: {href: this.to},on: {click: this.clickHandler}}, [this.$slots.default])},methods: {// 指定组件的点击事件clickHandler(e) {// 通过 push State 改变 hashhistory.pushState({}, '', `#${this.to}`)// 改变 current 值,动态渲染视图this.$router.data.current = this.to// 阻止默认事件跳转e.preventDefault()}}})const self = this// 初始化一个 router-view 组件,进行组件渲染$Vue.component('router-view', {render(h) {// 匹配路由对象,找到需要渲染的组件let cm = self.match(self.data.current)?.componentreturn h(cm)}})}
}
initComponents 方法需要在 init 中执行
match 匹配路由
match 函数可以说是这里最核心的方法,它可以根据传入的 path,找到与之匹配的路由对象和部分参数。
class MiniRouter {...match(path) {// 存储匹配到的路由及部分参数let matchRoute = null// 遍历所有的路由,知道匹配到对应的路由this.routes.every(route => {// 通过 getRouteType 判断当前 route 的类型let routeType = this.getRouteType(route.path)// 找到 route 匹配的规则,用于判断当前路由和传入的 path 是否匹配let routeMethod = this[`match${routeType}Route`]// 如果规则不存在,则跳过if (!routeMethod) {return true}// 判断路由和 path 是否匹配,并返回对应的数据参数let matchResult = routeMethod(path, route)if (matchResult) {// 匹配成功,储存返回的参数,并跳出循环matchRoute = matchResultreturn false}// 进行下一次循环return true})// 返回匹配结果,若没有匹配成功则返回 nullreturn matchRoute}
}
match 函数内部还有其他的方法,这里不一一阐述,有兴趣可以看源码。核心就是通过 getRouteType 找到路由的类型(静态路由,动态路由,统配符路由),然后找到对应类型下的路由匹配规则this[
match${routeType}Route]
,进行匹配和返回。
监听 hash 改变
最后,我们需要通过监听 popState 来监听 hash 的改变,从而动态改变 视图,这一步主要是监听浏览器的前进,后退,或者用户直接改变hash的操作
class MiniRouter {...initEvent() {document.addEventListener('popstate', () => {this.data.current = window.location.hash.replace(/#/, '')})}
}
initEvent 方法需要在 init 中执行
以上内容仅供学习参考,如需完整代码,可以私聊我