diff --git a/src/components/RightToolbar/index.vue b/src/components/RightToolbar/index.vue index 02a55f78e66d9d88906d6f089349838f9d4f0f9a..899b074ad6b4fdbe3d44096940bbb37b965e27a5 100644 --- a/src/components/RightToolbar/index.vue +++ b/src/components/RightToolbar/index.vue @@ -53,6 +53,7 @@ const style = computed(() => { // 搜索 function toggleSearch() { emits('update:showSearch', !props.showSearch); + nextTick(() => window.dispatchEvent(new Event('resize'))); } // 刷新 diff --git a/src/directive/common/adaptive.ts b/src/directive/common/adaptive.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4472b3d24df99759cd906f18e1f512eaf065ce4 --- /dev/null +++ b/src/directive/common/adaptive.ts @@ -0,0 +1,74 @@ +import type { Directive, DirectiveBinding } from 'vue'; + +// 扩展 HTMLElement 类型 +interface AdaptiveElement extends HTMLElement { + _resizeListener?: () => void; +} + +// 配置接口 +interface AdaptiveOptions { + height?: number; // 距离底部的距离,默认 90 +} + +const DEFAULT_HEIGHT = 105; + +/** + * 自适应高度指令 + * 用法: + *
+ *
+ */ +const vAdaptiveHeight: Directive = { + mounted(el, binding: DirectiveBinding) { + // 获取配置 + const config = binding.value || {}; + const bottomHeight = typeof config.height === 'number' ? config.height : DEFAULT_HEIGHT; + + // 设置高度 + const updateHeight = () => { + const rect = el.getBoundingClientRect(); + const top = rect.top; // 更准确 + const pageHeight = window.innerHeight; + el.style.height = `${pageHeight - top - bottomHeight}px`; + el.style.overflowY = 'auto'; + }; + + // 防抖:避免频繁触发 + let resizeTimer: number; + const onResize = () => { + clearTimeout(resizeTimer); + resizeTimer = window.setTimeout(() => { + requestAnimationFrame(updateHeight); + }, 100); + }; + + // 保存监听器,用于销毁 + el._resizeListener = onResize; + + // 初始设置 + updateHeight(); + + // 监听 resize + window.addEventListener('resize', onResize); + }, + + // 组件更新时重新计算(比如父组件 re-render) + updated(el, binding: DirectiveBinding) { + const config = binding.value || {}; + const bottomHeight = typeof config.height === 'number' ? config.height : DEFAULT_HEIGHT; + + const rect = el.getBoundingClientRect(); + const top = rect.top; + const pageHeight = window.innerHeight; + el.style.height = `${pageHeight - top - bottomHeight}px`; + }, + + unmounted(el) { + if (el._resizeListener) { + window.removeEventListener('resize', el._resizeListener); + delete el._resizeListener; + } + } +}; + +export default vAdaptiveHeight; diff --git a/src/directive/index.ts b/src/directive/index.ts index ef25ee897f6bec346588fae6324e41a4ba2ffed8..8d660c9983c20e3b6225fff5c0024d0bb439982b 100644 --- a/src/directive/index.ts +++ b/src/directive/index.ts @@ -1,9 +1,11 @@ import copyText from './common/copyText'; +import adaptive from './common/adaptive'; import { hasPermi, hasRoles } from './permission'; import { App } from 'vue'; export default (app: App) => { app.directive('copyText', copyText); + app.directive('adaptive', adaptive); app.directive('hasPermi', hasPermi); app.directive('hasRoles', hasRoles); }; diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue index d12aeedd71ff921108e71cd26816a8e56559edf2..494d497fd27c68240b0ee4817a2805cf80623731 100644 --- a/src/views/system/user/index.vue +++ b/src/views/system/user/index.vue @@ -6,8 +6,9 @@ - +