This commit is contained in:
wangxueliang 2018-03-10 20:51:40 +08:00
commit c0ef57df8e
18 changed files with 271 additions and 155 deletions

View File

@ -7,7 +7,7 @@ import getTransitionProps from '../_util/getTransitionProps'
export const BadgeProps = {
/** Number to show in badge */
count: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
count: PropTypes.oneOfType([PropTypes.number, PropTypes.string, null]),
showZero: PropTypes.bool,
/** Max count to show */
overflowCount: PropTypes.number,

View File

@ -14,7 +14,7 @@ function getNumberArray (num) {
const ScrollNumberProps = {
prefixCls: PropTypes.string.def('ant-scroll-number'),
count: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).def(null),
count: PropTypes.oneOfType([PropTypes.number, PropTypes.string, null]).def(null),
component: PropTypes.string,
title: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
}

View File

@ -1,24 +1,90 @@
<script>
import PropTypes from '../_util/vue-types'
import PropTypes from '../_util/vue-types'
import { cloneElement } from '../_util/vnode'
import { filterEmpty, getComponentFromProp, getSlotOptions } from '../_util/props-util'
import warning from '../_util/warning'
import BreadcrumbItem from './BreadcrumbItem'
export default {
name: 'Breadcrumb',
props: {
prefixCls: PropTypes.string.def('ant-breadcrumb'),
separator: PropTypes.string.def('/'),
},
provide () {
return {
breadCrumbParent: this,
}
},
render () {
const { prefixCls } = this
return (
<div class={prefixCls}>
{this.$slots.default}
</div>
)
},
const Route = PropTypes.shape({
path: PropTypes.string,
breadcrumbName: PropTypes.string,
}).loose
const BreadcrumbProps = {
prefixCls: PropTypes.string.def('ant-breadcrumb'),
routes: PropTypes.arrayOf(Route),
params: PropTypes.any,
separator: PropTypes.any,
itemRender: PropTypes.func,
}
function getBreadcrumbName (route, params) {
if (!route.breadcrumbName) {
return null
}
const paramsKeys = Object.keys(params).join('|')
const name = route.breadcrumbName.replace(
new RegExp(`:(${paramsKeys})`, 'g'),
(replacement, key) => params[key] || replacement,
)
return name
}
export default {
props: BreadcrumbProps,
methods: {
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>
},
},
render () {
let crumbs
const {
prefixCls, routes, params = {},
$slots, $scopedSlots,
} = this
const children = filterEmpty($slots.default)
const separator = getComponentFromProp(this, 'separator')
if (routes && routes.length > 0) {
const paths = []
const itemRender = this.itemRender || $scopedSlots.itemRender || this.defaultItemRender
crumbs = routes.map((route) => {
route.path = route.path || ''
let path = route.path.replace(/^\//, '')
Object.keys(params).forEach(key => {
path = path.replace(`:${key}`, params[key])
})
if (path) {
paths.push(path)
}
return (
<BreadcrumbItem separator={separator} key={route.breadcrumbName || path}>
{itemRender({ route, params, routes, paths })}
</BreadcrumbItem>
)
})
} else if (children.length) {
crumbs = children.map((element, index) => {
warning(
getSlotOptions(element).__ANT_BREADCRUMB_ITEM,
'Breadcrumb only accepts Breadcrumb.Item as it\'s children',
)
return cloneElement(element, {
props: { separator },
key: index,
})
})
}
return (
<div class={prefixCls}>
{crumbs}
</div>
)
},
}
</script>

View File

@ -1,30 +1,29 @@
<script>
import PropTypes from '../_util/vue-types'
import hasProp from '../_util/props-util'
import { hasProp, getComponentFromProp } from '../_util/props-util'
export default {
name: 'BreadcrumbItem',
inject: ['breadCrumbParent'],
__ANT_BREADCRUMB_ITEM: true,
props: {
prefixCls: PropTypes.string.def('ant-breadcrumb'),
href: PropTypes.string,
separator: PropTypes.any,
},
render () {
const { prefixCls, ...restProps } = this.$props
const { breadCrumbParent = {}} = this
const { separator = '/' } = breadCrumbParent
const solt = this.$slots.default
const { prefixCls, $slots } = this
const children = $slots.default
let link
if (hasProp(this, 'href')) {
link = <a class={`${prefixCls}-link`} {...restProps}>{solt}</a>
link = <a class={`${prefixCls}-link`}>{children}</a>
} else {
link = <span class={`${prefixCls}-link`} {...restProps}>{solt}</span>
link = <span class={`${prefixCls}-link`}>{children}</span>
}
if (solt) {
if (children) {
return (
<span>
{link}
<span class={`${prefixCls}-separator`}>{separator}</span>
<span class={`${prefixCls}-separator`}>{getComponentFromProp(this, 'separator') || '/'}</span>
</span>
)
}

View File

@ -10,24 +10,11 @@
```html
<template>
<Breadcrumb>
<BreadcrumbItem>Home</BreadcrumbItem>
<BreadcrumbItem><a href="">Application Center</a></BreadcrumbItem>
<BreadcrumbItem><a href="">Application List</a></BreadcrumbItem>
<BreadcrumbItem>An Application</BreadcrumbItem>
</Breadcrumb>
<a-breadcrumb>
<a-breadcrumb-item>Home</a-breadcrumb-item>
<a-breadcrumb-item><a href="">Application Center</a></a-breadcrumb-item>
<a-breadcrumb-item><a href="">Application List</a></a-breadcrumb-item>
<a-breadcrumb-item>An Application</a-breadcrumb-item>
</a-breadcrumb>
</template>
<script>
import '../style'
import { Icon, Breadcrumb } from 'antd/index'
export default {
components: {
Icon,
Breadcrumb,
BreadcrumbItem: Breadcrumb.Item,
},
}
</script>
```

View File

@ -2,6 +2,7 @@
import Basic from './basic.md'
import WithIcon from './withIcon.md'
import Separator from './separator.md'
import Router from './router'
import US from './../index.en-US.md'
import CN from './../index.zh-CN.md'
@ -27,6 +28,10 @@
}
export default {
category: 'Components',
subtitle: '面包屑',
type: 'Navigation',
title: 'Breadcrumb',
render () {
return (
<div>
@ -34,6 +39,7 @@
<Basic />
<WithIcon />
<Separator />
<Router/>
<api>
<CN slot='cn' />
<US />

View File

@ -0,0 +1,48 @@
<cn>
#### vue-router
`vue-router` 进行结合使用。
</cn>
<us>
#### Vue Router Integration
Used together with `vue-router`
</us>
```html
<template>
<div>
<a-breadcrumb :routes="routes">
<template slot="itemRender" slot-scope="{route, params, routes, paths}">
<span v-if="routes.indexOf(route) === routes.length - 1">
{{route.breadcrumbName}}
</span>
<router-link v-else :to="`${basePath}/${paths.join('/')}`">
{{route.breadcrumbName}}
</router-link>
</template>
</a-breadcrumb>
<br/>
{{$route.path}}
</div>
</template>
<script>
export default {
data(){
const { lang } = this.$route.params
return {
basePath: `/${lang}/components/breadcrumb`,
routes: [{
path: 'index',
breadcrumbName: '首页'
}, {
path: 'first',
breadcrumbName: '一级面包屑'
}, {
path: 'second',
breadcrumbName: '当前页面'
}],
}
},
}
</script>
```

View File

@ -1,33 +1,30 @@
<cn>
#### 分隔符
使用` separator=">" `可以自定义分隔符
使用` separator=">" `可以自定义分隔符或者使用slot="separator"自定义更复杂的分隔符
</cn>
<us>
#### Configuring the Separator
The separator can be customized by setting the separator preperty: separator=">"
The separator can be customized by setting the separator preperty: separator=">" or use
slot="separator"
</us>
```html
<template>
<Breadcrumb separator=">">
<BreadcrumbItem>Home</BreadcrumbItem>
<BreadcrumbItem href="">Application Center</BreadcrumbItem>
<BreadcrumbItem href="">Application List</BreadcrumbItem>
<BreadcrumbItem>An Application</BreadcrumbItem>
</Breadcrumb>
<div>
<a-breadcrumb separator=">">
<a-breadcrumb-item>Home</a-breadcrumb-item>
<a-breadcrumb-item href="">Application Center</a-breadcrumb-item>
<a-breadcrumb-item href="">Application List</a-breadcrumb-item>
<a-breadcrumb-item>An Application</a-breadcrumb-item>
</a-breadcrumb>
<a-breadcrumb>
<span slot="separator" style="color: red">></span>
<a-breadcrumb-item>Home</a-breadcrumb-item>
<a-breadcrumb-item href="">Application Center</a-breadcrumb-item>
<a-breadcrumb-item href="">Application List</a-breadcrumb-item>
<a-breadcrumb-item>An Application</a-breadcrumb-item>
</a-breadcrumb>
</div>
</template>
<script>
import '../style'
import { Icon, Breadcrumb } from 'antd/index'
export default {
components: {
Icon,
Breadcrumb,
BreadcrumbItem: Breadcrumb.Item,
},
}
</script>
```

View File

@ -10,30 +10,17 @@
```html
<template>
<Breadcrumb>
<BreadcrumbItem href="">
<Icon type="home" />
</BreadcrumbItem>
<BreadcrumbItem href="">
<Icon type="user" />
<a-breadcrumb>
<a-breadcrumb-item href="">
<a-icon type="home" />
</a-breadcrumb-item>
<a-breadcrumb-item href="">
<a-icon type="user" />
<span>Application List</span>
</BreadcrumbItem>
<BreadcrumbItem>
</a-breadcrumb-item>
<a-breadcrumb-item>
Application
</BreadcrumbItem>
</Breadcrumb>
</a-breadcrumb-item>
</a-breadcrumb>
</template>
<script>
import '../style'
import { Icon, Breadcrumb } from 'antd/index'
export default {
components: {
Icon,
Breadcrumb,
BreadcrumbItem: Breadcrumb.Item,
},
}
</script>
```

View File

@ -2,34 +2,44 @@
| Property | Description | Type | Optional | Default |
| -------- | ----------- | ---- | -------- | ------- |
| itemRender | Custom item renderer | (route, params, routes, paths) => ReactNode | | - |
| itemRender | Custom item renderer, slot="itemRender" and slot-scope="{route, params, routes, paths}" | ({route, params, routes, paths}) => vNode | | - |
| params | Routing parameters | object | | - |
| routes | The routing stack information of router | object\[] | | - |
| separator | Custom separator | string\|ReactNode | | `/` |
> `linkRender` and `nameRender` were removed after `antd@2.0`, please use `itemRender` instead.
| separator | Custom separator | string\|slot | | `/` |
### Use with browserHistory
The link of Breadcrumb item targets `#` by default, you can use `itemRender` to make a `browserHistory` Link.
```vue
import { Link } from 'react-router';
const routes = [{
path: 'index',
 breadcrumbName: 'home'
}, {
path: 'first',
breadcrumbName: 'first'
}, {
path: 'second',
breadcrumbName: 'second'
}];
function itemRender(route, params, routes, paths) {
const last = routes.indexOf(route) === routes.length - 1;
return last ? <span>{route.breadcrumbName}</span> : <Link to={paths.join('/')}>{route.breadcrumbName}</Link>;
}
return <Breadcrumb itemRender={itemRender} routes={routes} />;
```
````html
<template>
<a-breadcrumb :routes="routes">
<template slot="itemRender" slot-scope="{route, params, routes, paths}">
<span v-if="routes.indexOf(route) === routes.length - 1">
{{route.breadcrumbName}}
</span>
<router-link v-else :to="paths.join('/')">
{{route.breadcrumbName}}
</router-link>
</template>
</a-breadcrumb>
</template>
<script>
export default {
data(){
return {
routes: [{
path: 'index',
breadcrumbName: '首页'
}, {
path: 'first',
breadcrumbName: '一级面包屑'
}, {
path: 'second',
breadcrumbName: '当前页面'
}],
}
},
}
</script>
````

View File

@ -2,7 +2,7 @@
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| --- | --- | --- | --- | --- |
| itemRender | 自定义链接函数,和 react-router 配置使用 | (route, params, routes, paths) => ReactNode | | - |
| itemRender | 自定义链接函数,和 vue-router 配置使用, 也可使用slot="itemRender" 和 slot-scope="props" | ({route, params, routes, paths}) => vNode | | - |
| params | 路由的参数 | object | | - |
| routes | router 的路由栈信息 | object\[] | | - |
| separator | 分隔符自定义 | string\|slot | | '/' |
@ -12,22 +12,34 @@
和 vue-router 一起使用时,默认生成的 url 路径是带有 `#` 的,如果和 browserHistory 一起使用的话,你可以使用 `itemRender` 属性定义面包屑链接。
````html
import { Link } from 'react-router';
const routes = [{
path: 'index',
breadcrumbName: '首页'
}, {
path: 'first',
breadcrumbName: '一级面包屑'
}, {
path: 'second',
breadcrumbName: '当前页面'
}];
function itemRender(route, params, routes, paths) {
const last = routes.indexOf(route) === routes.length - 1;
return last ? <span>{route.breadcrumbName}</span> : <Link to={paths.join('/')}>{route.breadcrumbName}</Link>;
}
return <Breadcrumb itemRender={itemRender} routes={routes}/>;
<template>
<a-breadcrumb :routes="routes">
<template slot="itemRender" slot-scope="{route, params, routes, paths}">
<span v-if="routes.indexOf(route) === routes.length - 1">
{{route.breadcrumbName}}
</span>
<router-link v-else :to="paths.join('/')">
{{route.breadcrumbName}}
</router-link>
</template>
</a-breadcrumb>
</template>
<script>
export default {
data(){
return {
routes: [{
path: 'index',
breadcrumbName: '首页'
}, {
path: 'first',
breadcrumbName: '一级面包屑'
}, {
path: 'second',
breadcrumbName: '当前页面'
}],
}
},
}
</script>
````

View File

@ -5,22 +5,23 @@
.@{breadcrumb-prefix-cls} {
.reset-component;
color: @text-color-secondary;
color: @breadcrumb-base-color;
font-size: @breadcrumb-font-size;
.@{iconfont-css-prefix} {
font-size: @font-size-sm;
font-size: @breadcrumb-icon-font-size;
}
a {
color: @text-color-secondary;
color: @breadcrumb-link-color;
transition: color .3s;
&:hover {
color: @primary-5;
color: @breadcrumb-link-color-hover;
}
}
& > span:last-child {
color: @text-color;
color: @breadcrumb-last-item-color;
}
& > span:last-child &-separator {
@ -28,8 +29,8 @@
}
&-separator {
margin: 0 @padding-xs;
color: @text-color-secondary;
margin: @breadcrumb-separator-margin;
color: @breadcrumb-separator-color;
}
&-link {

View File

@ -12,10 +12,10 @@ For instance, add an external link after the selected value.
```html
<template>
<a-cascader :options="options" :defaultValue="['zhejiang', 'hangzhou', 'xihu']" style="width: 100%">
<template slot="displayRender" slot-scope="props">
<span v-for="(label, index) in props.labels" :key="props.selectedOptions[index].value">
<span v-if="index === props.labels.length - 1">
{{label}} (<a @click="e => handleAreaClick(e, label, props.selectedOptions[index])">{{props.selectedOptions[index].code}}</a>)
<template slot="displayRender" slot-scope="{labels, selectedOptions}">
<span v-for="(label, index) in labels" :key="selectedOptions[index].value">
<span v-if="index === labels.length - 1">
{{label}} (<a @click="e => handleAreaClick(e, label, selectedOptions[index])">{{selectedOptions[index].code}}</a>)
</span>
<span v-else @click="onChange">
{{label}} /

View File

@ -12,7 +12,7 @@
| changeOnSelect | change value on each selection if set to true, see above demo for details | boolean | false |
| defaultValue | initial selected value | string\[] | \[] |
| disabled | whether disabled select | boolean | false |
| displayRender | render function of displaying selected options, you can use slot="displayRender" and slot-scope="props" | `({labels, selectedOptions}) => vNode` | `labels => labels.join(' / ')` |
| displayRender | render function of displaying selected options, you can use slot="displayRender" and slot-scope="{labels, selectedOptions}" | `({labels, selectedOptions}) => vNode` | `labels => labels.join(' / ')` |
| expandTrigger | expand current item when click or hover, one of 'click' 'hover' | string | 'click' |
| getPopupContainer | Parent Node which the selector should be rendered to. Default to `body`. When position issues happen, try to modify it into scrollable content and position it relative. | Function(triggerNode) | () => document.body |
| loadData | To load option lazily, and it cannot work with `showSearch` | `(selectedOptions) => void` | - |
@ -33,7 +33,7 @@ Fields in `showSearch`:
| -------- | ----------- | ---- | ------- |
| filter | The function will receive two arguments, inputValue and option, if the function returns true, the option will be included in the filtered set; Otherwise, it will be excluded. | `function(inputValue, path): boolean` | |
| matchInputWidth | Whether the width of result list equals to input's | boolean | |
| render | Used to render filtered options, you can use slot="showSearchRender" and slot-scope="props" | `function({inputValue, path}): vNode` | |
| render | Used to render filtered options, you can use slot="showSearchRender" and slot-scope="{inputValue, path}" | `function({inputValue, path}): vNode` | |
| sort | Used to sort filtered options. | `function(a, b, inputValue)` | |
### events

View File

@ -12,7 +12,7 @@
| changeOnSelect | 当此项为 true 时,点选每级菜单选项值都会发生变化,具体见上面的演示 | boolean | false |
| defaultValue | 默认的选中项 | string\[] | \[] |
| disabled | 禁用 | boolean | false |
| displayRender | 选择后展示的渲染函数,可使用slot="displayRender" 和 slot-scope="props" | `({labels, selectedOptions}) => vNode` | `labels => labels.join(' / ')` |
| displayRender | 选择后展示的渲染函数,可使用slot="displayRender" 和 slot-scope="{labels, selectedOptions}" | `({labels, selectedOptions}) => vNode` | `labels => labels.join(' / ')` |
| expandTrigger | 次级菜单的展开方式,可选 'click' 和 'hover' | string | 'click' |
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。 | Function(triggerNode) | () => document.body |
| loadData | 用于动态加载选项,无法与 `showSearch` 一起使用 | `(selectedOptions) => void` | - |
@ -33,7 +33,7 @@
| --- | --- | --- | --- |
| filter | 接收 `inputValue` `path` 两个参数,当 `path` 符合筛选条件时,应返回 true反之则返回 false。 | `function(inputValue, path): boolean` | |
| matchInputWidth | 搜索结果列表是否与输入框同宽 | boolean | |
| render | 用于渲染 filter 后的选项,可使用slot="showSearchRender" 和 slot-scope="props" | `function({inputValue, path}): vNode` | |
| render | 用于渲染 filter 后的选项,可使用slot="showSearchRender" 和 slot-scope="{inputValue, path}" | `function({inputValue, path}): vNode` | |
| sort | 用于排序 filter 后的选项 | `function(a, b, inputValue)` | |
### 事件

View File

@ -42,7 +42,9 @@ const Textarea = InputTextArea
export { Input, InputGroup, InputSearch, InputTextArea, Textarea }
export { default as Breadcrumb } from './breadcrumb'
import Breadcrumb from './breadcrumb'
const BreadcrumbItem = Breadcrumb.Item
export { Breadcrumb, BreadcrumbItem }
export { default as Popover } from './popover'

View File

@ -31,3 +31,4 @@ import './modal/style'
import './alert/style'
import './time-picker/style'
import './steps/style'
import './breadcrumb/style'

View File

@ -7,7 +7,7 @@ const AsyncComp = () => {
}
}
export default [
{ path: '/:lang?/components/:name/:demo?', component: Demo },
{ path: '/:lang?/components/:name/:demo?/:other?', component: Demo },
{ path: '/:lang?/test/:name/:demo?', component: AsyncComp },
{ path: '/*', redirect: '/cn/components/select' },
]