// directives/collapse.js export default { mounted(el, binding) { el._collapse = { duration: binding.arg ? parseInt(binding.arg) : 300, // 使用指令参数设置 duration expanded: binding.value, }; el.style.overflow = 'hidden'; el.style.transition = `height ${el._collapse.duration}ms ease, opacity ${el._collapse.duration}ms ease`; if (!binding.value) { el.style.height = '0px'; el.style.opacity = '0'; } else { setTimeout(() => { getHeight(el).then((height) => { el.style.height = height + 'px'; el.style.opacity = '1'; }); }, 0); } }, updated(el, binding) { const duration = el._collapse.duration; const isShow = binding.value; if (isShow === el._collapse.expanded) return; el._collapse.expanded = isShow; if (isShow) { getHeight(el).then((height) => { el.style.transition = `none`; el.style.height = '0px'; el.style.opacity = '0'; // 动画开始 requestAnimationFrame(() => { el.style.transition = `height ${duration}ms ease, opacity ${duration}ms ease`; el.style.height = height + 'px'; el.style.opacity = '1'; // 动画结束后设置为 auto(避免内容变化导致高度错误) setTimeout(() => { el.style.height = 'auto'; }, duration); }); }); } else { getHeight(el).then((height) => { console.log(height) el.style.height = height + 'px'; el.style.opacity = '1'; requestAnimationFrame(() => { el.style.height = '0px'; el.style.opacity = '0'; }); }); } }, unmounted(el) { delete el._collapse; }, }; // 获取元素高度(兼容 H5 和小程序) function getHeight(el) { return new Promise((resolve) => { // #ifdef H5 resolve(el.scrollHeight); // #endif // #ifndef H5 const query = uni.createSelectorQuery(); query.select(el).boundingClientRect((res) => { resolve(res?.height || 0); }).exec(); // #endif }); }