Vben
2021-02-26 fcee7d4eb71471dd40567c8d7c97302eeee80697
提交 | 用户 | age
7db0c5 1 <template>
V 2   <div class="scrollbar">
3     <div
4       ref="wrap"
5       :class="[wrapClass, 'scrollbar__wrap', native ? '' : 'scrollbar__wrap--hidden-default']"
6       :style="style"
7       @scroll="handleScroll"
8     >
9       <component :is="tag" ref="resize" :class="['scrollbar__view', viewClass]" :style="viewStyle">
10         <slot></slot>
11       </component>
12     </div>
13     <template v-if="!native">
14       <bar :move="moveX" :size="sizeWidth" />
15       <bar vertical :move="moveY" :size="sizeHeight" />
16     </template>
17   </div>
18 </template>
19 <script lang="ts">
fcee7d 20   import { addResizeListener, removeResizeListener } from '/@/utils/event';
0e7c57 21   import componentSetting from '/@/settings/componentSetting';
V 22   const { scrollbar } = componentSetting;
7db0c5 23   import { toObject } from './util';
V 24   import {
25     defineComponent,
26     ref,
27     onMounted,
28     onBeforeUnmount,
29     nextTick,
30     provide,
31     computed,
bba776 32     unref,
7db0c5 33   } from 'vue';
V 34   import Bar from './bar';
35
36   export default defineComponent({
37     name: 'Scrollbar',
99ac30 38     // inheritAttrs: false,
7db0c5 39     components: { Bar },
V 40     props: {
41       native: {
42         type: Boolean,
0e7c57 43         default: scrollbar?.native ?? false,
7db0c5 44       },
V 45       wrapStyle: {
46         type: [String, Array],
47         default: '',
48       },
49       wrapClass: {
50         type: [String, Array],
51         default: '',
52       },
53       viewClass: {
54         type: [String, Array],
55         default: '',
56       },
57       viewStyle: {
58         type: [String, Array],
59         default: '',
60       },
61       noresize: Boolean, // 如果 container 尺寸不会发生变化,最好设置它可以优化性能
62       tag: {
63         type: String,
64         default: 'div',
65       },
66     },
67     setup(props) {
68       const sizeWidth = ref('0');
69       const sizeHeight = ref('0');
70       const moveX = ref(0);
71       const moveY = ref(0);
72       const wrap = ref<any>(null);
73       const resize = ref<any>(null);
74
75       provide('scroll-bar-wrap', wrap);
76
bba776 77       const style = computed(() => {
V 78         if (Array.isArray(props.wrapStyle)) {
79           return toObject(props.wrapStyle);
80         }
81         return props.wrapStyle;
82       });
83
7db0c5 84       const handleScroll = () => {
V 85         if (!props.native) {
bba776 86           moveY.value = (unref(wrap).scrollTop * 100) / unref(wrap).clientHeight;
V 87           moveX.value = (unref(wrap).scrollLeft * 100) / unref(wrap).clientWidth;
7db0c5 88         }
V 89       };
90
91       const update = () => {
bba776 92         if (!unref(wrap)) return;
7db0c5 93
bba776 94         const heightPercentage = (unref(wrap).clientHeight * 100) / unref(wrap).scrollHeight;
V 95         const widthPercentage = (unref(wrap).clientWidth * 100) / unref(wrap).scrollWidth;
7db0c5 96
V 97         sizeHeight.value = heightPercentage < 100 ? heightPercentage + '%' : '';
98         sizeWidth.value = widthPercentage < 100 ? widthPercentage + '%' : '';
99       };
100
101       onMounted(() => {
102         if (props.native) return;
103         nextTick(update);
144ab5 104         if (!props.noresize) {
bba776 105           addResizeListener(unref(resize), update);
V 106           addResizeListener(unref(wrap), update);
107           addEventListener('resize', update);
144ab5 108         }
7db0c5 109       });
V 110
111       onBeforeUnmount(() => {
112         if (props.native) return;
144ab5 113         if (!props.noresize) {
bba776 114           removeResizeListener(unref(resize), update);
V 115           removeResizeListener(unref(wrap), update);
116           removeEventListener('resize', update);
144ab5 117         }
7db0c5 118       });
bba776 119
7db0c5 120       return {
V 121         moveX,
122         moveY,
123         sizeWidth,
124         sizeHeight,
125         style,
126         wrap,
127         resize,
128         update,
129         handleScroll,
130       };
131     },
132   });
133 </script>
134 <style lang="less">
135   .scrollbar {
136     position: relative;
137     height: 100%;
138     overflow: hidden;
139
140     &__wrap {
141       height: 100%;
144ab5 142       overflow: auto;
7db0c5 143
V 144       &--hidden-default {
145         scrollbar-width: none;
146
147         &::-webkit-scrollbar {
148           display: none;
149           width: 0;
150           height: 0;
151           opacity: 0;
152         }
153       }
154     }
155
156     &__thumb {
157       position: relative;
158       display: block;
159       width: 0;
160       height: 0;
161       cursor: pointer;
162       background-color: rgba(144, 147, 153, 0.3);
163       border-radius: inherit;
164       transition: 0.3s background-color;
165
166       &:hover {
167         background-color: rgba(144, 147, 153, 0.5);
168       }
169     }
170
171     &__bar {
172       position: absolute;
173       right: 2px;
174       bottom: 2px;
175       z-index: 1;
176       border-radius: 4px;
177       opacity: 0;
178       -webkit-transition: opacity 80ms ease;
179       transition: opacity 80ms ease;
180
181       &.is-vertical {
182         top: 2px;
183         width: 6px;
184
185         & > div {
186           width: 100%;
187         }
188       }
189
190       &.is-horizontal {
191         left: 2px;
192         height: 6px;
193
194         & > div {
195           height: 100%;
196         }
197       }
198     }
199   }
200
201   .scrollbar:active > .scrollbar__bar,
202   .scrollbar:focus > .scrollbar__bar,
203   .scrollbar:hover > .scrollbar__bar {
204     opacity: 1;
205     transition: opacity 340ms ease-out;
206   }
207 </style>