创建Vue项目
- 首先我们通过
vue create vueApp
来创建一个vue的项目, - 进入
vueApp
后执行vue add router
载入vue-router - 执行
npm run serve
打开浏览器,发现我们的项目已经初始化完成了
Vue Router 分析
首先我们对Vue Router功能进行简单的分析:
- 他是前端路由,当路径切换的时候,在浏览器端判断路径,并加载当前路径对应的组件
- 他有两种模式,一种是hash,一种是history
- hash模式是基于锚点,以及onhashchange事件
- history模式是基于html5只不过的History API
- history.pushState() IE10以后才支持
- history.replaceState()
- history简单的工作流程
- 通过 history.pushState()方法改变地址栏
- 监听 popstate 事件
- 根据当前路由地址找到对应组件重新渲染
- 接下来我们去项目中看下vue-router 是如何使用的
- 下面是VueRouter的一个类图,我们接下来根据这个类图来实现VueRouter
模拟实现Vue Router
回到刚创建的vueApp
项目中,在src下创建一个vuerouter
文件夹,并添加index.js
在这个文件夹,此文件夹存放我们自己写的vue-router
模块,在index.js
中进行开发
install 方法
install的分析
- Vue.use()调用VueRouter时会传递两个参数,一个是Vue的构造函数,第二个是可选的选项对象(本文中没用到这个参数)
- install是一个静态方法静态方法,接收VueRouter传递的两个参数
- 函数内部首先判断下这个插件是否被安装
- 在全局作用域储存Vue构造函数(后面还需要调用Vue构造函数)
- 把创建Vue实例时传入的router对象,注入到所有Vue实例上(this.$router就是在这个时候注册到Vue实例上的)
代码实现
let _Vue = null
export default class VueRouter {
static install(Vue){
if(VueRouter.install.installed) {
return
}
VueRouter.install.installed = true
_Vue = Vue
_Vue.mixin({
beforeCreate(){
if(this.$options.router){
_Vue.prototype.$router = this.$options.router;
this.$options.router.init() // 调用init()方法,此方法定义在下文中可以看到
}
}
})
}
}
构造函数
构造函数分析
- 观察上文中的类图,发现构造函数接收一个参数options
- 在构造函数中初始化类图中的三个属性
- options:存储传入的参数options
- routeMap: 存储键值对,值可以从传入options中routes里面中拿到,键:path, 值:component
- data 是一个响应式对象,里面current存放当前的路由地址
代码实现
constructor(options) {
this.options = options
this.routeMap = {}
this.data = _Vue.ovservable({
current: '/'
})
}
createRouteMap
函数分析
- 遍历所有的路由规则(options.route),把路由规则转换成上文说的键值对形式 存在routeMap对象中去
代码实现
createRouteMap(){
this.options.routes.forEach(route => {
this.routeMap[route.path] = route.component
})
}
initComponents
函数分析
- 这个方法接收一个Vue构造函数(也可以不去传这个参数,因为我们在全局已经存储到_Vue了,这样做的目的是为了减少此模块对其他模块的依赖)
- 这个方法是创建router-link组件
- router-link在使用的时候,传入了to属性
- router-link最终渲染的时候是一个a标签
- router-link中间会有一些展示内容
代码实现
? template参数方式创建会有些小坑,后面会说到
initComponents(Vue){
Vue.component('router-link',{
props: {
to: String,
},
template: '<a :herf="to"><slot></slot></a>'
})
}
init函数
这个函数没什么特别的 就是帮助我们执行一些初始化的方法
init(){
this.createRouteMap()
this.initComponents(_Vue)
}
// 在instll中调用,调用位置参看上面的install方法
- 初始化完成后去修改router.js文件中导入VueRouter的模块,然后重新运行项目
- 运行后报错,You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build . 我们正在使用只包含运行版本的Vue,模板编译器不可用,这里就引出了关于Vue构建版本的问题
Vue构建版本
- 运行时版: 不支持template模板,需要打包的时候提前编译
- 完整版:包含运行时编译器的完整版,体积比运行时版本大10K左右,程序运行的时候把模板转换成render函数
解决方法
? 来解决上面说的template参数的坑啦,两种方式解决:1.使用Vue完整版 2.使用render函数
- 使用Vue完整版
思路就是将当前运行时版改成完整版,创建vue.config.js
module.exports={
runtimeCompiler: true // 启动包含运行时编译器的完整版
}
这个方法主要是开启完整版,对于配置的具体说明本文就不过多赘述,详情可以参考vue官方文档
- 使用render函数
initComponents(Vue){
Vue.component('router-link',{
props: {
to: String,
},
render(h){
return h('a', {
attrs: {
herf: this.to
},
},[this.$slots.default]);
}
// template: '<a :herf="to"><slot></slot></a>'
})
}
router-view组件
组件分析
- 相当于一个占位符,在这个组件内部,根据当前的路由地址获取到对应的组件,并渲染到router-view的位置
- 在initComponents 函数中继续创建router-view组件
- 上面我们已经知道如何去创建一个组件,现在思考一下在创建组件的render函数中需要进行什么样的操作
- 获取到当前的路由地址,根据路由地址在routeMap中找到对应的组件
- 然后调用h函数帮我们把找到的组件转成虚拟dom返回
initComponents(Vue){
Vue.component('router-link',{
props: {
to: String,
},
render(h){
return h('a', {
attrs: {
herf: this.to
},
on: {
click: this.clickHandler
}
},[this.$slots.default]);
},
methods: {
clickHandler(e){
// 改变浏览器地址栏,但是不会向浏览器发请求
history.pushState({}, '', this.to)
// 把当前路径记录到current里面
this.$router.data.current = this.to
e.preventDefault();
}
}
// template: '<a :herf="to"><slot></slot></a>'
})
const self = this
Vue.component('router-view',{
render(h){
const component = self.routeMap[self.data.current]
return h(component)
}
})
}
initEvent
- 点击浏览器的前进和后退按钮,地址栏发生了改变,但是视图没有发生变化,下面我来解决这个问题
- 这个方法的作用是用来注册popstate事件
initEvent(){
window.addEventListener('popstate',()=>{
this.data.current = window.location.pathname
})
}
// 然后在init方法中调用此方法
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!