前端和后端源码,合并到一个git仓库中,方便用户下载,避免前后端不匹配的问题

This commit is contained in:
JEECG
2024-06-23 10:39:52 +08:00
parent bb918b742e
commit 0325e34dcb
1439 changed files with 171106 additions and 0 deletions

View File

@ -0,0 +1,8 @@
/**
* copy from element-ui
*/
import Scrollbar from './src/Scrollbar.vue';
export { Scrollbar };
export type { ScrollbarType } from './src/types';

View File

@ -0,0 +1,193 @@
<template>
<div class="scrollbar">
<div ref="wrap" :class="[wrapClass, 'scrollbar__wrap', native ? '' : 'scrollbar__wrap--hidden-default']" :style="style" @scroll="handleScroll">
<component :is="tag" ref="resize" :class="['scrollbar__view', viewClass]" :style="viewStyle">
<slot></slot>
</component>
</div>
<template v-if="!native">
<bar :move="moveX" :size="sizeWidth" />
<bar vertical :move="moveY" :size="sizeHeight" />
</template>
</div>
</template>
<script lang="ts">
import { addResizeListener, removeResizeListener } from '/@/utils/event';
import componentSetting from '/@/settings/componentSetting';
const { scrollbar } = componentSetting;
import { toObject } from './util';
import { defineComponent, ref, onMounted, onBeforeUnmount, nextTick, provide, computed, unref } from 'vue';
import Bar from './bar';
export default defineComponent({
name: 'Scrollbar',
// inheritAttrs: false,
components: { Bar },
props: {
native: {
type: Boolean,
default: scrollbar?.native ?? false,
},
wrapStyle: {
type: [String, Array],
default: '',
},
wrapClass: {
type: [String, Array],
default: '',
},
viewClass: {
type: [String, Array],
default: '',
},
viewStyle: {
type: [String, Array],
default: '',
},
noresize: Boolean, // 如果 container 尺寸不会发生变化,最好设置它可以优化性能
tag: {
type: String,
default: 'div',
},
},
setup(props) {
const sizeWidth = ref('0');
const sizeHeight = ref('0');
const moveX = ref(0);
const moveY = ref(0);
const wrap = ref();
const resize = ref();
provide('scroll-bar-wrap', wrap);
const style = computed(() => {
if (Array.isArray(props.wrapStyle)) {
return toObject(props.wrapStyle);
}
return props.wrapStyle;
});
const handleScroll = () => {
if (!props.native) {
moveY.value = (unref(wrap).scrollTop * 100) / unref(wrap).clientHeight;
moveX.value = (unref(wrap).scrollLeft * 100) / unref(wrap).clientWidth;
}
};
const update = () => {
if (!unref(wrap)) return;
const heightPercentage = (unref(wrap).clientHeight * 100) / unref(wrap).scrollHeight;
const widthPercentage = (unref(wrap).clientWidth * 100) / unref(wrap).scrollWidth;
sizeHeight.value = heightPercentage < 100 ? heightPercentage + '%' : '';
sizeWidth.value = widthPercentage < 100 ? widthPercentage + '%' : '';
};
onMounted(() => {
if (props.native) return;
nextTick(update);
if (!props.noresize) {
addResizeListener(unref(resize), update);
addResizeListener(unref(wrap), update);
addEventListener('resize', update);
}
});
onBeforeUnmount(() => {
if (props.native) return;
if (!props.noresize) {
removeResizeListener(unref(resize), update);
removeResizeListener(unref(wrap), update);
removeEventListener('resize', update);
}
});
return {
moveX,
moveY,
sizeWidth,
sizeHeight,
style,
wrap,
resize,
update,
handleScroll,
};
},
});
</script>
<style lang="less">
.scrollbar {
position: relative;
height: 100%;
overflow: hidden;
&__wrap {
height: 100%;
overflow: auto;
&--hidden-default {
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
opacity: 0;
}
}
}
&__thumb {
position: relative;
display: block;
width: 0;
height: 0;
cursor: pointer;
background-color: rgba(144, 147, 153, 0.3);
border-radius: inherit;
transition: 0.3s background-color;
&:hover {
background-color: rgba(144, 147, 153, 0.5);
}
}
&__bar {
position: absolute;
right: 2px;
bottom: 2px;
z-index: 1;
border-radius: 4px;
opacity: 0;
-webkit-transition: opacity 80ms ease;
transition: opacity 80ms ease;
&.is-vertical {
top: 2px;
width: 6px;
& > div {
width: 100%;
}
}
&.is-horizontal {
left: 2px;
height: 6px;
& > div {
height: 100%;
}
}
}
}
.scrollbar:active > .scrollbar__bar,
.scrollbar:focus > .scrollbar__bar,
.scrollbar:hover > .scrollbar__bar {
opacity: 1;
transition: opacity 340ms ease-out;
}
</style>

View File

@ -0,0 +1,92 @@
import { defineComponent, h, computed, ref, getCurrentInstance, onUnmounted, inject, Ref } from 'vue';
import { on, off } from '/@/utils/domUtils';
import { renderThumbStyle, BAR_MAP } from './util';
export default defineComponent({
name: 'Bar',
props: {
vertical: Boolean,
size: String,
move: Number,
},
setup(props) {
const instance = getCurrentInstance();
const thumb = ref();
const wrap = inject('scroll-bar-wrap', {} as Ref<Nullable<HTMLElement>>) as any;
const bar = computed(() => {
return BAR_MAP[props.vertical ? 'vertical' : 'horizontal'];
});
const barStore = ref<Recordable>({});
const cursorDown = ref();
const clickThumbHandler = (e: any) => {
// prevent click event of right button
if (e.ctrlKey || e.button === 2) {
return;
}
window.getSelection()?.removeAllRanges();
startDrag(e);
barStore.value[bar.value.axis] =
e.currentTarget[bar.value.offset] - (e[bar.value.client] - e.currentTarget.getBoundingClientRect()[bar.value.direction]);
};
const clickTrackHandler = (e: any) => {
const offset = Math.abs(e.target.getBoundingClientRect()[bar.value.direction] - e[bar.value.client]);
const thumbHalf = thumb.value[bar.value.offset] / 2;
const thumbPositionPercentage = ((offset - thumbHalf) * 100) / instance?.vnode.el?.[bar.value.offset];
wrap.value[bar.value.scroll] = (thumbPositionPercentage * wrap.value[bar.value.scrollSize]) / 100;
};
const startDrag = (e: any) => {
e.stopImmediatePropagation();
cursorDown.value = true;
on(document, 'mousemove', mouseMoveDocumentHandler);
on(document, 'mouseup', mouseUpDocumentHandler);
document.onselectstart = () => false;
};
const mouseMoveDocumentHandler = (e: any) => {
if (cursorDown.value === false) return;
const prevPage = barStore.value[bar.value.axis];
if (!prevPage) return;
const offset = (instance?.vnode.el?.getBoundingClientRect()[bar.value.direction] - e[bar.value.client]) * -1;
const thumbClickPosition = thumb.value[bar.value.offset] - prevPage;
const thumbPositionPercentage = ((offset - thumbClickPosition) * 100) / instance?.vnode.el?.[bar.value.offset];
wrap.value[bar.value.scroll] = (thumbPositionPercentage * wrap.value[bar.value.scrollSize]) / 100;
};
function mouseUpDocumentHandler() {
cursorDown.value = false;
barStore.value[bar.value.axis] = 0;
off(document, 'mousemove', mouseMoveDocumentHandler);
document.onselectstart = null;
}
onUnmounted(() => {
off(document, 'mouseup', mouseUpDocumentHandler);
});
return () =>
h(
'div',
{
class: ['scrollbar__bar', 'is-' + bar.value.key],
onMousedown: clickTrackHandler,
},
h('div', {
ref: thumb,
class: 'scrollbar__thumb',
onMousedown: clickThumbHandler,
style: renderThumbStyle({
size: props.size,
move: props.move,
bar: bar.value,
}),
})
);
},
});

View File

@ -0,0 +1,18 @@
export interface BarMapItem {
offset: string;
scroll: string;
scrollSize: string;
size: string;
key: string;
axis: string;
client: string;
direction: string;
}
export interface BarMap {
vertical: BarMapItem;
horizontal: BarMapItem;
}
export interface ScrollbarType {
wrap: ElRef;
}

View File

@ -0,0 +1,50 @@
import type { BarMap } from './types';
export const BAR_MAP: BarMap = {
vertical: {
offset: 'offsetHeight',
scroll: 'scrollTop',
scrollSize: 'scrollHeight',
size: 'height',
key: 'vertical',
axis: 'Y',
client: 'clientY',
direction: 'top',
},
horizontal: {
offset: 'offsetWidth',
scroll: 'scrollLeft',
scrollSize: 'scrollWidth',
size: 'width',
key: 'horizontal',
axis: 'X',
client: 'clientX',
direction: 'left',
},
};
// @ts-ignore
export function renderThumbStyle({ move, size, bar }) {
const style = {} as any;
const translate = `translate${bar.axis}(${move}%)`;
style[bar.size] = size;
style.transform = translate;
style.msTransform = translate;
style.webkitTransform = translate;
return style;
}
function extend<T, K>(to: T, _from: K): T & K {
return Object.assign(to, _from);
}
export function toObject<T>(arr: Array<T>): Recordable<T> {
const res = {};
for (let i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i]);
}
}
return res;
}