add collapse and demo

This commit is contained in:
wangxueliang 2018-02-01 18:18:05 +08:00
parent 45442bb8b2
commit 2518078359
24 changed files with 831 additions and 1 deletions

View File

@ -0,0 +1,42 @@
<script>
import PropTypes from '../_util/vue-types'
import animation from '../_util/openAnimation'
import { getOptionProps } from '../_util/props-util'
import RcCollapse from './src'
export default {
props: {
prefixCls: PropTypes.string.def('ant-collapse'),
bordered: PropTypes.bool.def(true),
openAnimation: PropTypes.any.def({ ...animation, appear () { } }),
activeKey: PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string),
]),
defaultValue: PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string),
]),
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string),
]),
change: PropTypes.func.def(() => {}),
accordion: PropTypes.bool,
},
render () {
const { prefixCls, bordered, $listeners } = this
const collapseClassName = {
[`${prefixCls}-borderless`]: !bordered,
}
const rcCollapeProps = {
props: {
...getOptionProps(this),
},
class: collapseClassName,
on: $listeners,
}
return <RcCollapse {...rcCollapeProps}>{this.$slots.default}</RcCollapse>
},
}
</script>

View File

@ -0,0 +1,27 @@
<script>
import PropTypes from '../_util/vue-types'
import { getOptionProps } from '../_util/props-util'
import RcCollapse from './src'
import { panelProps } from './src/commonProps'
export default {
props: {
name: PropTypes.string,
...panelProps,
},
render () {
const { prefixCls, showArrow = true, $listeners } = this
const collapsePanelClassName = {
[`${prefixCls}-no-arrow`]: !showArrow,
}
const rcCollapePanelProps = {
props: {
...getOptionProps(this),
},
class: collapsePanelClassName,
on: $listeners,
}
return <RcCollapse.Panel {...rcCollapePanelProps} >{this.$slots.default}</RcCollapse.Panel>
},
}
</script>

View File

@ -0,0 +1,36 @@
<cn>
#### 手风琴
手风琴每次只打开一个tab。默认打开第一个。
</cn>
<us>
#### Accordion
Accordion mode, only one panel can be expanded at a time. The first panel will be expanded by default.
</us>
```html
<template>
<div>
<a-collapse accordion>
<a-collapse-panel header="This is panel header 1" name="1">
<p>{{text}}</p>
</a-collapse-panel>
<a-collapse-panel header="This is panel header 2" name="2" :disabled='false'>
<p>{{text}}</p>
</a-collapse-panel>
<a-collapse-panel header="This is panel header 3" name="3">
<p>{{text}}</p>
</a-collapse-panel>
</a-collapse>
</div>
</template>
<script>
export default {
data () {
return {
text: `A dog is a type of domesticated animal.Known for its loyalty and faithfulness,it can be found as a welcome guest in many households across the world.`,
}
},
}
</script>
```

View File

@ -0,0 +1,42 @@
<cn>
#### 折叠面板
可以同时展开多个面板,这个例子默认展开了第一个。
</cn>
<us>
#### Collapse
More than one panel can be expanded at a time, the first panel is initialized to be active in this case.
</us>
```html
<template>
<div>
<a-collapse v-model="value" @change="changeActivekey">
<a-collapse-panel header="This is panel header 1" name="1">
<p>{{text}}</p>
</a-collapse-panel>
<a-collapse-panel header="This is panel header 2" name="2" :disabled='false'>
<p>{{text}}</p>
</a-collapse-panel>
<a-collapse-panel header="This is panel header 3" name="3" disabled>
<p>{{text}}</p>
</a-collapse-panel>
</a-collapse>
</div>
</template>
<script>
export default {
data () {
return {
text: `A dog is a type of domesticated animal.Known for its loyalty and faithfulness,it can be found as a welcome guest in many households across the world.`,
value: ['1']
}
},
methods: {
changeActivekey (key) {
console.log(key)
},
},
}
</script>
```

View File

@ -0,0 +1,36 @@
<cn>
#### 简洁风格
一套没有边框的简洁样式。
</cn>
<us>
#### Borderless
A borderless style of Collapse.
</us>
```html
<template>
<div>
<a-collapse :defaultValue="'1'" :bordered="false">
<a-collapse-panel header="This is panel header 1" name="1">
<p>{{text}}</p>
</a-collapse-panel>
<a-collapse-panel header="This is panel header 2" name="2" :disabled='false'>
<p>{{text}}</p>
</a-collapse-panel>
<a-collapse-panel header="This is panel header 3" name="3">
<p>{{text}}</p>
</a-collapse-panel>
</a-collapse>
</div>
</template>
<script>
export default {
data () {
return {
text: `A dog is a type of domesticated animal.Known for its loyalty and faithfulness,it can be found as a welcome guest in many households across the world.`,
}
},
}
</script>
```

View File

@ -0,0 +1,37 @@
<cn>
#### 自定义面板
自定义各个面板的背景色、圆角和边距。
</cn>
<us>
#### Custom Panel
Customize the background, border and margin styles for each panel.
</us>
```html
<template>
<div>
<a-collapse :defaultValue="'1'" :bordered="false">
<a-collapse-panel header="This is panel header 1" name="1" :style="customStyle">
<p>{{text}}</p>
</a-collapse-panel>
<a-collapse-panel header="This is panel header 2" name="2" :style="customStyle">
<p>{{text}}</p>
</a-collapse-panel>
<a-collapse-panel header="This is panel header 3" name="3" :style="customStyle">
<p>{{text}}</p>
</a-collapse-panel>
</a-collapse>
</div>
</template>
<script>
export default {
data () {
return {
text: `A dog is a type of domesticated animal.Known for its loyalty and faithfulness,it can be found as a welcome guest in many households across the world.`,
customStyle: 'background: #f7f7f7;border-radius: 4px;margin-bottom: 24px;border: 0;overflow: hidden'
}
},
}
</script>
```

View File

@ -0,0 +1,53 @@
<script>
import Accordion from './accordion'
import Basic from './basic'
import Borderless from './borderless'
import Custom from './custom'
import Mix from './mix'
import Noarrow from './noarrow'
import CN from '../index.zh-CN.md'
import US from '../index.en-US.md'
const md = {
cn: `# Collapse折叠面板
可以折叠/展开的内容区域
## 何时使用
- 对复杂区域进行分组和隐藏保持页面的整洁
- '手风琴' 是一种特殊的折叠面板只允许单个内容区域展开
## 代码演示`,
us: `# When To Use
- Can be used to group or hide complex regions to keep the page clean.
- 'Accordion' is a special kind of 'Collapse', which allows only one panel to be expanded at a time.`,
}
export default {
render () {
return (
<div>
<md cn={md.cn} us={md.us}/>
<Basic/>
<br/>
<Accordion/>
<br/>
<Mix/>
<br/>
<Borderless/>
<br/>
<Custom/>
<br/>
<Noarrow/>
<br/>
<api>
<template slot='cn'>
<CN/>
</template>
<US/>
</api>
</div>
)
},
}
</script>

View File

@ -0,0 +1,45 @@
<cn>
#### 面板嵌套
嵌套折叠面板。
</cn>
<us>
#### Nested panel
`Collapse` is nested inside the `Collapse`.
</us>
```html
<template>
<div>
<a-collapse @change="changeActivekey">
<a-collapse-panel header="This is panel header 1" name="1">
<a-collapse :defaultValue="'1'">
<a-collapse-panel header="This is panel nest panel" name="1">
<p>{{text}}</p>
</a-collapse-panel>
</a-collapse>
</a-collapse-panel>
<a-collapse-panel header="This is panel header 2" name="2" :disabled='false'>
<p>{{text}}</p>
</a-collapse-panel>
<a-collapse-panel header="This is panel header 3" name="3">
<p>{{text}}</p>
</a-collapse-panel>
</a-collapse>
</div>
</template>
<script>
export default {
data () {
return {
text: `A dog is a type of domesticated animal.Known for its loyalty and faithfulness,it can be found as a welcome guest in many households across the world.`,
}
},
methods: {
changeActivekey (key) {
console.log(key)
},
},
}
</script>
```

View File

@ -0,0 +1,38 @@
<cn>
#### 隐藏箭头
你可以通过 `:showArrow="false"` 隐藏 `a-collapse-panel` 组件的箭头图标。
</cn>
<us>
#### No arrow
You can disable showing arrow icon by passing `:showArrow="false"` to `a-collapse-panel` component.
</us>
```html
<template>
<div>
<a-collapse :defaultValue="'1'" @change="changeActivekey">
<a-collapse-panel header="This is panel header with arrow icon" name="1">
<p>{{text}}</p>
</a-collapse-panel>
<a-collapse-panel header="This is panel header with no arrow icon" name="2" :showArrow="false">
<p>{{text}}</p>
</a-collapse-panel>
</a-collapse>
</div>
</template>
<script>
export default {
data () {
return {
text: `A dog is a type of domesticated animal.Known for its loyalty and faithfulness,it can be found as a welcome guest in many households across the world.`,
}
},
methods: {
changeActivekey (key) {
console.log(key)
},
},
}
</script>
```

View File

@ -0,0 +1,18 @@
## API
### Collapse
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| value | name of the active panel | \[]\|string | No default value. In `accordion` mode, it's the name of the first panel. |
| defaultValue | name of the initial active panel | string | - |
| change | Callback function executed when active panel is changed | Function | - |
### Collapse.Panel
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| disabled | If `true`, panel cannot be opened or closed | boolean | `false` |
| header | Title of the panel | string | - |
| name | Unique name identifying the panel from among its siblings | string | - |
| showArrow | If `false`, panel will not show arrow icon | boolean | `true` |

View File

@ -0,0 +1,5 @@
import Collapse from './Collapse'
import CollapsePanel from './CollapsePanel'
Collapse.Panel = CollapsePanel
export default Collapse

View File

@ -0,0 +1,17 @@
## API
### Collapse
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| value | 当前激活 tab 面板的 name | []\|string | 默认无accordion模式下默认第一个元素 |
| defaultValue | 初始化选中面板的 name | string | 无 |
| change | 切换面板的回调 | Function | 无 |
### Collapse.Panel
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| disabled | 禁用后的面板展开与否将无法通过用户交互改变 | boolean | false |
| header | 面板头内容 | string | 无 |
| name | 对应 activeKey | string | 无 |

View File

@ -0,0 +1,123 @@
<script>
import PropTypes from '../../_util/vue-types'
import BaseMixin from '../../_util/BaseMixin'
import { hasProp } from '../../_util/props-util'
import { cloneElement, getPropsData, isEmptyElement } from '../../_util/vnode'
import openAnimationFactory from './openAnimationFactory'
import { collapseProps } from './commonProps'
function _toArray (activeKey) {
let currentActiveKey = activeKey
if (!Array.isArray(currentActiveKey)) {
currentActiveKey = currentActiveKey ? [currentActiveKey] : []
}
return currentActiveKey
}
export default {
name: 'Collapse',
mixins: [BaseMixin],
props: {
...collapseProps,
openAnimation: PropTypes.object,
},
data () {
const { value, defaultValue, openAnimation, prefixCls } = this.$props
let currentActiveKey = defaultValue
if (hasProp(this, 'value')) {
currentActiveKey = value
}
const currentOpenAnimations = openAnimation || openAnimationFactory(prefixCls)
return {
currentOpenAnimations,
stateActiveKey: _toArray(currentActiveKey),
}
},
methods: {
onClickItem (key) {
let activeKey = this.stateActiveKey
if (this.accordion) {
activeKey = activeKey[0] === key ? [] : [key]
} else {
activeKey = [...activeKey]
const index = activeKey.indexOf(key)
const isActive = index > -1
if (isActive) {
// remove active state
activeKey.splice(index, 1)
} else {
activeKey.push(key)
}
}
this.setActiveKey(activeKey)
},
getItems () {
const activeKey = this.stateActiveKey
const { prefixCls, accordion, destroyInactivePanel } = this.$props
const newChildren = []
this.$slots.default.forEach((child, index) => {
if (isEmptyElement(child)) return
const { header, headerClass, disabled, name = String(index) } = getPropsData(child)
let isActive = false
if (accordion) {
isActive = activeKey[0] === name
} else {
isActive = activeKey.indexOf(name) > -1
}
let panelEvents = {}
if (!disabled && disabled !== '') {
panelEvents = {
itemClick: () => { this.onClickItem(name) },
}
}
const props = {
props: {
header,
headerClass,
isActive,
prefixCls,
destroyInactivePanel,
openAnimation: this.currentOpenAnimations,
},
on: {
...panelEvents,
},
}
newChildren.push(cloneElement(child, props))
})
return newChildren
},
setActiveKey (activeKey) {
this.setState({ stateActiveKey: activeKey })
this.$emit('change', this.accordion ? activeKey[0] : activeKey)
this.$emit('input', this.accordion ? activeKey[0] : activeKey)
},
},
watch: {
value (val) {
this.setState({
stateActiveKey: _toArray(val),
})
},
openAnimation (val) {
this.setState({
currentOpenAnimations: val,
})
},
},
render () {
const { prefixCls } = this.$props
const collapseClassName = {
[prefixCls]: true,
}
return (
<div class={collapseClassName}>
{this.getItems()}
</div>
)
},
}
</script>

View File

@ -0,0 +1,69 @@
<script>
import PanelContent from './PanelContent'
import { panelProps } from './commonProps'
export default {
name: 'Panel',
props: {
...panelProps,
},
methods: {
handleItemClick () {
this.$emit('itemClick')
},
},
render () {
const {
prefixCls,
header,
headerClass,
isActive,
showArrow,
destroyInactivePanel,
disabled,
openAnimation,
} = this.$props
const { $slots } = this
const transitionProps = {
props: Object.assign({
appear: false,
css: false,
}),
on: { ...openAnimation },
}
const headerCls = {
[`${prefixCls}-header`]: true,
[headerClass]: headerClass,
}
const itemCls = {
[`${prefixCls}-item`]: true,
[`${prefixCls}-item-active`]: isActive,
[`${prefixCls}-item-disabled`]: disabled,
}
return (
<div class={itemCls} role='tablist'>
<div
class={headerCls}
onClick={this.handleItemClick.bind(this)}
role='tab'
aria-expanded={isActive}
>
{showArrow && <i class='arrow' />}
{header}
</div><transition
{...transitionProps}
>
<PanelContent
prefixCls={prefixCls}
isActive={isActive}
destroyInactivePanel={destroyInactivePanel}
>
{$slots.default}
</PanelContent>
</transition>
</div>
)
},
}
</script>

View File

@ -0,0 +1,32 @@
<script>
import PropTypes from '../../_util/vue-types'
export default {
name: 'PanelContent',
props: {
prefixCls: PropTypes.string,
isActive: PropTypes.bool,
destroyInactivePanel: PropTypes.bool,
},
render () {
if (!this.isActive) {
return null
}
const { prefixCls, isActive, destroyInactivePanel } = this.$props
const { $slots } = this
const contentCls = {
[`${prefixCls}-content`]: true,
[`${prefixCls}-content-active`]: isActive,
[`${prefixCls}-content-inactive`]: !isActive,
}
const child = !isActive && destroyInactivePanel ? null
: <div class={`${prefixCls}-content-box`}>{$slots.default}</div>
return (
<div
class={contentCls}
role='tabpanel'
>{child}</div>
)
},
}
</script>

View File

@ -0,0 +1,32 @@
import PropTypes from '../../_util/vue-types'
const collapseProps = {
prefixCls: PropTypes.string,
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string),
]),
defaultValue: PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string),
]),
accordion: PropTypes.bool.def(false),
destroyInactivePanel: PropTypes.bool.def(false),
}
const panelProps = {
openAnimation: PropTypes.object,
prefixCls: PropTypes.string,
header: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.node,
]),
headerClass: PropTypes.string.def(''),
showArrow: PropTypes.bool.def(true),
isActive: PropTypes.bool.def(false),
destroyInactivePanel: PropTypes.bool.def(false),
disabled: PropTypes.bool.def(false),
}
export { collapseProps, panelProps }

View File

@ -0,0 +1,6 @@
import CollapsePanel from './Panel'
import Collapse from './Collapse'
Collapse.Panel = CollapsePanel
export default Collapse

View File

@ -0,0 +1,35 @@
import cssAnimation from 'css-animation'
function animate (node, show, transitionName, done) {
let height
return cssAnimation(node, transitionName, {
start () {
if (!show) {
node.style.height = `${node.offsetHeight}px`
} else {
height = node.offsetHeight
node.style.height = 0
}
},
active () {
node.style.height = `${show ? height : 0}px`
},
end () {
node.style.height = ''
done()
},
})
}
function animation (prefixCls) {
return {
enter (node, done) {
return animate(node, true, `${prefixCls}-anim`, done)
},
leave (node, done) {
return animate(node, false, `${prefixCls}-anim`, done)
},
}
}
export default animation

View File

@ -0,0 +1,2 @@
import '../../style/index.less'
import './index.less'

View File

@ -0,0 +1,128 @@
@import "../../style/themes/default";
@import "../../style/mixins/index";
@collapse-prefix-cls: ~"@{ant-prefix}-collapse";
@collapse-header-bg: @background-color-light;
@collapse-active-bg: @background-color-base;
.collapse-close() {
transform: rotate(0);
}
.collapse-open() {
transform: rotate(90deg);
}
.@{collapse-prefix-cls} {
.reset-component;
background-color: @collapse-header-bg;
border-radius: @border-radius-base;
border: @border-width-base @border-style-base @border-color-base;
border-bottom: 0;
& > &-item {
border-bottom: @border-width-base @border-style-base @border-color-base;
&:last-child {
&,
& > .@{collapse-prefix-cls}-header {
border-radius: 0 0 @border-radius-base @border-radius-base;
}
}
> .@{collapse-prefix-cls}-header {
line-height: 22px;
padding: 12px 0 12px 40px;
color: @heading-color;
cursor: pointer;
position: relative;
transition: all .3s;
.arrow {
.iconfont-mixin();
.collapse-close();
font-size: @font-size-sm;
position: absolute;
display: inline-block;
line-height: 46px;
vertical-align: top;
transition: transform 0.24s;
top: 0;
left: @padding-md;
&:before {
content: "\E61F";
}
}
}
&.@{collapse-prefix-cls}-no-arrow {
> .@{collapse-prefix-cls}-header {
padding-left: 12px;
}
}
}
&-anim-active {
transition: height .2s @ease-out;
}
&-content {
overflow: hidden;
color: @text-color;
padding: 0 @padding-md;
background-color: @component-background;
border-top: @border-width-base @border-style-base @border-color-base;
& > &-box {
padding-top: @padding-md;
padding-bottom: @padding-md;
}
&-inactive {
display: none;
}
}
&-item:last-child {
> .@{collapse-prefix-cls}-content {
border-radius: 0 0 @border-radius-base @border-radius-base;
}
}
& > &-item > &-header[aria-expanded="true"] {
.arrow {
.collapse-open();
}
}
&-borderless {
background-color: @component-background;
border: 0;
}
&-borderless > &-item {
border-bottom: 1px solid @border-color-base;
}
&-borderless > &-item:last-child,
&-borderless > &-item:last-child &-header {
border-radius: 0;
}
&-borderless > &-item > &-content {
background-color: transparent;
border-top: 0;
}
&-borderless > &-item > &-content > &-content-box {
padding-top: 4px;
}
& &-item-disabled > &-header {
&,
& > .arrow {
cursor: not-allowed;
color: @disabled-color;
}
}
}

View File

@ -55,3 +55,7 @@ const DropdownButton = Dropdown.Button
export { Dropdown, DropdownButton } export { Dropdown, DropdownButton }
export { default as Divider } from './divider' export { default as Divider } from './divider'
import Collapse from './collapse'
const CollapsePanel = Collapse.Panel
export { Collapse, CollapsePanel }

View File

@ -16,3 +16,5 @@ import './popconfirm/style'
import './menu/style' import './menu/style'
import './dropdown/style' import './dropdown/style'
import './divider/style' import './divider/style'
import './card/style'
import './collapse/style'

View File

@ -18,4 +18,5 @@ export { default as tag } from 'antd/tag/demo/index.vue'
export { default as tooltip } from 'antd/tooltip/demo/index.vue' export { default as tooltip } from 'antd/tooltip/demo/index.vue'
export { default as dropdown } from 'antd/dropdown/demo/index.vue' export { default as dropdown } from 'antd/dropdown/demo/index.vue'
export { default as divider } from 'antd/divider/demo/index.vue' export { default as divider } from 'antd/divider/demo/index.vue'
export { default as collapse } from 'antd/collapse/demo/index.vue'

View File

@ -1,7 +1,7 @@
import Demo from './components/demo.vue' import Demo from './components/demo.vue'
const AsyncComp = () => { const AsyncComp = () => {
return { return {
component: import(`../components/dropdown/demo/sub-menu.md`), component: import(`../components/collapse/demo/index.vue`),
} }
} }
export default [ export default [