| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- <template>
- <view :class="['nut-collapse-item', { 'nut-collapse-item-left': classDirection == 'left' }, { 'nut-collapse-item-icon': icon }]">
- <view :class="['collapse-item', { 'item-expanded': openExpanded }, { 'nut-collapse-item-disabled': disabled }]" @click="toggleOpen">
- <view class="collapse-title">
- <view v-html="title"></view>
- </view>
- <view v-if="subTitle" v-html="subTitle" class="subTitle"></view>
- <i v-if="icon" :class="['collapse-icon', { 'col-expanded': openExpanded }, { 'collapse-icon-disabled': disabled }]" :style="iconStyle"></i>
- <i v-else :class="['collapse-icon', { 'col-expanded': openExpanded }, { 'collapse-icon-disabled': disabled }]"></i>
- </view>
- <view class="collapse-wrapper" ref="wrapperRef">
- <view class="collapse-content" ref="contentRef">
- <slot></slot>
- </view>
- </view>
- </view>
- </template>
- <script lang="ts">
- import { reactive, toRefs, onMounted, ref, nextTick, computed, watch } from 'vue';
- import { createComponent } from '@/utils/create';
- import { useParent } from '@/utils/useRelation/useParent';
- import { COLLAPSE_KEY } from './../collapse/index.vue';
- const { create } = createComponent('collapse-item');
- export default create({
- props: {
- title: {
- type: String,
- default: ''
- },
- subTitle: {
- type: String,
- default: ''
- },
- disabled: {
- type: Boolean,
- default: false
- },
- name: {
- type: [Number, String],
- default: -1,
- required: true
- },
- collapseRef: {
- type: Object
- }
- },
- setup(props) {
- const collapse = useParent(COLLAPSE_KEY);
- const parent: any = reactive(collapse.parent as any);
- const index: any = reactive(collapse.index as any);
- const proxyData = reactive({
- openExpanded: false,
- classDirection: 'right',
- iconStyle: {
- width: '20px',
- height: '20px',
- 'background-image': 'url(https://img10.360buyimg.com/imagetools/jfs/t1/111306/10/17422/341/5f58aa0eEe9218dd6/28d76a42db334e31.png)',
- 'background-repeat': 'no-repeat',
- 'background-size': '100% 100%',
- transform: 'rotate(0deg)'
- }
- });
- // 获取 Dom 元素
- const wrapperRef: any = ref(null);
- const contentRef: any = ref(null);
- // 清除 willChange 减少性能浪费
- const onTransitionEnd = () => {
- const wrapperRefEle: any = document.getElementsByClassName('collapse-wrapper')[0];
- wrapperRefEle.style.willChange = 'auto';
- };
- // 手风琴模式
- const animation = () => {
- const wrapperRefEle: any = wrapperRef.value;
- const contentRefEle: any = contentRef.value;
- if (!wrapperRefEle || !contentRefEle) {
- return;
- }
- const offsetHeight = contentRefEle.offsetHeight;
- if (offsetHeight) {
- const contentHeight = `${offsetHeight}px`;
- wrapperRefEle.style.willChange = 'height';
- wrapperRefEle.style.height = !proxyData.openExpanded ? 0 : contentHeight;
- if (parent.icon && !proxyData.openExpanded) {
- proxyData.iconStyle['transform'] = 'rotate(0deg)';
- } else {
- proxyData.iconStyle['transform'] = 'rotate(' + parent.rotate + 'deg)';
- }
- }
- if (!proxyData.openExpanded) {
- onTransitionEnd();
- }
- };
- const open = () => {
- proxyData.openExpanded = !proxyData.openExpanded;
- animation();
- };
- const defaultOpen = () => {
- open();
- if (parent.icon) {
- proxyData['iconStyle']['transform'] = 'rotate(' + parent.rotate + 'deg)';
- }
- };
- const currentName = computed(() => props.name ?? index.value);
- const toggleOpen = () => {
- if (parent.accordion) {
- parent.children.forEach((item: any, index: number) => {
- if (currentName.value == item.name) {
- item.changeOpen(!item.openExpanded);
- } else {
- item.changeOpen(false);
- item.animation();
- }
- });
- nextTick(() => {
- parent.changeVal(currentName.value, !proxyData.openExpanded);
- animation();
- });
- } else {
- parent.changeValAry(props.name);
- open();
- }
- };
- // 更改子组件展示
- const changeOpen = (bol: boolean) => {
- proxyData.openExpanded = bol;
- };
- const expanded = computed(() => {
- if (parent) {
- return parent.isExpanded(props.name);
- }
- return null;
- });
- watch(expanded, (value, oldValue) => {
- if (value) {
- proxyData.openExpanded = true;
- }
- });
- onMounted(() => {
- const { name } = props;
- const active = parent && parent.value;
- if (typeof active == 'number' || typeof active == 'string') {
- if (name == active) {
- defaultOpen();
- }
- } else if (Object.values(active) instanceof Array) {
- const f = Object.values(active).filter(item => item == name);
- if (f.length > 0) {
- defaultOpen();
- }
- }
- proxyData.classDirection = parent.expandIconPosition;
- if (parent.icon) {
- proxyData.iconStyle['background-image'] = 'url(' + parent.icon + ')';
- }
- if (parent.iconWidth) {
- proxyData.iconStyle['width'] = parent.conWidth;
- }
- if (parent.iconHeght) {
- proxyData.iconStyle['height'] = parent.iconHeight;
- }
- });
- return {
- ...toRefs(proxyData),
- ...toRefs(parent),
- wrapperRef,
- contentRef,
- open,
- toggleOpen,
- changeOpen,
- animation
- };
- }
- });
- </script>
- <style lang="scss" scoped>
- @import './index.scss';
- </style>
|