use-content-style.ts 1.7 KB

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