工具组件提效优化
-
在项目开发过程中,使用到的方法和组件,有时候需要进行优化
-
性能优化
-
使用方式优化,用起来更便捷
-
用户体验优化
-
有时候组件,在某些场景下需要让用户用起来更舒服
-
比如表格,滚动时候
-
表头可以一直固定在顶部
-
底部滚动条固定在底部
-
-
-
event
export function addEventListen(
target: Window | HTMLElement,
event: string,
handler: EventListenerOrEventListenerObject,
capture = false
) {
if (
target.addEventListener &&
typeof target.addEventListener === 'function'
) {
target.addEventListener(event, handler, capture);
}
}
export function removeEventListen(
target: Window | HTMLElement,
event: string,
handler: EventListenerOrEventListenerObject,
capture = false
) {
if (
target.removeEventListener &&
typeof target.removeEventListener === 'function'
) {
target.removeEventListener(event, handler, capture);
}
}
使用例子
onBeforeMount(() => {
addEventListen(window, 'resize', debounceFn);
});
onBeforeUnmount(() => {
removeEventListen(window, 'resize', debounceFn);
});
固定顶部滚动条实现
问题:
- 横向滚动的表格,如果表格高度超过了一个屏幕,横向滚动条只有拖到页面底部时才会出现,这样不方便用户试用。
遇到问题:
- sticky布局 遮挡影响了fixed布局
- z-index可解决,底部滚动条z-index 高于sticky布局即可
第三方库参考:
滚动条样式
::-webkit-scrollbar {
// width: 16px;
// height: 4px;
}
::-webkit-scrollbar-thumb {
border: 4px solid transparent;
background-clip: padding-box;
border-radius: 10px;
background-color: var(--color-text-4);
}
::-webkit-scrollbar-thumb:hover {
background-color: var(--color-text-3);
}
vue组件实现
<script lang="jsx">
import { defineComponent } from 'vue';
import { addEventListen, removeEventListen } from '@/utils/event';
import { useAppStore } from '@/store';
import { forEach } from 'lodash';
export default defineComponent({
props: {
// 距离
distance: {
type: Number,
default: 30,
},
// 滚动条高度
barHeight: {
type: Number,
default: 20,
},
delay: {
type: Number,
default: 500,
},
},
setup(props, { slots }) {
const appStore = useAppStore();
const tableContentRef = ref(null);
const scrollbarWidth = ref(null);
const scrollbarRef = ref(null);
const scrollWidth = ref(0);
const scrollbarLeft = ref(0);
const stopObserver = ref([]);
const tableVisible = ref(false);
const headerVisible = ref(false);
const setScrollbar = async () => {
await nextTick();
setTimeout(() => {
const { width, left } = useElementBounding(tableContentRef.value);
scrollbarWidth.value = width.value;
scrollbarLeft.value = left.value;
}, props.delay);
};
const setTableScroll = (left) => {
// table有数据,body滚动
const tableBodyDom =
tableContentRef.value.querySelector('.arco-table-body');
// 兼容table无数据情况,表头滚动
const tableHeaderDom =
tableContentRef.value.querySelector('.arco-table-header');
tableBodyDom.scrollLeft = left;
tableHeaderDom.scrollLeft = left;
};
const getScrollWidth = () => {
const tableElement = tableContentRef.value.querySelector(
'.arco-table-element'
);
const { stop } = useResizeObserver(tableElement, (entries) => {
const entry = entries[0];
const { width } = entry.contentRect;
scrollWidth.value = width;
});
stopObserver.value.push(stop);
};
const setVisible = () => {
const { stopIntersection } = useIntersectionObserver(
tableContentRef,
([{ isIntersecting }]) => {
tableVisible.value = isIntersecting;
}
);
const tableHeaderDom =
tableContentRef.value.querySelector('.arco-table-header');
const { stopResize } = useResizeObserver(tableHeaderDom, (entries) => {
const entry = entries[0];
const { height } = entry.contentRect;
headerVisible.value = Boolean(height);
});
stopObserver.value.push(stopIntersection, stopResize);
};
const onScroll = (event) => {
setTableScroll(event.target.scrollLeft);
};
const debounceFn = useDebounceFn(setScrollbar, 100);
onMounted(async () => {
await nextTick();
addEventListen(window, 'resize', debounceFn);
getScrollWidth();
setScrollbar();
setVisible();
});
onBeforeUnmount(() => {
removeEventListen(window, 'resize', debounceFn);
forEach(stopObserver.value, (stop) => stop?.());
});
const scrollVisible = computed(() => {
return tableVisible.value && headerVisible.value;
});
watch(
() => appStore.menuCollapse,
() => setScrollbar()
);
return () => (
<div class="fixed-scrollbar-wrapper">
<div ref={tableContentRef}>{slots.default?.()}</div>
{scrollVisible.value && (
<div
class="scrollbar-box overflow-x-auto fixed bottom-0 z-[99]"
style={{
'height': `${props.barHeight}px`,
'width': `${scrollbarWidth.value - props.distance}px`,
'left': `${scrollbarLeft.value + props.distance}px`,
'--barHeight': `${props.barHeight}px`,
}}
ref={scrollbarRef}
onScroll={onScroll}
>
<div
class="scrollbar h-[1px]"
style={{ width: `${scrollWidth.value}px` }}
></div>
</div>
)}
</div>
);
},
});
</script>
<style lang="scss" scoped>
.fixed-scrollbar-wrapper {
:deep(.arco-table .arco-scrollbar-track-direction-horizontal) {
.arco-scrollbar-thumb-bar {
height: 0px;
}
}
.scrollbar-box {
&::-webkit-scrollbar {
height: var(--barHeight) !important;
}
}
}
</style>