Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(collapse): collapse-item add expandInViewport prop(#12783) #12798

Open
wants to merge 2 commits into
base: 2.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions src/collapse-item/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const [createComponent, bem] = createNamespace('collapse-item');

const CELL_SLOTS = ['title', 'icon', 'right-icon'];

const DOUBLE_RAF_TIME = 32;

export default createComponent({
mixins: [ChildrenMixin('vanCollapse')],

Expand All @@ -28,6 +30,10 @@ export default createComponent({
type: Boolean,
default: true,
},
expandInViewport: {
type: Boolean,
default: false,
},
},

data() {
Expand Down Expand Up @@ -83,6 +89,7 @@ export default createComponent({
// Use raf: flick when opened in safari
// Use nextTick: closing animation failed when set `user-select: none`
const nextTick = expanded ? this.$nextTick : raf;
const { accordion } = this.parent;

nextTick(() => {
const { content, wrapper } = this.$refs;
Expand All @@ -99,6 +106,12 @@ export default createComponent({
// use double raf to ensure animation can start
doubleRaf(() => {
wrapper.style.height = expanded ? contentHeight : 0;

// ensure that the expanded node during the expansion animation is not pushed out of the viewport
if (accordion && expanded && this.expandInViewport) {
const duration = this.getTransitionDuration(wrapper);
this.stayInViewport(Date.now() + duration);
}
});
} else {
this.onTransitionEnd();
Expand Down Expand Up @@ -130,6 +143,51 @@ export default createComponent({
}
},

/**
* Get the transition duration
* @param {Element} el
*/
getTransitionDuration(el) {
const computedStyle = window.getComputedStyle(el);
const duration = computedStyle.getPropertyValue('transition-duration');

// unit ms
const durationList = duration.split(',').map((timestr) => {
const coefficient = timestr.endsWith('ms') ? 1 : 1000;
return parseFloat(timestr) * coefficient;
});

return durationList.length ? Math.max(...durationList) : 0;
},

/**
* Keep the node within the viewport.
* @param {Number} endTime
*/
stayInViewport(endTime) {
const currTime = Date.now();
const restTime = endTime - currTime;
const titleRef = this.$refs.title;

if (!titleRef || restTime <= -DOUBLE_RAF_TIME) return;

if (typeof titleRef.scrollIntoViewIfNeeded === 'function') {
titleRef.scrollIntoViewIfNeeded(false);
} else {
const rect = titleRef.getBoundingClientRect();

if (rect.top < 0) {
titleRef.scrollIntoView({
behavior: 'instant',
});
}
}

raf(() => {
this.stayInViewport(endTime);
});
},

genTitle() {
const { border, disabled, expanded } = this;

Expand All @@ -147,6 +205,7 @@ export default createComponent({

return (
<Cell
ref="title"
role="button"
class={bem('title', { disabled, expanded, borderless: !border })}
onClick={this.onClick}
Expand Down
1 change: 1 addition & 0 deletions src/collapse/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export default {
| title-class | Title className | _string_ | - |
| value-class | Value className | _string_ | - |
| label-class | Label className | _string_ | - |
| expand-in-viewport | Whether to expand inside viewport | _boolean_ | `false` |

### CollapseItem Slots

Expand Down
1 change: 1 addition & 0 deletions src/collapse/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export default {
| title-class | 左侧标题额外类名 | _string_ | - |
| value-class | 右侧内容额外类名 | _string_ | - |
| label-class | 描述信息额外类名 | _string_ | - |
| expand-in-viewport | 是否在视口内展开 | _boolean_ | `false` |

### CollapseItem Slots

Expand Down
21 changes: 21 additions & 0 deletions src/collapse/demo/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,22 @@
</van-collapse-item>
</van-collapse>
</demo-block>

<demo-block :title="t('expandInViewport')">
<van-collapse v-model="active5" accordion>
<van-collapse-item
v-for="(item, index) in new Array(10)"
:key="index"
:title="`标题${index}`"
:name="index"
expand-in-viewport
>
<p v-for="(item, i) in new Array(20 - index * 2)" :key="i">
内容 {{ i }}
</p>
</van-collapse-item>
</van-collapse>
</demo-block>
</demo-section>
</template>

Expand All @@ -69,11 +85,15 @@ export default {
accordion: '手风琴',
titleSlot: '自定义标题内容',
text: '代码是写出来给人看的,附带能在机器上运行',
expandInViewport:
'手风琴模式下,保证展开动画期间被展开节点不会被挤出视口范围',
},
'en-US': {
accordion: 'Accordion',
titleSlot: 'Custom title',
text: 'Content',
expandInViewport:
'In accordion mode, ensure that during the expansion animation, the nodes being expanded do not get pushed out of the viewport range.',
},
},

Expand All @@ -83,6 +103,7 @@ export default {
active2: 0,
active3: [],
active4: [],
active5: 0,
};
},
};
Expand Down
Loading