We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
注册路由插件,制定路由规则
创建router对象,导出
注册router对象。创建Vue实例的时候,传入router对象,Vue实例中被注入两个属性:
$route:路由规则
$route
$router:路由相关的方法
$router
创建路由组件的占位<router-view/>
<router-view/>
创建链接<router-link/>
<router-link/>
{ path:'xxx/:id', //props:true, //开启props,会把URL中的参数传递给组件 //在组件中通过props来接收URL参数 name:'xxx', //命名式导航 commponent:() => import('../xxx/xxx.vue') }
通过当前路由规则,获取数据。强依赖路由。
{{$route.params.id}}
父子组件传值的方式:路由规则中开启props传参。不依赖路由。
父子组件传值的方式
{{id}}
export default { props: ['id'] }
layout.vue嵌套到index.vue/ details.vue中输出,使之拥有相同的头和尾
layout.vue
index.vue
details.vue
//index.js //配置路由 import Layout from '@/commponents/Layout.vue' const routes = [ //嵌套路由:先加载Layout组件,再加载Index/Detail组件 { path:'/', component:Layout, children: [ //首页 { name: 'index', path: '',//相对路径'/' component: Index }, //详情页 { name: 'detail', path: 'detail/:id', props: true, component: () => import('@/views/Detail.vue')//'/Detail.vue' } ] } ]
this.$router.push('/') this.$router.push({name:'Home'})
this.$router.replace('/login') //不会记录当前历史
this.$router.go(-2)
表现形式:
http://xxx.com/#/xxx?id=11
http://xxx.com/xxx/222
原理:
Hash:基于锚点,以及onhashchange事件
onhashchange
调用push方法会先判断当前浏览器是否支持window.pushState,再调用pushState改变地址栏; 否则通过window.loaction改变地址栏
调用push方法会先判断当前浏览器是否支持window.pushState,再调用pushState改变地址栏;
window.pushState
pushState
否则通过window.loaction改变地址栏
window.loaction
History:基于HTML5中的HistoryAPI
HistoryAPI
history.pushState()
history.replaceState()
此模式下调用router.push(url)方法时,push方法内部会直接调用window.history.pushState,把url设置到浏览器的地址栏 window.history.pushState不能触发popstate事件,当历史状态被激活的时候才会触发popstate
此模式下调用router.push(url)方法时,push方法内部会直接调用window.history.pushState,把url设置到浏览器的地址栏
router.push(url)
window.history.pushState
window.history.pushState不能触发popstate事件,当历史状态被激活的时候才会触发popstate
两者都是客户端修改URL,性能相差不大
http://www.xx.com/login
index.html
//index.js const routes = [ { path:'*', name:'404', compontent: () => import('../xxx/404.vue') } ] const router = new VueRouter({ mode: 'history', routes })
node配置的服务器app.js:
app.js
//app.js const path = require('path')//可以合并两个路径 //导入处理hitory模式的模块 const history = require('connect-history-fallback') //导入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, () => { console.log("服务器开启,端口:3000") })
中间件?
app.use(history()) node app.js
(不能有中文)
start nginx nginx -s reload nginx -s stop
Vue.observable():可以使用Vue.observable()把任意对象转换成响应式对象,Vue.observable()返回的对象没有办法在模板中直接使用,但可以在h()函数中使用
Vue.observable()
h()
Hash模式:
hashchange
History模式:
popstate
类图:
install
//./vuerouter/index.js let _Vue = null export default class VueRouter { static install() { if(VueRouter.install.installed){ return } VueRouter.install.installed = true//当前插件被安装了 _Vue = Vue //_Vue.prototype.$router = this.$options.router //混入 _Vue.mixin({ beforeCreate(){ //组件orvue实例 if(this.$options.router) { _Vue.prototype.$router = this.$options.router//只需要执行一次 this.$options.router.init() } } }) } } /** * 1.判断当前插件是否重复被安装 * 2.install静态方法接收了静态函数,将来要在vue的实例方法中使用这个函数,要把vue构造函数记录到全局变量中 * 3.把创建vue实例时候传入的router对象注入到vue实例上 */
构造函数
constructor (options) { this.options = options this.routeMap = {} this.data = _Vue.observable({ current: '/'//存储当前路由地址 }) //三个所需要的属性 }
createRouteMap:把构造函数传过来的选项中的rules(路由规则)转换为键值对的形式存储到routerMap.
createRouteMap
路由规则
routerMap
routerMap中存储的键的值就是路由中对应的组件。如果路由发生变化,很容易根据地址在routeMap中找到组件,并且渲染到视图上。
createRouteMap() { // 遍历所有的路由规则,把路由规则解析成键值对的形式,存储到routeMap中 this.options.routes.forEach(route => { this.routeMap[route.path] = route.component }) }
initComponents:
initComponents
router-link
//参数vue为了减少和外部的依赖 initComponents (Vue) { vue.component('router-link',{ props: { to: String, }, template: '<a :href = "to"><slot></slot></a>' }) }
init:包装initComponents和createRouteMap方法让外部使用方便
init
init() { this.createRouteMap() this.initComponents(_Vue)//传入vue的构造函数 }
Vue的构建版本 运行时版:不支持template模板,需要打包的时候提前编译 完整版:包含运行时和编译器,体积比运行时版大10K左右,程序运行的时候把模板转换成render函数 完整版性能不如运行时版本 vuecli默认使用运行时版本
Vue的构建版本
运行时版:不支持template模板,需要打包的时候提前编译
template
完整版:包含运行时和编译器,体积比运行时版大10K左右,程序运行的时候把模板转换成render函数
render
完整版性能不如运行时版本
vuecli默认使用运行时版本
Vue-cli中方法,runtimeCompiler:是否使用包含运行时编译器的Vue构建版本。设置为true后可以在Vue组件中使用template选项
runtimeCompiler
创建./vue.config.js
./vue.config.js
module.exports = { runtimeCompiler: true, }
关注:render函数怎么写
因为运行版本不支持template选项,需要修改initComponents
initComponents(Vue){ Vue.component('router-link', { props: { to: String } }, //h创建虚拟DOM render (h) { return h('a', { attrs: { herf: this.to//history模式 }//设置DOM属性 }, [this.$slots.default]) //获取默认插槽设置到a标签里 } //template:... ) }
router-view
initComponents (Vue) { Vue.component('router-link', { props: { to: String } }, render (h) { return h('a', { attrs: { herf: this.to }, on: { click: this.clickHandler },//给a标签注册一个跳转功能 }, [this.$slots.default]) methods:{ clickHander (e) { //1.改变浏览器的地址栏 history.pushState({}, '', this.to) //2.把当前路径记录到data.current里 this.$router.data.current = this.to e.preventDefault() //事件处理函数,调用默认行为 } } } ) const self = this Vue.component('route-view', { render (h) { //在render内部首先要找到路由地址,再根据当前路由的地址,在routeMap对象中找到路由地址对应的组件,再调用h函数帮这个组件转换成虚拟DOM,然后返回 const component = self.routeMap[self.data.current]//获取路由地址 return h(component) } }) }
initEvent:当地址变化的时候,改变页面元素的逻辑
initEvent
init() { this.createRouteMap() this.initComponents(_Vue) this.initEvent() } initEvent () { window.addEventListener('popstate', ()=> { this.data.current = window.location.pathname }) }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
Vue Router实现原理
基础回顾
Ⅰ、创建路由
注册路由插件,制定路由规则
创建router对象,导出
注册router对象。创建Vue实例的时候,传入router对象,Vue实例中被注入两个属性:
$route
:路由规则$router
:路由相关的方法创建路由组件的占位
<router-view/>
创建链接
<router-link/>
Ⅱ、动态路由传参
通过当前路由规则,获取数据。强依赖路由。
父子组件传值的方式
:路由规则中开启props传参。不依赖路由。Ⅲ、嵌套路由
layout.vue
嵌套到index.vue
/details.vue
中输出,使之拥有相同的头和尾Ⅳ、编程式导航
Hash模式和History模式
Ⅰ、区别
表现形式:
http://xxx.com/#/xxx?id=11
很丑http://xxx.com/xxx/222
原理:
Hash:基于锚点,以及
onhashchange
事件History:基于HTML5中的
HistoryAPI
history.pushState()
IE10以后才支持history.replaceState()
两者都是客户端修改URL,性能相差不大
Ⅱ、History模式
http://www.xx.com/login
会返回找不到页面index.html
Ⅲ、node.js服务器配置
node配置的服务器
app.js
:http://www.xx.com/login
会返回找不到页面,所以要在服务端配置支持Ⅳ、nginx服务器配置
(不能有中文)
实现自己的Vue Router
Ⅰ、实现原理
Hash模式:
hashchange
事件History模式:
history.pushState()
方法改变地址栏popstate
事件Ⅱ、分析
类图:
Ⅲ、代码实现
install
构造函数
createRouteMap
:把构造函数传过来的选项中的rules(路由规则
)转换为键值对的形式存储到routerMap
.routerMap中存储的键的值就是路由中对应的组件。如果路由发生变化,很容易根据地址在routeMap中找到组件,并且渲染到视图上。
initComponents
:router-link
组件init
:包装initComponents
和createRouteMap
方法让外部使用方便Vue-cli中方法,
runtimeCompiler
:是否使用包含运行时编译器的Vue构建版本。设置为true后可以在Vue组件中使用template
选项创建
./vue.config.js
关注:
render
函数怎么写因为运行版本不支持template选项,需要修改
initComponents
router-view
组件,并且使路由转跳都在客户端操作,页面不刷新,但地址栏发生变化initEvent
:当地址变化的时候,改变页面元素的逻辑The text was updated successfully, but these errors were encountered: