1.前言
挑战下自己,看能不能梳理个头绪哈哈
首先通过
3x
以上的脚手架 (目前我使用的是4.5.13
)创建
vue项目
创建的时候配置好router
和vuex
2. vue-router----router.js分析 3件事情
2.1 作为插件引入 VueRouter
Vue.use(VueRouter)
插件的形式: 一般是对象或者函数
这行代码其实会调用
install
方法如果写过插件这块应该会很清楚
也可以 通过查看 vue add axios 生成的文件
2.2 路由表的配置
主要就是 path和组件的对应关系
2.3 创建实例并导出
3. 准备工作
- 复制 router目录 为 zrouter/index.js zrouter/zvue-router.js
- main.js文件修改引入
import router from './zrouter'
4. zrouter/index 实现上述基础的3个步骤结构
- 不用import 导入
Vue
因为我们现在写的是个第三方库,把Vue打包进去,耦合性太高,所有用参数传进来
//ZVueRouter 类 对比 VueRouter类 class ZVueRouter{ } // 形参1是Vue的构造函数 ZVueRouter.install = function(_Vue,options){ // 传入构造函数 修改原型,起到扩展作用 // 保存一下Vue实例 便于其他地方使用 Vue = _Vue // install中 this是 ZVueRouter } export default ZVueRouter
5. $router注册
因为path 跳转 都是
this.$router.push()
的写法,所以需要注册$router
通常的方法 是 原型挂载 例如事件总线
Vue.prototype.$bus
main.js
new Vue({ router, store, render: h => h(App) }).$mount('#app')
所以
Vue.prototype.$router = this.$options.router
,但是在这
install
函数里面 this指向的是ZVueRouter
,所以拿不到 路由的配置信息
5.1 顺序问题
Vue.use(VueRouter) const router = new VueRouter({ routes })
仔细分析这段代码其实
use
的时候router
还没有创建呢,所以自己模拟这块的话,也需要延迟执行
也就是需要等到router的实例创建完成之后在,执行,我们的挂载代码
嘿嘿这里怎么办呢 ,应该有不少人脑子里 蹦出来 定时器 ,或者 钩子了
5.2 解决方案 全局混入
6.注册全局router-link router-view组件
6.1 基本结构
顺便把上面的代码一起贴下
// 形参1是Vue的构造函数 ZVueRouter.install = function (_Vue, options) { // 传入构造函数 修改原型,起到扩展作用 // 保存一下Vue实例 便于其他地方使用 Vue = _Vue // install中 this是 ZVueRouter // 1. 注册 router Vue.mixin({ beforeCreate() { if (this.$options.router) { Vue.prototype.$router = this.$options.router } } }) // 2. 注册全局组件 routerLink routerView Vue.component("router-link",{ template:'<a> 跳吧</a>' }) Vue.component("router-view",{ template:'<div> 出来吧 ,神龙</div>' }) }
6.2 终于 可以查看界面效果了,但是报错了 哈哈
6.3 render函数结构
// 2. 注册全局组件 routerLink routerView Vue.component("router-link", { render(h) { return h( "a", { attrs: { href: '#/yzs' } }, "随便写点" ) } }) Vue.component("router-view", { render(h) { return h( "div", {}, "神龙这次出来了吧" ) } })
6.4 界面效果
6.5 render函数 介绍
h
就是createElement
创建 VNode 虚拟节点h(参数1,参数2,参数3)
参数1: 渲染的 标签 ,这标签其实也可以是
组件名
哦 ,这里可以自定义组件渲染哦,所以在
iview
和elementUI
等框架的表格组件 经常自己写render
参数2:主要就是标签 属性配置信息
参数3: 是标签内容, 那系统组件的话,写的时候内容又要显示我们自己的,就需要用到
slot
插槽啦
6.6 render 实现 组件
Home
Vue.component("router-link", { // 这就是组件的传值 to属性是 使用 router-link的时候传过来的 props:{ to:{ type:String, required:true, } }, render(h) { return h( "a", { attrs: { href: '#'+this.to } }, // 标签内容是 用户传过来的 默认插槽 this.$slots.default ) } })
6.6.1 效果
6.6.2 扩展 jsx用法
也可以使用
JSX
支持JSX
语法就行
return <a href={'#' + this.to}> {this.$slots.default}</a>
7 render 实现 router-view组件
7.1作用
- 获取路由实例
- 获取hash 部分 也就是path
- 根据path,从路由表中获取组件
7.2. 获取路由实例
1.先前 已经把路由实例 通过混入的方式 挂载到了实例上
- 获取路由配置信息
const router = new VueRouter({ routes })
- 这路由配置信息是通过 创建 路由实例挂载上去的
- 所以我们可以通过路由的 构造函数获取这个配置信息
class ZVueRouter { constructor(options){ //选项中 包含路由配置信息 ,保存下 ,后边使用 // 挂载到了 ZVueRouter this.$options = options; } }
- 测试获取 路由配置信息
Vue.component("router-view", { render(h) { // 0获取路由实例 console.log("配置信息",this.$router.$options) return h( "div", {}, "神龙这次出来了吧" ) } })
7.3. 获取hash 部分 也就是path
- 监听hashchange事件并且在变化的时候响应
1.截取下 因为 获取的是 #about 这种形式
2.初识话的 第一次进来也可能没有 哈希 所有给个默认的/
3.赋值给ZVueRouter 实例
class ZVueRouter { constructor(options){ //选项中 包含路由配置信息 ,保存下 ,下边使用 // 挂载到了 ZVueRouter this.$options = options; // 2.监听hashchange事件并且在变化的时候响应 window.addEventListener("hashchange",()=>{ // 1.截取下 因为 获取的是 #about 这种形式 // 2.初识话的 第一次进来也可能没有 哈希 所有给个默认的/ // 3.赋值给ZVueRouter 实例 this.current = window.location.hash.slice(1) ||"/" console.log("监听 hash",this.current); }) } }
7.3.1, 问题可以监听到 但是 下方的路由router-view
并不会切换
7.3.2. 数据响应式
数据变化可侦听
使用这些数据的组件就会和数据产生依赖关系
当响应式数据变化的时候,组件也会变化
数据响应式的方式
1,使用new Vue() 里面的data
2.Vue.util.defineReactive()
注意 Vue.set()不行
其实
set
这里的第一个参数 要求就是必须是响应式的
class ZVueRouter { constructor(options) { this.$options = options; // 需要将current 设置为响应式的 Vue.util.defineReactive( this, "current", window.location.hash.slice(1) || "/" ) // 2.监听hashchange事件并且在变化的时候响应 this.current = window.location.hash.slice(1) || "/" console.log("监听 hash", this.current); }) } }
7.3.4 router 打印
Vue.component("router-view", { render(h) { // 0获取路由实例 console.log("配置信息-view",this.$router.current, this.$router.$options) return h( "div", {}, "神龙这次出来了吧" ) } })
7.3.5运行查看效果
来回切换 已经可以 每次都触发
router-view
了
7.4. 根据path,从路由表中获取组件
Vue.component("router-view", { render(h) { console.log("配置信息-view",this.$router.current, this.$router.$options) let component = null const route = this.$router.$options.routes.find( (route)=>route.path === this.$router.current ) if(route){ component = route.component } return h(component) } })
8.纸上得来终觉浅呀
最好的学习,最好的检测自己 ,就是输出, 受益匪浅,
- 目录结构
- index.js 修改下引用
import VueRouter from './zvue-router'
- 主文件 zvue-router.js
let Vue class ZVueRouter { constructor(options) { //选项中 包含路由配置信息 ,保存下 ,下边使用 // 挂载到了 ZVueRouter this.$options = options; // 需要将current 设置为响应式的 Vue.util.defineReactive( this, "current", window.location.hash.slice(1) || "/" ) // 2.监听hashchange事件并且在变化的时候响应 window.addEventListener("hashchange", () => { this.current = window.location.hash.slice(1) || "/" console.log("监听 hash", this.current); }) } } // 形参1是Vue的构造函数 ZVueRouter.install = function (_Vue, options) { // 传入构造函数 修改原型,起到扩展作用 // 保存一下Vue实例 便于其他地方使用 Vue = _Vue // install中 this是 ZVueRouter Vue.mixin({ beforeCreate() { if (this.$options.router) { Vue.prototype.$router = this.$options.router } } }) // 2. 注册全局组件 routerLink routerView Vue.component("router-link", { // 这就是组件的传值 to属性是 使用 router-link的时候传过来的 props: { to: { type: String, required: true, } }, render(h) { // 这里也支持JSX语法 // return <a href={'#' + this.to}> {this.$slots.default}</a> return h( "a", { attrs: { href: '#' + this.to } }, // 标签内容是 用户传过来的 // <router-link to="/">Home</router-link> | this.$slots.default ) } }) Vue.component("router-view", { render(h) { console.log("配置信息-view",this.$router.current, this.$router.$options) let component = null const route = this.$router.$options.routes.find( (route)=>route.path === this.$router.current ) if(route){ component = route.component } return h(component) } }) } export default ZVueRouter