index.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import {
  2. PropType,
  3. defineComponent,
  4. nextTick,
  5. onMounted,
  6. reactive,
  7. ref,
  8. watch
  9. } from 'vue';
  10. import styles from './index.module.less';
  11. import { useRect } from '@vant/use';
  12. import { useResizeObserver } from '@vueuse/core';
  13. export default defineComponent({
  14. name: 'm-sticky',
  15. props: {
  16. position: {
  17. type: String as PropType<'top' | 'bottom'>,
  18. default: 'top'
  19. },
  20. mode: {
  21. type: String as PropType<'fixed' | 'sticky'>,
  22. default: 'fixed'
  23. },
  24. offsetTop: {
  25. type: String,
  26. default: '0px'
  27. },
  28. offsetBottom: {
  29. default: '0px'
  30. },
  31. // 变量名
  32. varName: {
  33. type: String,
  34. default: '--header-height'
  35. }
  36. },
  37. emits: ['barHeight'],
  38. setup(props, { slots, emit }) {
  39. const forms = reactive({
  40. divStyle: {} as any,
  41. heightV: 0,
  42. sectionStyle: {
  43. width: '100%',
  44. height: 'auto',
  45. left: '0'
  46. }
  47. });
  48. const __initHeight = (height: any) => {
  49. forms.sectionStyle.height = `${height}px`;
  50. forms.heightV = height;
  51. // 设置名称
  52. document.documentElement.style.setProperty(props.varName, `${height}px`);
  53. emit('barHeight', height);
  54. };
  55. const divRef = ref();
  56. const div2Ref = ref();
  57. onMounted(() => {
  58. if (props.position === 'top') {
  59. forms.divStyle.top = props.offsetTop || '0px';
  60. } else {
  61. forms.divStyle.bottom = props.offsetBottom || '0px';
  62. }
  63. // const resize = new ResizeObserver(() => {
  64. // const { height } = useRect(div2Ref.value);
  65. // __initHeight(height);
  66. // });
  67. // resize.observe(divRef.value);
  68. try {
  69. useResizeObserver(div2Ref.value, (entries: any) => {
  70. const entry = entries[0];
  71. const { height } = entry.contentRect;
  72. if (Math.abs(height - forms.heightV) > 1) {
  73. setTimeout(() => {
  74. __initHeight(height);
  75. }, 10);
  76. }
  77. });
  78. } catch {}
  79. // nextTick(() => {
  80. // // 为了处理刚开始头部高度为0的情况
  81. // if (divRef.value) {
  82. // const { height } = useRect(divRef.value);
  83. // __initHeight(height);
  84. // setTimeout(() => {
  85. // const { height } = useRect(divRef.value);
  86. // // 判断获取的高度是否一致,如果一致则不做处理
  87. // if (height === forms.heightV) return;
  88. // __initHeight(height);
  89. // }, 200);
  90. // }
  91. // // 为了处理头部第一次获取高度不对的问题
  92. // if (div2Ref.value) {
  93. // setTimeout(() => {
  94. // const { height } = useRect(div2Ref.value);
  95. // if (height !== forms.heightV && props.position === 'top') {
  96. // __initHeight(height);
  97. // }
  98. // }, 1000);
  99. // }
  100. // });
  101. });
  102. watch(
  103. () => props.offsetTop,
  104. () => {
  105. forms.divStyle.top = props.offsetTop;
  106. }
  107. );
  108. watch(
  109. () => props.offsetBottom,
  110. () => {
  111. forms.divStyle.bottom = props.offsetBottom;
  112. }
  113. );
  114. return () => (
  115. <div
  116. style={[forms.sectionStyle]}
  117. class={props.mode === 'sticky' && styles.sticky}>
  118. <div
  119. ref={divRef}
  120. class={[
  121. 'van-sticky',
  122. props.mode === 'fixed' ? 'van-sticky--fixed' : ''
  123. ]}
  124. style={[forms.divStyle, forms.sectionStyle]}>
  125. <div ref={div2Ref}>{slots.default && slots.default()}</div>
  126. </div>
  127. </div>
  128. );
  129. }
  130. });