UNPKG

@hippy/vue-router

Version:

Official router for hippy-vue

143 lines (128 loc) 4.08 kB
/* * Tencent is pleased to support the open source community by making * Hippy available. * * Copyright (C) 2017-2019 THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* eslint-disable no-underscore-dangle */ /* eslint-disable no-param-reassign */ import { warn } from '../util/warn'; function resolveProps(route, config) { switch (typeof config) { case 'undefined': return null; case 'object': return config; case 'function': return config(route); case 'boolean': return config ? route.params : undefined; default: if (process.env.NODE_ENV !== 'production') { warn( false, `props in "${route.path}" is a ${typeof config}, ` + 'expecting an object, function or boolean.', ); } return null; } } export default { name: 'RouterView', functional: true, props: { name: { type: String, default: 'default', }, }, render(_, { props, children, parent, data, }) { // used by devtools to display a router-view badge data.routerView = true; // directly use parent context's createElement() function // so that components rendered by router-view can resolve named slots const h = parent.$createElement; const { name } = props; const route = parent.$route; const cache = parent._routerViewCache || (parent._routerViewCache = {}); // determine current view depth, also check to see if the tree // has been toggled inactive but kept-alive. let depth = 0; let inactive = false; while (parent && parent._routerRoot !== parent) { if (parent.$vnode && parent.$vnode.data.routerView) { depth += 1; } if (parent._inactive) { inactive = true; } parent = parent.$parent; } data.routerViewDepth = depth; // render previous view if the tree is inactive and kept-alive if (inactive) { return h(cache[name], data, children); } const matched = route.matched[depth]; // render empty node if no matched route if (!matched) { cache[name] = null; return h(); } const component = matched.components[name]; cache[name] = component; // attach instance registration hook // this will be called in the instance's injected lifecycle hooks data.registerRouteInstance = (vm, val) => { // val could be undefined for unregistration const current = matched.instances[name]; if ( (val && current !== vm) || (!val && current === vm) ) { matched.instances[name] = val; } }; // also register instance in prepatch hook // in case the same component instance is reused across different routes if (!data.hook) { data.hook = {}; } data.hook.prepatch = (__, vnode) => { matched.instances[name] = vnode.componentInstance; }; // resolve props let propsToPass = resolveProps(route, matched.props && matched.props[name]); data.props = propsToPass; if (propsToPass) { // clone to prevent mutation propsToPass = { ...propsToPass }; data.props = propsToPass; // pass non-declared props as attrs const attrs = data.attrs || {}; Object.keys(propsToPass).forEach((key) => { if (!component.props || !(key in component.props)) { attrs[key] = propsToPass[key]; delete propsToPass[key]; } }); } return h(component, data, children); }, };