diff --git a/@types/accordion.d.ts b/@types/accordion.d.ts
index bc952a614..7b4c14d56 100644
--- a/@types/accordion.d.ts
+++ b/@types/accordion.d.ts
@@ -10,6 +10,10 @@ export interface AtAccordionProps extends AtComponent {
icon?: AtIconBaseProps
+ isAnimation?: boolean
+
+ hasBorder?: boolean
+
onClick?: CommonEventFunction
}
diff --git a/docs/markdown/accordion.md b/docs/markdown/accordion.md
index 65a60a193..aca3acb69 100644
--- a/docs/markdown/accordion.md
+++ b/docs/markdown/accordion.md
@@ -23,36 +23,63 @@ import { AtAccordion } from 'taro-ui'
## 一般用法
-说明
+说明:
+
+* 该组件为受控组件,开发者通过 open 来控制组件开关状态,可通过触发 onClick 函数时修改 open 实现状态切换
:::demo
-```html
-
-
-
-
-
-
-
+```js
+import Taro from '@tarojs/taro'
+import { View } from '@tarojs/components'
+import { AtAccordion, AtList, AtListItem } from 'taro-ui'
+
+export default class Index extends Taro.Component {
+ constructor () {
+ super(...arguments)
+ this.state = {
+ open: false,
+ }
+ }
+ handleClick (value) {
+ this.setState({
+ open: value
+ })
+ }
+ render () {
+
+ return (
+
+
+
+
+
+
+
+ )
+ }
+}
+
+
```
:::
@@ -94,10 +121,12 @@ import { AtAccordion } from 'taro-ui'
| ---------- | -------------------------------------- | ------- | ------------------------------------------------------------------- | -------- |
| open | 是否默认开启 | Boolean | - | false |
| title | 标题 | String | - | - |
+| hasBorder | 是否有头部下划线 | Boolean | - | true |
+| isAnimation | 是否开启动画 (v2.0.0-beta.3 支持)| Boolean | - | true |
| icon | 图标,仅支持 AtIcon 支持的类型,object 属性有 value color size | object | - | - |
## 事件
| 事件名称 | 说明 | 返回参数 |
|---------- |-------------- |---------- |
-| onClick | 点击头部触发事件 | event |
+| onClick | 点击头部触发事件 | (open,event) => void |
diff --git a/src/common/utils.ts b/src/common/utils.ts
index 568ff94de..3882c6c8f 100644
--- a/src/common/utils.ts
+++ b/src/common/utils.ts
@@ -219,6 +219,33 @@ function pxTransform(size) {
return Taro.pxTransform(size)
}
+
+function linear(t, b, c, d) {
+ return (c * t / d) + b
+}
+
+function easeOut(from, to, callback) {
+ if (from === to || typeof from !== 'number') {
+ return
+ }
+
+ const change = to - from
+ const dur = 1000
+ const sTime = +new Date()
+ const isLarger = to >= from
+
+ function step() {
+ from = linear(+new Date() - sTime, from, change, dur)
+ if ((isLarger && from >= to) || (!isLarger && to >= from)) {
+ callback(to)
+ return
+ }
+ callback(from)
+ requestAnimationFrame(step)
+ }
+ step()
+}
+
export {
delay,
delayQuerySelector,
@@ -229,5 +256,6 @@ export {
pxTransform,
handleTouchScroll,
delayGetClientRect,
- delayGetScrollOffset
+ delayGetScrollOffset,
+ easeOut
}
diff --git a/src/components/accordion/index.js b/src/components/accordion/index.js
index 5953fde76..d9b6542c2 100644
--- a/src/components/accordion/index.js
+++ b/src/components/accordion/index.js
@@ -3,62 +3,50 @@ import PropTypes from 'prop-types'
import classNames from 'classnames'
import { View, Text } from '@tarojs/components'
import AtComponent from '../../common/component'
-import { delayQuerySelector, uuid } from '../../common/utils'
+import { delayQuerySelector, initTestEnv, easeOut } from '../../common/utils'
+initTestEnv()
+
+// 文档
export default class AtAccordion extends AtComponent {
constructor () {
super(...arguments)
- this.bodyHeight = 0 // body 高度
- this.accordionId = this.props.isTest ? 'accordion-AOTU2018' : `accordion-${uuid()}`
+ this.isCompleted = true
this.state = {
- isOpen: !!this.props.open, // 组件是否展开
- wrapperHeight: '',
+ wrapperHeight: ''
}
}
- handleClick (e) {
- this.switch()
- this.props.onClick(e)
- }
-
- componentDidMount () {
- this.initData()
- }
-
- componentWillReceiveProps () {
- this.initData()
+ handleClick = event => {
+ const { open } = this.props
+ this.props.onClick(!open, event)
}
- initData () {
- const { isOpen } = this.state
- const env = Taro.getEnv()
+ toggleWithAnimation () {
+ const { open, isAnimation } = this.props
+ if (!this.isCompleted || !isAnimation) return
- if (env === Taro.ENV_TYPE.WEB) {
- setTimeout(() => {
- this.accordionRef = document.getElementById(this.accordionId)
- this.bodyHeight = this.accordionRef.getBoundingClientRect().height
-
- this.setState({
- wrapperHeight: isOpen ? this.bodyHeight : 0
- })
- }, 500)
- } else if (env === Taro.ENV_TYPE.WEAPP || env === Taro.ENV_TYPE.ALIPAY) {
- delayQuerySelector(this, `#${this.accordionId}`)
- .then(rect => {
- this.bodyHeight = rect[0].height || 0
+ this.isCompleted = false
+ delayQuerySelector(this, '.at-accordion__content', 0)
+ .then(rect => {
+ const height = parseInt(rect[0].height)
+ const startHeight = open ? height : 0
+ const endHeight = open ? 0 : height
+ easeOut(startHeight, endHeight, value => {
+ if (value === endHeight) {
+ this.isCompleted = true
+ }
this.setState({
- wrapperHeight: isOpen ? this.bodyHeight : 0
+ wrapperHeight: value
})
})
- }
+ })
}
- switch () {
- const { isOpen } = this.state
- this.setState({
- isOpen: !isOpen,
- wrapperHeight: isOpen ? 0 : this.bodyHeight
- })
+ componentWillReceiveProps (nextProps) {
+ if (nextProps.open !== this.props.open) {
+ this.toggleWithAnimation()
+ }
}
render () {
@@ -68,61 +56,61 @@ export default class AtAccordion extends AtComponent {
title,
icon,
hasBorder,
+ open
} = this.props
- const { wrapperHeight, isOpen } = this.state
+ const { wrapperHeight } = this.state
+
+ const isAnimationStart = open && !this.isCompleted && wrapperHeight < 2
- const iconClass = classNames({
+ const rootCls = classNames('at-accordion', className)
+ const iconCls = classNames({
'at-icon': true,
[`at-icon-${icon && icon.value}`]: icon && icon.value,
'at-accordion__icon': true,
})
- const headerClass = classNames('at-accordion__header', {
+ const headerCls = classNames('at-accordion__header', {
'at-accordion__header--noborder': !hasBorder
})
- const arrowClass = classNames('at-accordion__arrow', {
- 'at-accordion__arrow--folded': !!isOpen
+ const arrowCls = classNames('at-accordion__arrow', {
+ 'at-accordion__arrow--folded': !!open
+ })
+ const contentCls = classNames('at-accordion__content', {
+ 'at-accordion__content--inactive': (!open && this.isCompleted) || isAnimationStart
})
- const contentStyle = {
- height: `${wrapperHeight}px`
- }
const iconStyle = {
color: (icon && icon.color) || '',
fontSize: (icon && `${icon.size}px`) || '',
}
+ const contentStyle = { height: `${wrapperHeight}px` }
- return (
-
-
- {icon && icon.value && }
- {title}
-
-
-
-
-
- {this.props.children}
+ if (this.isCompleted || isAnimationStart) {
+ contentStyle.height = ''
+ }
+
+ return
+
+ {icon && icon.value && }
+ {title}
+
+
- )
+
+ {this.props.children}
+
+
}
}
AtAccordion.defaultProps = {
- isTest: false,
open: false,
customStyle: '',
className: '',
title: '',
icon: {},
hasBorder: true,
+ isAnimation: true,
onClick: () => {},
}
@@ -135,8 +123,8 @@ AtAccordion.propTypes = {
PropTypes.array,
PropTypes.string
]),
- isTest: PropTypes.bool,
open: PropTypes.bool,
+ isAnimation: PropTypes.bool,
title: PropTypes.string,
icon: PropTypes.object,
hasBorder: PropTypes.bool,
diff --git a/src/components/accordion/index.test.js b/src/components/accordion/index.test.js
index eaf46cc7c..46252d6c0 100644
--- a/src/components/accordion/index.test.js
+++ b/src/components/accordion/index.test.js
@@ -6,32 +6,23 @@ import AtAccordion from '../../../.temp/components/accordion'
describe('AtAccordion Snap', () => {
it('render initial AtAccordion', () => {
- const component = renderToString(
-
-
- )
+ const component = renderToString()
expect(component).toMatchSnapshot()
})
it('render AtAccordion -- props title', () => {
- const component = renderToString(
-
-
- )
+ const component = renderToString()
expect(component).toMatchSnapshot()
})
it('render AtAccordion -- props open', () => {
- const component = renderToString(
-
-
- )
+ const component = renderToString()
expect(component).toMatchSnapshot()
})
it('render AtAccordion -- props icon', () => {
const component = renderToString(
-
+
)
diff --git a/src/pages/layout/accordion/index.js b/src/pages/layout/accordion/index.js
index ac338970f..5e84d8eff 100644
--- a/src/pages/layout/accordion/index.js
+++ b/src/pages/layout/accordion/index.js
@@ -9,11 +9,24 @@ export default class CardPage extends Taro.Component {
navigationBarTitleText: 'Taro UI'
}
- onClick (e) {
- console.log(e)
+ constructor () {
+ super(...arguments)
+ this.state = {
+ value1: false,
+ value2: true,
+ value3: false
+ }
+ }
+
+ onClick (stateName, value) {
+ this.setState({
+ [stateName]: value
+ })
}
render () {
+ const { value1, value2, value3 } = this.state
+
return (
@@ -23,8 +36,9 @@ export default class CardPage extends Taro.Component {
-
+
配置图标
-
+