Vue路由
Vue的基础结构
对于Vue的基本机构,我相信小伙伴们肯定都会有很多的了解;在这里小编就不多做介绍了,简单的列一下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>render</title>
</head>
<body>
<!--这里可以使用插值表达式 {{}}-->
<div id="app">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
data: {
school: {
name: 'XX',
address: 'XXXXXXXXXXXXXXX'
}
},
render(h) {
return h('div', [
h('p', '学校名称:' + this.school.name),
h('p', '学校地址:' + this.school.address)
])
}
}).$mount('#app')
</script>
</body>
</html>
VueRouter
import Vue from 'vue'
// import VueRouter from 'vue-router'
import VueRouter from './vue-router-hash.js'
import Index from '../views/Index.vue'
// 1. 注册路由插件
Vue.use(VueRouter)
// 路由规则
const routes = [
{
path: '/',
name: 'Index',
component: Index
},
{
path: '/blog',
name: 'Blog',
component: () => import(/* webpackChunkName: "blog" */ '../views/Blog.vue')
},
{
path: '/photo',
name: 'Photo',
component: () => import(/* webpackChunkName: "photo" */ '../views/Photo.vue')
}
]
// 2. 创建 router 对象
const router = new VueRouter({
routes
})
export default router
// router/index.js
// 注册插件
// Vue.use()可以传入函数,就直接调用这个函数;也可以传入一个对象;调用对象的install方法;所以需要一个install方法
Vue.use(VueRouter)
// 创建路由对象
const router = new VueRouter({
routes: [
{ name: 'home', path: '/', component: homeComponent }
]
})
// main.js
// 创建vue实例,注册router对象
new Vue({
router,
render: h => h(App).$mount('#app')
})
import Vue from 'vue'
import VueRouter from 'vue-router'
import Index from '../views/Index.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Index',
component: Index
},
{
path: '/detail/:id',
name: 'Detail',
// 开启 props,会把 URL 中的参数传递给组件
// 在组件中通过 props 来接收 URL 参数
props: true,
component: () => import(/* webpackChunkName: "detail" */ '../views/Detail.vue')
}
]
const router = new VueRouter({
routes
})
export default router
import Vue from 'vue'
import VueRouter from 'vue-router'
// 加载组件
import Layout from '@/components/Layout.vue'
import Index from '@/views/Index.vue'
import Login from '@/views/Login.vue'
Vue.use(VueRouter)
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/Detail.vue')
}
]
}
]
const router = new VueRouter({
routes
})
export default router
// 通过this.$router打点调用replace/push/go方法实现路由切换
// 例如:
this.$router.replace('/login')
this.$router.go(1)
this.$router.push({ name: 'Detail', params: { id: 1 } })
// 其中replace方法不会记录本次历史。
// Hash模式:URL中#后面的内容最为路径地址;监听hashchange事件;根据当前路由地址找到对应的组件重新渲染
// History模式:通过history.pushState()方法改变地址栏;监听popstate事件;根据当前路由地址找到对应组件重新渲染;
let _Vue = null
export default class VueRouter {
static install (Vue) {
// 1、判断当前插件是否已经被安装
if (VueRouter.install.installed) {
// 如果有直接返回;不需要做操作
return
}
VueRouter.install.installed = true
// 2、把构造函数记录到全局上面:作用:在VueRouter的实例方法中用到这个构造函数,在创建组件的时候可以用到:Vue.component
_Vue = Vue
// 3、把创建Vue实例时候传入的router注入到Vue实例上
// 混入
_Vue.mixin({
// 所有的Vue实例中;所有的组件中都会执行这个;但是只需要Vue是实例中执行一次就行;vue实例中才会有this.$options.router
beforeCreate () {
if (this.$options.router) {
_Vue.prototype.$router = this.$options.router
// this.$options.router.init()
}
}
})
}
// 构造函数(需要初始化三个属性:options,data,routeMap)
constructor (options) { // options里有routers路由规则
this.options = options
this.routeMap = {}
// data是响应式的对象
this.data = _Vue.observable({
current: '/' // 当前的路由地址
})
this.init()
}
init () {
this.createRouteMap()
this.initComponents(_Vue)
this.initEvent()
}
// createRouteMap
createRouteMap () {
// 遍历所有的路由规则,把他们解析成键值对的形式,存储到routerMap中
this.options.routes.forEach(el => {
// console.log(el.path, '这个是路由规则', el.component);
this.routeMap[el.path] = el.component
})
}
// initComponents
initComponents (Vue) {
Vue.component('router-link', {
// 接受外部传入的参数:props
props: {
to: String
},
// vue的构建版本:运行时版:不支持template模板,需要打包的时候提前编译;完整版:包含运行时和编译器,体积比运行时版大10k左右,程序运行的时候把模板转换成render函数
// vue-cli创建的项目都是运行时版本的;如果需要改成完整版的,在项目中创建vue.config.js文件;写入:module.exports ={
// runtimeComiler:true
// }
// template: '<a :href="to"><slot></slot></a>'
render (h) {
// h函数的三个参数:第一个是标签名,第二个是标签属性;第三个是标签内容
return h('a', {
attrs: { // dom对象的属性attrs:
href: '#' + this.to
},
on: {
click: this.clickHandler
}
}, [this.$slots.default]) //this.$slots.default获取默认插槽
},
methods: {
clickHandler (e) {
history.pushState({}, '', this.to)
this.$router.data.current = '#' + this.to
console.log(this.to);
e.preventDefault();
}
}
})
// router-view
const that = this
Vue.component('router-view', {
render (h) {
// 先要找到当前路由地址,然后在routerMap对象中找到对应的组件,调用h函数把找到的组件转换为虚拟DOM直接返回
const component = that.routeMap[that.data.current.replace('#', '')]
// console.log(that.data.current, '当前地址', that.routeMap);
return h(component)
}
})
}
// initEvent
initEvent () {
window.addEventListener('hashchange', () => {
// this.data.current = window.location.pathname
console.log(window.location.pathname);
})
}
}
// 模拟history模式
console.dir(Vue)
let _Vue = null
class VueRouter {
static install (Vue) {
//1 判断当前插件是否被安装
if (VueRouter.install.installed) {
return;
}
VueRouter.install.installed = true
//2 把Vue的构造函数记录在全局
_Vue = Vue
//3 把创建Vue的实例传入的router对象注入到Vue实例
// _Vue.prototype.$router = this.$options.router
// 混入选项
_Vue.mixin({
beforeCreate () { // 这个钩子函数就可以获取到vue实例
if (this.$options.router) { //
_Vue.prototype.$router = this.$options.router
}
}
})
}
// 构造函数
constructor (options) {
this.options = options
this.routeMap = {}
// observable 创建响应式的对象;可以直接用在渲染函数、计算属性里面
this.data = _Vue.observable({
current: "/"
})
this.init()
}
init () {
this.createRouteMap()
this.initComponent(_Vue)
this.initEvent()
}
createRouteMap () {
//遍历所有的路由规则 把路由规则解析成键值对的形式存储到routeMap中
this.options.routes.forEach(route => {
// route.path:路由的路径;route.component路由对应的组件
this.routeMap[route.path] = route.component
});
}
initComponent (Vue) {
// 创建组件
Vue.component("router-link", {
props: {
to: String
},
// render渲染函数
render (h) {
// 第一个参数是选择器;第二个是标签的属性
return h("a", {
attrs: { // dom对象的属性
href: this.to
},
// 注册点击事件
on: {
click: this.clickhander
}
// 第三个参数是标签里面的子元素
// 获取默认插槽this.$slots.default
}, [this.$slots.default])
},
methods: {
clickhander (e) {
// history.pushState()方法会改变地址栏的地址;但是不会向服务器发送请求
history.pushState({}, "", this.to)
this.$router.data.current = this.to
e.preventDefault() // 阻止点击事件的默认行为
}
}
// <slot></slot>就是插槽
// template:"<a :href='to'><slot></slot><>"
})
const self = this
Vue.component("router-view", {
render (h) {
// self.data.current
const cm = self.routeMap[self.data.current]
return h(cm) // h函数也可以直接把一个组件转换为虚拟DOM返回
}
})
}
initEvent () {
//popstate事件是当历史发生变化的时候触发
window.addEventListener("popstate", () => {
// 更改当前相应的组件
this.data.current = window.location.pathname
})
}
}