ScrollContainer.vue 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. <template>
  2. <Scrollbar
  3. ref="scrollbarRef"
  4. class="scroll-container"
  5. :scrollHeight="scrollHeight"
  6. v-bind="$attrs"
  7. >
  8. <slot></slot>
  9. </Scrollbar>
  10. </template>
  11. <script lang="ts" setup>
  12. import { ref, unref, nextTick } from 'vue';
  13. import { Scrollbar, ScrollbarType } from '@/components/Scrollbar';
  14. import { useScrollTo } from '@vben/hooks';
  15. import { type Nullable } from '@vben/types';
  16. defineOptions({ name: 'ScrollContainer' });
  17. defineProps({
  18. scrollHeight: {
  19. type: Number,
  20. },
  21. });
  22. const scrollbarRef = ref<Nullable<ScrollbarType>>(null);
  23. function getScrollWrap() {
  24. const scrollbar = unref(scrollbarRef);
  25. if (!scrollbar) {
  26. return null;
  27. }
  28. return scrollbar.wrap;
  29. }
  30. /**
  31. * Scroll to the specified position
  32. */
  33. function scrollTo(to: number, duration = 500) {
  34. const wrap = unref(getScrollWrap());
  35. nextTick(() => {
  36. if (!wrap) {
  37. return;
  38. }
  39. const { start } = useScrollTo({
  40. el: wrap,
  41. to,
  42. duration,
  43. });
  44. start();
  45. });
  46. }
  47. /**
  48. * Scroll to the bottom
  49. */
  50. function scrollBottom() {
  51. const wrap = unref(getScrollWrap());
  52. nextTick(() => {
  53. if (!wrap) {
  54. return;
  55. }
  56. const scrollHeight = wrap.scrollHeight as number;
  57. const { start } = useScrollTo({
  58. el: wrap,
  59. to: scrollHeight,
  60. });
  61. start();
  62. });
  63. }
  64. defineExpose({
  65. scrollTo,
  66. scrollBottom,
  67. });
  68. </script>
  69. <style lang="less">
  70. .scroll-container {
  71. width: 100%;
  72. height: 100%;
  73. .scrollbar__wrap {
  74. margin-bottom: 18px !important;
  75. }
  76. .scrollbar__view {
  77. box-sizing: border-box;
  78. }
  79. }
  80. </style>