2019-01-12 11:33:27 +08:00
|
|
|
import PropTypes from '../_util/vue-types';
|
|
|
|
import { cloneElement } from '../_util/vnode';
|
|
|
|
import { filterEmpty, getComponentFromProp, getSlotOptions } from '../_util/props-util';
|
|
|
|
import warning from '../_util/warning';
|
2019-03-13 09:38:54 +08:00
|
|
|
import { ConfigConsumerProps } from '../config-provider';
|
2019-01-12 11:33:27 +08:00
|
|
|
import BreadcrumbItem from './BreadcrumbItem';
|
2020-03-07 19:45:13 +08:00
|
|
|
import Menu from '../menu';
|
2018-01-15 10:52:16 +08:00
|
|
|
|
2018-03-10 13:34:26 +08:00
|
|
|
const Route = PropTypes.shape({
|
|
|
|
path: PropTypes.string,
|
|
|
|
breadcrumbName: PropTypes.string,
|
2020-03-07 19:45:13 +08:00
|
|
|
children: PropTypes.array,
|
2019-01-12 11:33:27 +08:00
|
|
|
}).loose;
|
2018-03-10 13:34:26 +08:00
|
|
|
|
|
|
|
const BreadcrumbProps = {
|
2019-03-13 09:38:54 +08:00
|
|
|
prefixCls: PropTypes.string,
|
2018-03-10 13:34:26 +08:00
|
|
|
routes: PropTypes.arrayOf(Route),
|
|
|
|
params: PropTypes.any,
|
|
|
|
separator: PropTypes.any,
|
|
|
|
itemRender: PropTypes.func,
|
2019-01-12 11:33:27 +08:00
|
|
|
};
|
2018-03-10 13:34:26 +08:00
|
|
|
|
2019-01-12 11:33:27 +08:00
|
|
|
function getBreadcrumbName(route, params) {
|
2018-03-10 13:34:26 +08:00
|
|
|
if (!route.breadcrumbName) {
|
2019-01-12 11:33:27 +08:00
|
|
|
return null;
|
2018-01-15 10:52:16 +08:00
|
|
|
}
|
2019-01-12 11:33:27 +08:00
|
|
|
const paramsKeys = Object.keys(params).join('|');
|
2018-03-10 13:34:26 +08:00
|
|
|
const name = route.breadcrumbName.replace(
|
|
|
|
new RegExp(`:(${paramsKeys})`, 'g'),
|
|
|
|
(replacement, key) => params[key] || replacement,
|
2019-01-12 11:33:27 +08:00
|
|
|
);
|
|
|
|
return name;
|
2018-03-10 13:34:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export default {
|
2018-04-08 21:17:20 +08:00
|
|
|
name: 'ABreadcrumb',
|
2018-03-10 13:34:26 +08:00
|
|
|
props: BreadcrumbProps,
|
2019-03-13 09:38:54 +08:00
|
|
|
inject: {
|
2019-09-11 22:35:25 +08:00
|
|
|
configProvider: { default: () => ConfigConsumerProps },
|
2019-03-13 09:38:54 +08:00
|
|
|
},
|
2018-03-10 13:34:26 +08:00
|
|
|
methods: {
|
2019-01-12 11:33:27 +08:00
|
|
|
defaultItemRender({ route, params, routes, paths }) {
|
|
|
|
const isLastItem = routes.indexOf(route) === routes.length - 1;
|
|
|
|
const name = getBreadcrumbName(route, params);
|
|
|
|
return isLastItem ? <span>{name}</span> : <a href={`#/${paths.join('/')}`}>{name}</a>;
|
2018-03-10 13:34:26 +08:00
|
|
|
},
|
2020-03-07 19:45:13 +08:00
|
|
|
getPath(path, params) {
|
|
|
|
path = (path || '').replace(/^\//, '');
|
|
|
|
Object.keys(params).forEach(key => {
|
|
|
|
path = path.replace(`:${key}`, params[key]);
|
|
|
|
});
|
|
|
|
return path;
|
|
|
|
},
|
|
|
|
|
|
|
|
addChildPath(paths, childPath, params) {
|
|
|
|
const originalPaths = [...paths];
|
|
|
|
const path = this.getPath(childPath, params);
|
|
|
|
if (path) {
|
|
|
|
originalPaths.push(path);
|
|
|
|
}
|
|
|
|
return originalPaths;
|
|
|
|
},
|
|
|
|
|
2020-03-18 14:52:02 +08:00
|
|
|
genForRoutes({ routes = [], params = {}, separator, itemRender = this.defaultItemRender }) {
|
2020-03-07 19:45:13 +08:00
|
|
|
const paths = [];
|
|
|
|
return routes.map(route => {
|
|
|
|
const path = this.getPath(route.path, params);
|
|
|
|
|
|
|
|
if (path) {
|
|
|
|
paths.push(path);
|
|
|
|
}
|
|
|
|
// generated overlay by route.children
|
|
|
|
let overlay = null;
|
|
|
|
if (route.children && route.children.length) {
|
|
|
|
overlay = (
|
|
|
|
<Menu>
|
|
|
|
{route.children.map(child => (
|
|
|
|
<Menu.Item key={child.breadcrumbName || child.path}>
|
|
|
|
{itemRender({
|
|
|
|
route: child,
|
|
|
|
params,
|
|
|
|
routes,
|
|
|
|
paths: this.addChildPath(paths, child.path, params),
|
|
|
|
h: this.$createElement,
|
|
|
|
})}
|
|
|
|
</Menu.Item>
|
|
|
|
))}
|
|
|
|
</Menu>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<BreadcrumbItem
|
|
|
|
overlay={overlay}
|
|
|
|
separator={separator}
|
|
|
|
key={route.breadcrumbName || path}
|
|
|
|
>
|
|
|
|
{itemRender({ route, params, routes, paths, h: this.$createElement })}
|
|
|
|
</BreadcrumbItem>
|
|
|
|
);
|
|
|
|
});
|
|
|
|
},
|
2018-03-10 13:34:26 +08:00
|
|
|
},
|
2019-01-12 11:33:27 +08:00
|
|
|
render() {
|
|
|
|
let crumbs;
|
2019-03-13 09:38:54 +08:00
|
|
|
const { prefixCls: customizePrefixCls, routes, params = {}, $slots, $scopedSlots } = this;
|
2019-09-11 22:35:25 +08:00
|
|
|
const getPrefixCls = this.configProvider.getPrefixCls;
|
2019-03-13 09:38:54 +08:00
|
|
|
const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls);
|
|
|
|
|
2019-01-12 11:33:27 +08:00
|
|
|
const children = filterEmpty($slots.default);
|
|
|
|
const separator = getComponentFromProp(this, 'separator');
|
2020-03-07 19:45:13 +08:00
|
|
|
const itemRender = this.itemRender || $scopedSlots.itemRender || this.defaultItemRender;
|
2018-03-10 13:34:26 +08:00
|
|
|
if (routes && routes.length > 0) {
|
2020-03-07 19:45:13 +08:00
|
|
|
// generated by route
|
|
|
|
crumbs = this.genForRoutes({
|
|
|
|
routes,
|
|
|
|
params,
|
|
|
|
separator,
|
|
|
|
itemRender,
|
2019-01-12 11:33:27 +08:00
|
|
|
});
|
2018-03-10 13:34:26 +08:00
|
|
|
} else if (children.length) {
|
|
|
|
crumbs = children.map((element, index) => {
|
|
|
|
warning(
|
2020-03-07 19:45:13 +08:00
|
|
|
getSlotOptions(element).__ANT_BREADCRUMB_ITEM ||
|
|
|
|
getSlotOptions(element).__ANT_BREADCRUMB_SEPARATOR,
|
|
|
|
'Breadcrumb',
|
|
|
|
"Only accepts Breadcrumb.Item and Breadcrumb.Separator as it's children",
|
2019-01-12 11:33:27 +08:00
|
|
|
);
|
2018-03-10 13:34:26 +08:00
|
|
|
return cloneElement(element, {
|
|
|
|
props: { separator },
|
|
|
|
key: index,
|
2019-01-12 11:33:27 +08:00
|
|
|
});
|
|
|
|
});
|
2018-03-10 13:34:26 +08:00
|
|
|
}
|
2019-01-12 11:33:27 +08:00
|
|
|
return <div class={prefixCls}>{crumbs}</div>;
|
2018-03-10 13:34:26 +08:00
|
|
|
},
|
2019-01-12 11:33:27 +08:00
|
|
|
};
|