Vue-Router 原理实现
一、Vue-Router 动态路由
方式1:通过当前路由规则,获取数据
{{$route.params.id}}
方式2:路由规则中开启props 传参 推荐使用这种方式
通过开启props 获取{{id}}
Details.vue
export defult {
name:'Details',
props:['id']
}
--------------------------------------------
router--index.js
const routes = [
{
path:'/detail/:id',
name:'Details',
//开启props,会把URL中国的参数传递给组件
//在组建中通过props来接受URL参数
props:true,
component:()=>import('../views/Details.vue')
}
]
二、Vue-Router 嵌套路由
router--index.js
const routes = [
{
name:'login',
path:'/login',
component:Login
},
//嵌套路由
{
path:'/',
component:Layout,
children:[
{
name:'index',
path:'',
component:Index
},
{
name:'detail',
path:'detail/:id',
props:true,
component:()=>import('../views/Details.vue')
}
]
}
]
三、Vue-Router 编程式导航
methods:{
push(){
this.$router.push('/')
// this.$router.push({name:'login'})
},
replace(){ // 不会记录当前历史
this.$router.replace('/login')
},
goDetail(){
this.$router.push({name:'Detail',params:{id:1}})
},
go(){
this.$router.go(-2)
}
}
四、Vue-Router Hash和History模式的区别
表现形式的区别
原理的区别
- Hash 模式是基于锚点,以及onhashchange时间
- History 模式是基于HTML5中的HistoryAPI
- history.pushState() IE 10以后才支持
- history.replaceState()
五、History 模式的使用
- History 需要服务器的支持
- 但也应用中,服务端不存在http://www.testurl.com/login这样的地址会返回找不到该页面
- 在服务端应该出了静态资源外都返回单页面应用的index.html
六、History 模式 Node.js 服务器配置
const path = require('path')
//导入处理history模式的模块
cosnt history require ('connect-history-api-fqallback')
//导入express
const express = require('express')
const app = express()
//注册处理history 模式的中间件
app.use(history())
//处理静态资源的中间件,网站根目录 ../web
app.use(express.static(path.join(__dirname,'../web')))
//开启服务器,端口为3000
app.listen(3000,()=>{
const.log('服务器已开启,localhost:3000');
})
七、History 模式 nginx 服务器配置
- 从官网下载nginx 的压缩包
- 把压缩包解压到C盘根目录,c:\nginx-1.18.0文件夹
- 打开命令行,切换到目录c:\nginx-1.18.0
- 命令行启动nginx
启动:start nginx
重启:nginx -s reload
停止:nginx -s stop -
配置history模式需要修改nginx.conf文件为如下内容
八、VueRouter 实现原理
vue前置知识
- 插件
- 混入
- Vue.observable()
- 插槽
- render函数
- 运行时和完整版的vue
Hish模式
- URL中#后面的内容作为路径地址
- 监听hashchange 时间
- 根据当前路由地址找到对应的组件进行渲染
History 模式
- 通过history.pushState() 方法改变地址栏
- 监听popState 时间
- 根据当前路由地址找到对应的组件重新渲染
九、 VueRouter模拟事件-分析
- 回顾核心代码
//router/index.js
//注册插件
Vue.use(VueRouter)
//创建路由对象
const router = new VueRouter({
routes:[
{name:'home',path:'/',component:homeComponent}
]
})
export default router;
//main.js
//创建Vue 实例 注册router 对象
new Vue({
router,
render:h =>h(App)
}).$mount('#app)
十、VueRouter - install
let _Vue = null;
export default class VueRouter {
static install(Vue) {
// 1、判断当前插件是否已经被安装
if (VueRouter.install.installed) {
return;
}
VueRouter.install.installed = true;
// 2、把Vue构造函数记录到全局变量
_Vue = Vue;
// 3、把创建Vue实例时候传入的router对象注入到Vue 实例上
// 混入
_Vue.mixin({
beforeCreate () {
if(this.$options.router){
_Vue.prototype.$router = this.$options.router
}
}
})
}
}
十一、VueRouter - 构造函数
// 构造函数 初始化三个必要属性
constructor(options) {
this.options = options;
this.routeMap = {};
this.data = _Vue.observable({
current: "/",
});
}
十二、VueRouter - createRouteMap
createRouteMap() {
//遍历所有的路由规则,把路由规则解析成键值对的形式存储到routeMap中
this.options.routes.forEach((route) => {
this.routeMap[route.path] = route.component;
});
}
十三、 VueRouter ---- router-link
Vue 的构建版本
- 运行时版:不支持template模板,需要打包的时候提前编译,vue-Cli 默认使用的是运行时版本,所以构建时候会出错,可以切换成完整版
如下配置。也可以使用render函数构建。 -
完整版:包含运行时和编译器,体积比运行时版大10K左右,程序运行的时候把模板转换成render函数
十四、VueRouter - render
使用render 函数解决构建时候出错
initComponents(Vue) {
Vue.component("router-link", {
props: {
to: String,
},
render(h){
return h('a',{
attrs:{
href:this.to
}
},[this.$slots.default])
}
// template: '<a :href="to"><slot></slot></a>',
});
}
十五、 VueRouter --- router-view
const self = this;
Vue.component("router-view", {
render(h) {
console.log(self);
const component = self.routeMap[self.data.current]
console.log(self.routeMap[self.data.current]);
return h(component);
},
});
十六、VueRouter - initEvent
init() {
this.createRouteMap();
this.initComponents(_Vue);
this.initEvent()
}
initEvent() {
window.addEventListener("popstate", () => {
this.data.current = window.location.pathname;
});
}