【vue-router 源码04】<router-view />

198 阅读1分钟
export default {
    name: 'RouterView',
    functional: true,
    props: {
        name: {
            type: String,
            default: 'default'
        }
    },
    render(_, { props, children, parent, data }) {
        data.routerView = true // chrome dev插件显示
        
        const h = parent.$createElement
        const name = props.name
        const route = parent.$route // 响应依赖
        const cache = parent._routerViewCache || (parent._routerViewCache = {}) // 缓存
        
        let depth = 0
        let inactive = false
        while (parent && parent._routerRoot !== parent) {
            const vnodeData = parent.$vnode ? parent.$vnode.data : {}
            if (vnodeData.routerView) {
                depth++
            }
            if (vnodeData.keepAlive && parent._directInactive && parent._inactive) {
                inactive = true
            }
            parent = parent.$parent
        }
        data.routerViewDepth = depth
        const matched = route.matched[depth]
        const component = matched && matched.components[name]
        if (!matched || !component) {
            cache[name] = null
            return h()
        }
        // 计算深度,找出当前匹配组件
        
        cache[name] = { component } // 缓存
        
        data.registerRouteInstance = (vm, val) => {
            const current = matched.instances[name]
            if ((val && current !== vm) || (!val && current === vm)) {
                    matched.instances[name] = val // 注册vue实例
            }
        }
        // mixin 注册vue实例
        
        ;(data.hook || (data.hook = {})).prepatch = (_, vnode) => {
            matched.instances[name] = vnode.componentInstance
        }
        data.hook.init = vnode => {
            if (vnode.data.keepAlive && vnode.componentInstance && vnode.componentInstance !== matched.instances[name]) {
                matched.instances[name] = vnode.componentInstance
            }

            handleRouteEntered(route)
        }
        // 注册实例钩子
        
        const configProps = matched.props && matched.props[name]
        if (configProps) {
            extend(cache[name], {
                route,
                configProps
            })
            fillPropsinData(component, data, route, configProps)
        }
        // 传递属性 : 'props: true' => '/blog/:id', '(route) => return {}'
        
    }
    
}