Commit a104e5cc authored by Sendya's avatar Sendya

fix: breadcrumbRender and props breadcrumb #10

parent 1187b501
English | [简体中文](./README.zh-CN.md)
<h1 align="center">Ant Design Pro Layout</h1>
## Usage
```bash
......@@ -106,8 +107,12 @@ export default {
</script>
```
## API
### ProLayout
| Property | Description | Type | Default Value |
......@@ -127,15 +132,30 @@ export default {
| rightContentRender | header right content render method | (props: HeaderViewProps) => VNode | - |
| collapsedButtonRender | custom collapsed button method | (collapsed: boolean) => VNode | - |
| footerRender | custom footer render method | (props: BasicLayoutProps) => VNode | - |
| breadcrumbRender | custom breadcrumb render method | ({ route, params, routes, paths, h }) => VNode[] | - |
| i18nRender | i18n | Function (key: string) => string | - |
| handleMediaQuery | media matchs callback | (querys: []) => void | - |
| mediaQuery | media matchs | Array | - |
### PageHeaderWrapper
| Property | Description | Type | Default Value |
| --- | --- | --- | --- |
| content | Content area | VNode \| v-slot | - |
| extra | Extra content area, on the right side of content | VNode \| v-slot | - |
| extraContent | Extra content area, on the right side of content | VNode \| v-slot | - |
| tabList | Tabs title list | `Array<{key: string, tab: sting}>` | - |
| tab-change | Switch panel callback | (key) => void | - |
| tab-active-key | The currently highlighted tab item | string | - |
### SettingDrawer
#### {settings}
| Property | Description | Type | Default Value |
| ---- | ---- | ---- | ---- |
| theme | Theme | `dark` `light` `realDark` | `light` |
......
......@@ -102,8 +102,12 @@ export default {
</script>
```
## API
### ProLayout
| Property | Description | Type | Default Value |
......@@ -123,13 +127,30 @@ export default {
| rightContentRender | 自定义头右部的 render 方法 | (props: HeaderViewProps) => VNode | - |
| collapsedButtonRender | 自定义 侧栏收缩按钮 的方法 | (collapsed: boolean) => VNode | - |
| footerRender | 自定义 底部区域内容 | (props: BasicLayoutProps) => VNode | - |
| breadcrumbRender | 自定义面包屑渲染方法 | ({ route, params, routes, paths, h }) => VNode[] | - |
| i18nRender | 本地化渲染函数 (this.$t) | Function (key: string) => string | - |
| handleMediaQuery | 媒体查询回调 | (querys: []) => void | - |
| mediaQuery | ProLayout 当前的媒体查询 | Array | - |
### PageHeaderWrapper
| Property | Description | Type | Default Value |
| --- | --- | --- | --- |
| content | 内容区 | VNode \| v-slot | - |
| extra | 扩展区域 | VNode \| v-slot | - |
| extraContent | 扩展内容区 | VNode \| v-slot | - |
| tabList | Tabs 导航 | `Array<{key: string, tab: sting}>` | - |
| tab-change | Tab 改变事件 | (key) => void | - |
| tab-active-key | 当前 Tab 选中项 | string | - |
### SettingDrawer
#### {settings}
| Property | Description | Type | Default Value |
| ---- | ---- | ---- | ---- |
| theme | 主题 | `dark` `light` `realDark` | `light` |
......
......@@ -62,7 +62,7 @@ const asyncRouterMap = [
icon: 'smile',
title: 'menu.form.basicform'
},
component: () => import(/* webpackChunkName: "about" */ '../views/BlockPage')
component: () => import(/* webpackChunkName: "about" */ '../views/form/basic-form')
},
{
path: '/form/step-form',
......@@ -72,7 +72,7 @@ const asyncRouterMap = [
icon: 'smile',
title: 'menu.form.stepform'
},
component: () => import(/* webpackChunkName: "about" */ '../views/BlockPage')
component: () => import(/* webpackChunkName: "about" */ '../views/form/step-form')
},
{
path: '/form/advanced-form',
......@@ -82,7 +82,7 @@ const asyncRouterMap = [
icon: 'smile',
title: 'menu.form.advancedform'
},
component: () => import(/* webpackChunkName: "about" */ '../views/BlockPage')
component: () => import(/* webpackChunkName: "about" */ '../views/form/advanced-form')
}
]
},
......
export {
default as SettingOutline
} from '@ant-design/icons/lib/outline/SettingOutline'
export {
default as GithubOutline
} from '@ant-design/icons/lib/outline/GithubOutline'
export {
default as CopyrightOutline
} from '@ant-design/icons/lib/outline/CopyrightOutline'
/* MultiTab begin */
export {
default as CloseOutline
} from '@ant-design/icons/lib/outline/CloseOutline'
export {
default as ReloadOutline
} from '@ant-design/icons/lib/outline/ReloadOutline'
export {
default as DownOutline
} from '@ant-design/icons/lib/outline/DownOutline'
export {
default as AlignLeftOutline
} from '@ant-design/icons/lib/outline/AlignLeftOutline'
/* MultiTab end */
/* Layout begin */
export {
default as LeftOutline
......@@ -72,4 +47,34 @@ export {
export {
default as NotificationOutline
} from '@ant-design/icons/lib/outline/NotificationOutline'
export {
default as SettingOutline
} from '@ant-design/icons/lib/outline/SettingOutline'
export {
default as GithubOutline
} from '@ant-design/icons/lib/outline/GithubOutline'
export {
default as CopyrightOutline
} from '@ant-design/icons/lib/outline/CopyrightOutline'
/* Layout end */
/* Feedback begin */
export {
default as QuestionCircleOutline
} from '@ant-design/icons/lib/outline/QuestionCircleOutline'
/* Feedback end */
/* MultiTab begin */
export {
default as CloseOutline
} from '@ant-design/icons/lib/outline/CloseOutline'
export {
default as ReloadOutline
} from '@ant-design/icons/lib/outline/ReloadOutline'
export {
default as DownOutline
} from '@ant-design/icons/lib/outline/DownOutline'
export {
default as AlignLeftOutline
} from '@ant-design/icons/lib/outline/AlignLeftOutline'
/* MultiTab end */
......@@ -105,6 +105,7 @@ export default {
theme: 'dark',
// 主色调
primaryColor: '#1890ff',
colorWeak: false,
hideHintAlert: false,
hideCopyButton: false
......@@ -132,7 +133,6 @@ export default {
const menus = asyncRouterMap.find(item => item.path === '/').children
const handleSettingChange = ({ type, value, ...args }) => {
console.log('type', type, 'value', value, 'args:', args)
this.settings[type] = value
if (type === 'contentWidth') {
......@@ -148,6 +148,15 @@ export default {
}
}
// eslint-disable-next-line no-unused-vars
const breadcrumbRender = ({ route, params, routes, paths, h }) => {
return routes.indexOf(route) === routes.length - 1 && (
<span>{route.breadcrumbName}</span>
) || (
<router-link to={{ path: route.path || '/' }}>{route.breadcrumbName}</router-link>
)
}
const cdProps = {
props: {
...this.settings,
......@@ -162,6 +171,7 @@ export default {
footerRender,
i18nRender,
menuHeaderRender,
breadcrumbRender,
// logo: LogoSvg,
title: 'Ant Design Pro'
......
......@@ -15,13 +15,13 @@ const messages = {
}
const i18n = new VueI18n({
silentTranslationWarn: true,
locale: defaultLang,
fallbackLocale: defaultLang,
messages
})
const loadedLanguages = [defaultLang]
// eslint-disable-next-line
function setI18nLanguage (lang) {
i18n.locale = lang
......
import Vue from 'vue'
import VueRouter from 'vue-router'
import { asyncRouterMap } from '../config/router.config'
import { asyncRouterMap } from '@/config/router.config'
// hack router push/replace callback
['push', 'replace'].map(key => {
......@@ -20,6 +20,7 @@ Vue.use(VueRouter)
const routes = asyncRouterMap
const router = new VueRouter({
mode: 'history',
routes
})
......
<template>
<page-header-wrapper
:tab-list="tabList"
:tab-active-key="tabActiveKey"
:tab-change="(key) => {
this.tabActiveKey = key
console.log('PageHeader::tabChange', key)
}"
@back="() => {
console.log('PageHeader::@back')
}"
:back="() => {
// 自定义 back,不会覆盖 onBack 事件
console.log('PageHeader::.back')
}"
>
<template v-slot:content>
<span>{{ $t('pages.form.basicform.content') }}</span>
</template>
<template v-slot:extraContent>
<div><a-button>{{ $t('pages.form.basicform.headers.btn1') }}</a-button></div>
</template>
<div>
<strong>Advanced Form</strong>
</div>
</page-header-wrapper>
</template>
<script>
export default {
name: 'AdvancedForm',
data () {
return {
console: window.console,
tabList: [
{ tab: 'pages.form.basicform.tabs.tab1', key: 'tab1' },
{ tab: 'pages.form.basicform.tabs.tab2', key: 'tab2' },
{ tab: 'pages.form.basicform.tabs.tab3', key: 'tab3' }
],
tabActiveKey: 'tab1'
}
},
methods: {
handleTabChange (key) {
this.tabActiveKey = key
console.log('PageHeader::tabChange', key)
}
}
}
</script>
<style scoped>
</style>
<template>
<page-header-wrapper
:tab-list="tabList"
:tab-active-key="tabActiveKey"
:tab-change="(key) => {
this.tabActiveKey = key
console.log('PageHeader::tabChange', key)
}"
@back="() => {
console.log('PageHeader::@back')
}"
:back="() => {
// 自定义 back,不会覆盖 onBack 事件
console.log('PageHeader::.back')
}"
>
<template v-slot:content>
<span>{{ $t('pages.form.basicform.content') }}</span>
</template>
<template v-slot:extraContent>
<div><a-button>{{ $t('pages.form.basicform.headers.btn1') }}</a-button></div>
</template>
<div>
<strong>Basic Form</strong>
</div>
</page-header-wrapper>
</template>
<script>
export default {
name: 'BasicForm',
data () {
return {
console: window.console,
tabList: [
{ tab: 'pages.form.basicform.tabs.tab1', key: 'tab1' },
{ tab: 'pages.form.basicform.tabs.tab2', key: 'tab2' },
{ tab: 'pages.form.basicform.tabs.tab3', key: 'tab3' }
],
tabActiveKey: 'tab1'
}
},
methods: {
handleTabChange (key) {
this.tabActiveKey = key
console.log('PageHeader::tabChange', key)
}
}
}
</script>
<style scoped>
</style>
<template>
<page-header-wrapper
:tab-list="tabList"
:tab-active-key="tabActiveKey"
:tab-change="(key) => {
this.tabActiveKey = key
console.log('PageHeader::tabChange', key)
}"
@back="() => {
console.log('PageHeader::@back')
}"
:back="() => {
// 自定义 back,不会覆盖 onBack 事件
console.log('PageHeader::.back')
}"
:breadcrumb="customBreadcrumb"
>
<template v-slot:content>
<span>{{ $t('pages.form.basicform.content') }}</span>
</template>
<template v-slot:extraContent>
<div><a-button>{{ $t('pages.form.basicform.headers.btn1') }}</a-button></div>
</template>
<div>
<strong>Step Form</strong>
</div>
</page-header-wrapper>
</template>
<script>
export default {
name: 'StepForm',
data () {
return {
console: window.console,
tabList: [
{ tab: 'pages.form.basicform.tabs.tab1', key: 'tab1' },
{ tab: 'pages.form.basicform.tabs.tab2', key: 'tab2' },
{ tab: 'pages.form.basicform.tabs.tab3', key: 'tab3' }
],
tabActiveKey: 'tab1'
}
},
computed: {
customBreadcrumb () {
return {
props: {
routes: this.$route.matched.concat().map(route => {
return {
path: route.path,
breadcrumbName: this.$t(route.meta.title)
}
}),
itemRender: ({ route, params, routes, paths, h }) => {
return routes.indexOf(route) === routes.length - 1 && (
<span>{route.breadcrumbName}</span>
) || (
<router-link to={{ path: route.path || '/' }}>{route.breadcrumbName}</router-link>
)
}
}
}
}
},
methods: {
handleTabChange (key) {
this.tabActiveKey = key
console.log('PageHeader::tabChange', key)
}
}
}
</script>
<style scoped>
</style>
......@@ -93,8 +93,8 @@ const defaultConfig = {
}
},
devServer: {
// development server port 8000
port: 8000
// default development server port 8000
port: 9001
// If you want to turn on the proxy, please remove the mockjs /src/main.jsL11
// proxy: {
// '/api': {
......
import './BasicLayout.less'
import PropTypes from 'ant-design-vue/es/_util/vue-types'
import { Layout } from 'ant-design-vue'
import { ContainerQuery } from 'vue-container-query'
import { SiderMenuWrapper, GlobalFooter } from './components'
......@@ -9,33 +11,17 @@ import HeaderView, { HeaderViewProps } from './Header'
import WrapContent from './WrapContent'
import ConfigProvider from './components/ConfigProvider'
const noop = () => {}
export const BasicLayoutProps = {
...SiderMenuProps,
...HeaderViewProps,
locale: {
type: String,
default: 'en-US'
},
breadcrumbRender: {
type: Function,
default: () => undefined
},
disableMobile: {
type: Boolean,
default: false
},
mediaQuery: {
type: Object,
default: () => {}
},
handleMediaQuery: {
type: Function,
default: () => undefined
},
footerRender: {
type: Function,
default: () => undefined
}
locale: PropTypes.string.def('en-US'),
breadcrumbRender: PropTypes.func,
disableMobile: PropTypes.bool.def(false),
mediaQuery: PropTypes.object.def({}),
handleMediaQuery: PropTypes.func,
footerRender: PropTypes.func,
}
const MediaQueryEnum = {
......@@ -107,6 +93,8 @@ const BasicLayout = {
const rightContentRender = getComponentFromProp(content, 'rightContentRender')
const collapsedButtonRender = getComponentFromProp(content, 'collapsedButtonRender')
const menuHeaderRender = getComponentFromProp(content, 'menuHeaderRender')
const breadcrumbRender = getComponentFromProp(content, 'breadcrumbRender')
const isTopMenu = layout === 'topmenu'
const hasSiderMenu = !isTopMenu
// If it is a fix menu, calculate padding
......@@ -118,11 +106,12 @@ const BasicLayout = {
footerRender,
menuHeaderRender,
rightContentRender,
collapsedButtonRender
collapsedButtonRender,
breadcrumbRender
}
return (
<ConfigProvider i18nRender={i18nRender} contentWidth={contentWidth}>
<ConfigProvider i18nRender={i18nRender} contentWidth={contentWidth} breadcrumbRender={breadcrumbRender}>
<ContainerQuery query={MediaQueryEnum} onChange={handleMediaQuery}>
<Layout class={{
'ant-pro-basicLayout': true,
......
......@@ -5,12 +5,14 @@ const ConfigProvider = {
props: {
i18nRender: PropTypes.any,
contentWidth: PropTypes.bool,
breadcrumbRender: PropTypes.func,
},
provide () {
const _self = this
return {
locale: _self.$props.i18nRender,
contentWidth: _self.$props.contentWidth
contentWidth: _self.$props.contentWidth,
breadcrumbRender: _self.$props.breadcrumbRender,
}
},
render () {
......
......@@ -23,7 +23,7 @@ const PageHeaderWrapperProps = {
content: PropTypes.any,
extraContent: PropTypes.any,
pageHeaderRender: PropTypes.func,
breadcrumb: PropTypes.oneOf([PropTypes.object, PropTypes.bool]).def(true),
breadcrumb: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]).def(true),
back: PropTypes.func,
// 包装 pro-layout 才能使用
......@@ -131,14 +131,15 @@ const defaultPageHeaderRender = (h, props, pageMeta, i18nRender) => {
const PageHeaderWrapper = {
name: 'PageHeaderWrapper',
props: PageHeaderWrapperProps,
inject: ['locale', 'contentWidth'],
inject: ['locale', 'contentWidth', 'breadcrumbRender'],
render(h) {
const { $route } = this
const children = this.$slots.default
const content = getComponentFromProp(this, 'content')
const extra = getComponentFromProp(this, 'extra')
const extraContent = getComponentFromProp(this, 'extraContent')
const pageMeta = useContext(this.$props.route || this.$route)
const pageMeta = useContext(this.$props.route || $route)
const i18n = this.$props.i18nRender || this.locale || defaultI18nRender
const contentWidth = this.$props.contentWidth || this.contentWidth || false
// 当未设置 back props 或未监听 @back,不显示 back
......@@ -155,26 +156,31 @@ const PageHeaderWrapper = {
onTabChange && onTabChange(key)
}
const propsBreadcrumb = this.$props.breadcrumb
let breadcrumb = {}
if (propsBreadcrumb === undefined) {
const routes = this.$route.matched.concat().map(route => {
const propsBreadcrumb = this.$props.breadcrumb
if (propsBreadcrumb === true) {
const routes = $route.matched.concat().map(route => {
return {
path: route.path,
breadcrumbName: i18n(route.meta.title),
}
})
// TODO:: warn -> abs path
const itemRender = ({ route, params, routes, paths, h }) => {
const defaultItemRender = ({ route, params, routes, paths, h }) => {
return routes.indexOf(route) === routes.length - 1 && (
<span>{route.breadcrumbName}</span>
) || (
<router-link to={{ path: route.path }}>{route.breadcrumbName}</router-link>
<router-link to={{ path: route.path || '/', params }}>{route.breadcrumbName}</router-link>
)
}
// If custom breadcrumb render undefined
// use default breadcrumb..
const itemRender = this.breadcrumbRender || defaultItemRender
breadcrumb = { props: { routes, itemRender } }
} else {
breadcrumb = propsBreadcrumb
breadcrumb = propsBreadcrumb || null
}
const props = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment