use-content-style.ts 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. import type { CSSProperties } from 'vue';
  2. import { computed, onMounted, onUnmounted, ref } from 'vue';
  3. import {
  4. CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT,
  5. CSS_VARIABLE_LAYOUT_CONTENT_WIDTH,
  6. getElementVisibleRect,
  7. type VisibleDomRect,
  8. } from '@vben-core/shared';
  9. import { useCssVar, useDebounceFn } from '@vueuse/core';
  10. /**
  11. * @zh_CN content style
  12. */
  13. function useContentStyle() {
  14. let resizeObserver: null | ResizeObserver = null;
  15. const contentElement = ref<HTMLDivElement | null>(null);
  16. const visibleDomRect = ref<null | VisibleDomRect>(null);
  17. const contentHeight = useCssVar(CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT);
  18. const contentWidth = useCssVar(CSS_VARIABLE_LAYOUT_CONTENT_WIDTH);
  19. const overlayStyle = computed((): CSSProperties => {
  20. const { height, left, top, width } = visibleDomRect.value ?? {};
  21. return {
  22. height: `${height}px`,
  23. left: `${left}px`,
  24. position: 'fixed',
  25. top: `${top}px`,
  26. width: `${width}px`,
  27. zIndex: 150,
  28. };
  29. });
  30. const debouncedCalcHeight = useDebounceFn(
  31. (_entries: ResizeObserverEntry[]) => {
  32. visibleDomRect.value = getElementVisibleRect(contentElement.value);
  33. contentHeight.value = `${visibleDomRect.value.height}px`;
  34. contentWidth.value = `${visibleDomRect.value.width}px`;
  35. },
  36. 100,
  37. );
  38. onMounted(() => {
  39. if (contentElement.value && !resizeObserver) {
  40. resizeObserver = new ResizeObserver(debouncedCalcHeight);
  41. resizeObserver.observe(contentElement.value);
  42. }
  43. });
  44. onUnmounted(() => {
  45. resizeObserver?.disconnect();
  46. resizeObserver = null;
  47. });
  48. return { contentElement, overlayStyle, visibleDomRect };
  49. }
  50. export { useContentStyle };