taro-ui-vue3
Version:
Taro UI Rewritten in Vue 3.0
140 lines (139 loc) • 4.33 kB
JavaScript
import {h, defineComponent, reactive, ref, watch, computed, mergeProps} from "vue";
import {Text, View} from "@tarojs/components";
import {delayQuerySelector} from "../utils/common";
const AtAccordion = defineComponent({
name: "AtAccordion",
props: {
open: Boolean,
title: {
type: String,
default: ""
},
icon: {
type: Object,
default: () => ({value: ""})
},
hasBorder: {
type: Boolean,
default: true
},
isAnimation: {
type: Boolean,
default: true
},
note: {
type: String,
default: ""
},
onClick: Function
},
setup(props, {attrs, slots}) {
const isCompleted = ref(true);
const startOpen = ref(false);
const contentID = ref("content");
const state = reactive({wrapperHeight: "unset"});
const iconClass = computed(() => ({
[`${props.icon.prefixClass || "at-icon"}`]: Boolean(props.icon),
[`${props.icon.prefixClass || "at-icon"}-${props.icon.value}`]: Boolean(props.icon && props.icon.value),
"at-accordion__icon": true
}));
const headerClass = computed(() => ({
"at-accordion__header": true,
"at-accordion__header--noborder": !props.hasBorder
}));
const arrowClass = computed(() => ({
"at-accordion__arrow": true,
"at-accordion__arrow--folded": !!props.open
}));
const contentClass = computed(() => ({
"at-accordion__content": true,
"at-accordion__content--inactive": !props.open && isCompleted.value || startOpen.value
}));
const iconStyle = computed(() => ({
color: props.icon && props.icon.color ? props.icon.color : "",
fontSize: props.icon && props.icon.size ? `${props.icon.size}px` : ""
}));
const contentStyle = computed(() => ({
height: isCompleted.value ? "" : state.wrapperHeight === "unset" ? state.wrapperHeight : `${state.wrapperHeight}px`
}));
watch(() => props.open, (val) => {
startOpen.value = !!val && !!props.isAnimation;
toggleWithAnimation();
});
function handleClick(e) {
contentID.value = "content" + String(e.timeStamp).replace(".", "");
if (!isCompleted.value)
return;
props.onClick && props.onClick(!props.open, e);
}
function toggleWithAnimation() {
if (!isCompleted.value || !props.isAnimation)
return;
isCompleted.value = false;
delayQuerySelector(this, `#${contentID.value}.at-accordion__body`, 30).then((rect) => {
const height = parseInt(rect[0].height.toString());
const startHeight = props.open ? 0 : height;
const endHeight = props.open ? height : 0;
startOpen.value = false;
state.wrapperHeight = startHeight;
setTimeout(() => {
state.wrapperHeight = endHeight;
}, 100);
setTimeout(() => {
isCompleted.value = true;
}, 700);
});
}
return () => h(View, mergeProps(attrs, {
class: "at-accordion"
}), {
default: () => [
h(View, {
class: headerClass.value,
onTap: handleClick
}, {
default: () => [
props.icon && props.icon.value && h(Text, {
class: iconClass.value,
style: iconStyle.value
}),
h(View, {
class: "at-accordion__info"
}, {
default: () => [
h(View, {
class: "at-accordion__info__title"
}, {default: () => props.title}),
h(View, {
class: "at-accordion__info__note"
}, {default: () => props.note})
]
}),
h(View, {
class: arrowClass.value
}, {
default: () => [
h(Text, {class: "at-icon at-icon-chevron-down"})
]
})
]
}),
h(View, {
class: contentClass.value,
style: contentStyle.value
}, {
default: () => [
h(View, {
id: contentID.value,
class: "at-accordion__body"
}, {default: () => slots.default && slots.default()})
]
})
]
});
}
});
var accordion_default = AtAccordion;
export {
accordion_default as default
};