最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 如何实现vue-router

    正文概述 掘金(川普_莱茵哈特)   2021-02-23   595

    vue-router使用

    import VueRouter from 'vue-router'
    
    // 1、引入
    Vue.use(VueRouter) // 插件install
    
    
    const routes = [
      {
        path: '/',
        name: 'Home',
        component: Home
      }
    ]
    
    // 2、new对象
    const router = new VueRouter({
      routes
    })
    
    // 3、放到opstions里面
    new Vue({
      router,
      store,
      render: h => h(App)
    }).$mount('#app')
    
    

    实现一个简版

    my-router.js

    类vue-router

    1、构造函数,保存options、设置初始值,作响应式,加监听

    let Vue
    
    class VueRouter {
      // 构造器
      	constructor(options) {
      	    // 保存options
    		this.$options = options
    		
    		// 设初值
    		const initVal = window.location.hash.slice(1) || '/'
    		this.current = initVal
    		console.log('this.current', this.current)
    		
    		// 作响应式
    		Vue.util.defineReactive(this, 'matched', [])
    		// this.current = window.location.hash.slice(1) || '/'
    		
    		// 加监听
    		this.hashChange = this.hashChange.bind(this)
    		window.addEventListener('hashchange', this.hashChange)
    	}
    	
    	// 监听的值变化实际操作
    	hashChange() {
    		this.current = window.location.hash.slice(1)
    		this.matched = [] 
    		this.match() // 重新匹配
    	}
    	
    	match(routes) {
    	    // 一般直接取options
    		routes = routes || this.$options.routes
    		
    		// match的会生成一个数组
    		// 比如 /about/info
    		// match会生成 ['/about', '/about/info'] // 实际存的是对象
    		for (const route of routes) {
    			if (route.path === '/' && this.current === '/') {
    				this.matched.push(route)
    				return
    			}
    			if (route.path !== '/' && this.current.indexOf(route.path) > -1) {
    				this.matched.push(route)
    			}
    			if (route.children && route.children.length > 0) {
    				route.children.forEach((ele) => {
    					if (ele.path !== '/' && this.current.indexOf(ele.path) > -1) {
    						this.matched.push(ele)
    					}
    				})
    			}
    		}
    	}
    }
    

    2、install 方法实现,直接挂在静态下

    VueRouter.install = function(_Vue) {
    	Vue = _Vue
    	
    	// 利用全局混入,延迟执行下面的代码,这样可以获取router实例
    	Vue.mixin({
    		beforeCreate() {
    			// 组件实例
    			if (this.$options.router) {
    				Vue.prototype.$router = this.$options.router
    			}
    		},
    		beforeDesotry() {
    		}
    	})
    	
    	// 注册组件 router-link、router-view实现
    	// ....
    	
    }
    
    	
    export default VueRouter;
    
    

    router-link 实现

    Vue.component('router-link', {
    	props: {
    		to: {
    			type: String,
    			required: true
    		}
    	},
    	render(h) {
    		return h(
    			'a',
    			{
    				attrs: {
    					href: '#' + this.to
    				}
    			},
    			this.$slots.default
    		)
    	}
    })
    

    router-view 实现

    Vue.component('router-view', {
    	render(h) {
    		this.$vnode.data.routerView = true
    		let depth = 0
    		let parent = this.$parent
    		while (parent) {
    			const vnodeData = parent.$vnode && 
    			parent.$vnode.data
    			if (vnodeData && vnodeData.routerView) {
    				// 说明当前parent时routerview
    				depth++
    			}
    			parent = parent.$parent
    		}
    		
    		console.log('执行-routerview渲染--')
    		console.log('this.$router.current + '比较')
    		
    		let component = null
    		
    		// 获取path对应的component
    		const route = this.$router.matched[depth]
    		console.log(depth)
    		console.log(this.$router.matched)
    		if (route) {
    			component = route.component
    		} else {
    			component = this.$router.$options.notFund.component
    		}
    		// console.log(component)
    		return h(component)
    	}
    })
    

    3、vue-router源码里是如何生成matched的

    在util/route下存在以下方法

    function formatMatch (record: ?RouteRecord): Array<RouteRecord> {
      const res = []
      while (record) {
        res.unshift(record)
        record = record.parent
      }
      return res
    }
    

    4、源码vue-router问题解析

    问题1:每个组件都是怎么拿到router的?

    Vue.mixin 在beforeCreate时给根vue挂了个_router

    Vue.util.defineReactive(this, '_route', this._router.history.current)
    

    子组件在constructor的时候会走这一步:

    this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
    

    从 this._routerRoot 获取

      Object.defineProperty(Vue.prototype, '$router', {
        get () { return this._routerRoot._router }
      })
    
      Object.defineProperty(Vue.prototype, '$route', {
        get () { return this._routerRoot._route }
      })
    
    问题2:如何做响应式的?(即push后页面会进行替换)

    源码位置:src\index.js

    根vue实例里作了响应式

    Vue.util.defineReactive(this, '_route', this._router.history.current)
    

    vueRoutr对象内有个apps数组,存的是根实例。

    (为什么是数组,大概是处理多页面应用?)

    init时会添加个监听函数,当history的current变化时会同步修改 _route

    history.listen(function (route) {
      this.apps.forEach(function (app) {
        app._route = route;
      });
    });
    

    起源地下载网 » 如何实现vue-router

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元