element-plus
Version:
A Component Library for Vue 3
367 lines (362 loc) • 13.2 kB
JavaScript
Object.defineProperty(exports, '__esModule', { value: true });
var vue = require('vue');
var core = require('@vueuse/core');
var useCache = require('../hooks/use-cache.js');
var useWheel = require('../hooks/use-wheel.js');
var scrollbar = require('../components/scrollbar.js');
var utils = require('../utils.js');
var props = require('../props.js');
var defaults = require('../defaults.js');
var index = require('../../../../hooks/use-namespace/index.js');
var types = require('../../../../utils/types.js');
var shared = require('@vue/shared');
const createList = ({
name,
getOffset,
getItemSize,
getItemOffset,
getEstimatedTotalSize,
getStartIndexForOffset,
getStopIndexForStartIndex,
initCache,
clearCache,
validateProps
}) => {
return vue.defineComponent({
name: name != null ? name : "ElVirtualList",
props: props.virtualizedListProps,
emits: [defaults.ITEM_RENDER_EVT, defaults.SCROLL_EVT],
setup(props, { emit, expose }) {
validateProps(props);
const instance = vue.getCurrentInstance();
const ns = index.useNamespace("vl");
const dynamicSizeCache = vue.ref(initCache(props, instance));
const getItemStyleCache = useCache.useCache();
const windowRef = vue.ref();
const innerRef = vue.ref();
const scrollbarRef = vue.ref();
const states = vue.ref({
isScrolling: false,
scrollDir: "forward",
scrollOffset: types.isNumber(props.initScrollOffset) ? props.initScrollOffset : 0,
updateRequested: false,
isScrollbarDragging: false,
scrollbarAlwaysOn: props.scrollbarAlwaysOn
});
const itemsToRender = vue.computed(() => {
const { total, cache } = props;
const { isScrolling, scrollDir, scrollOffset } = vue.unref(states);
if (total === 0) {
return [0, 0, 0, 0];
}
const startIndex = getStartIndexForOffset(props, scrollOffset, vue.unref(dynamicSizeCache));
const stopIndex = getStopIndexForStartIndex(props, startIndex, scrollOffset, vue.unref(dynamicSizeCache));
const cacheBackward = !isScrolling || scrollDir === defaults.BACKWARD ? Math.max(1, cache) : 1;
const cacheForward = !isScrolling || scrollDir === defaults.FORWARD ? Math.max(1, cache) : 1;
return [
Math.max(0, startIndex - cacheBackward),
Math.max(0, Math.min(total - 1, stopIndex + cacheForward)),
startIndex,
stopIndex
];
});
const estimatedTotalSize = vue.computed(() => getEstimatedTotalSize(props, vue.unref(dynamicSizeCache)));
const _isHorizontal = vue.computed(() => utils.isHorizontal(props.layout));
const windowStyle = vue.computed(() => [
{
position: "relative",
[`overflow-${_isHorizontal.value ? "x" : "y"}`]: "scroll",
WebkitOverflowScrolling: "touch",
willChange: "transform"
},
{
direction: props.direction,
height: types.isNumber(props.height) ? `${props.height}px` : props.height,
width: types.isNumber(props.width) ? `${props.width}px` : props.width
},
props.style
]);
const innerStyle = vue.computed(() => {
const size = vue.unref(estimatedTotalSize);
const horizontal = vue.unref(_isHorizontal);
return {
height: horizontal ? "100%" : `${size}px`,
pointerEvents: vue.unref(states).isScrolling ? "none" : void 0,
width: horizontal ? `${size}px` : "100%"
};
});
const clientSize = vue.computed(() => _isHorizontal.value ? props.width : props.height);
const { onWheel } = useWheel["default"]({
atStartEdge: vue.computed(() => states.value.scrollOffset <= 0),
atEndEdge: vue.computed(() => states.value.scrollOffset >= estimatedTotalSize.value),
layout: vue.computed(() => props.layout)
}, (offset) => {
var _a, _b;
(_b = (_a = scrollbarRef.value).onMouseUp) == null ? void 0 : _b.call(_a);
scrollTo(Math.min(states.value.scrollOffset + offset, estimatedTotalSize.value - clientSize.value));
});
core.useEventListener(windowRef, "wheel", onWheel, {
passive: false
});
const emitEvents = () => {
const { total } = props;
if (total > 0) {
const [cacheStart, cacheEnd, visibleStart, visibleEnd] = vue.unref(itemsToRender);
emit(defaults.ITEM_RENDER_EVT, cacheStart, cacheEnd, visibleStart, visibleEnd);
}
const { scrollDir, scrollOffset, updateRequested } = vue.unref(states);
emit(defaults.SCROLL_EVT, scrollDir, scrollOffset, updateRequested);
};
const scrollVertically = (e) => {
const { clientHeight, scrollHeight, scrollTop } = e.currentTarget;
const _states = vue.unref(states);
if (_states.scrollOffset === scrollTop) {
return;
}
const scrollOffset = Math.max(0, Math.min(scrollTop, scrollHeight - clientHeight));
states.value = {
..._states,
isScrolling: true,
scrollDir: utils.getScrollDir(_states.scrollOffset, scrollOffset),
scrollOffset,
updateRequested: false
};
vue.nextTick(resetIsScrolling);
};
const scrollHorizontally = (e) => {
const { clientWidth, scrollLeft, scrollWidth } = e.currentTarget;
const _states = vue.unref(states);
if (_states.scrollOffset === scrollLeft) {
return;
}
const { direction } = props;
let scrollOffset = scrollLeft;
if (direction === defaults.RTL) {
switch (utils.getRTLOffsetType()) {
case defaults.RTL_OFFSET_NAG: {
scrollOffset = -scrollLeft;
break;
}
case defaults.RTL_OFFSET_POS_DESC: {
scrollOffset = scrollWidth - clientWidth - scrollLeft;
break;
}
}
}
scrollOffset = Math.max(0, Math.min(scrollOffset, scrollWidth - clientWidth));
states.value = {
..._states,
isScrolling: true,
scrollDir: utils.getScrollDir(_states.scrollOffset, scrollOffset),
scrollOffset,
updateRequested: false
};
vue.nextTick(resetIsScrolling);
};
const onScroll = (e) => {
vue.unref(_isHorizontal) ? scrollHorizontally(e) : scrollVertically(e);
emitEvents();
};
const onScrollbarScroll = (distanceToGo, totalSteps) => {
const offset = (estimatedTotalSize.value - clientSize.value) / totalSteps * distanceToGo;
scrollTo(Math.min(estimatedTotalSize.value - clientSize.value, offset));
};
const scrollTo = (offset) => {
offset = Math.max(offset, 0);
if (offset === vue.unref(states).scrollOffset) {
return;
}
states.value = {
...vue.unref(states),
scrollOffset: offset,
scrollDir: utils.getScrollDir(vue.unref(states).scrollOffset, offset),
updateRequested: true
};
vue.nextTick(resetIsScrolling);
};
const scrollToItem = (idx, alignment = defaults.AUTO_ALIGNMENT) => {
const { scrollOffset } = vue.unref(states);
idx = Math.max(0, Math.min(idx, props.total - 1));
scrollTo(getOffset(props, idx, alignment, scrollOffset, vue.unref(dynamicSizeCache)));
};
const getItemStyle = (idx) => {
const { direction, itemSize, layout } = props;
const itemStyleCache = getItemStyleCache.value(clearCache && itemSize, clearCache && layout, clearCache && direction);
let style;
if (shared.hasOwn(itemStyleCache, String(idx))) {
style = itemStyleCache[idx];
} else {
const offset = getItemOffset(props, idx, vue.unref(dynamicSizeCache));
const size = getItemSize(props, idx, vue.unref(dynamicSizeCache));
const horizontal = vue.unref(_isHorizontal);
const isRtl = direction === defaults.RTL;
const offsetHorizontal = horizontal ? offset : 0;
itemStyleCache[idx] = style = {
position: "absolute",
left: isRtl ? void 0 : `${offsetHorizontal}px`,
right: isRtl ? `${offsetHorizontal}px` : void 0,
top: !horizontal ? `${offset}px` : 0,
height: !horizontal ? `${size}px` : "100%",
width: horizontal ? `${size}px` : "100%"
};
}
return style;
};
const resetIsScrolling = () => {
states.value.isScrolling = false;
vue.nextTick(() => {
getItemStyleCache.value(-1, null, null);
});
};
const resetScrollTop = () => {
const window = windowRef.value;
if (window) {
window.scrollTop = 0;
}
};
vue.onMounted(() => {
if (!core.isClient)
return;
const { initScrollOffset } = props;
const windowElement = vue.unref(windowRef);
if (types.isNumber(initScrollOffset) && windowElement) {
if (vue.unref(_isHorizontal)) {
windowElement.scrollLeft = initScrollOffset;
} else {
windowElement.scrollTop = initScrollOffset;
}
}
emitEvents();
});
vue.onUpdated(() => {
const { direction, layout } = props;
const { scrollOffset, updateRequested } = vue.unref(states);
const windowElement = vue.unref(windowRef);
if (updateRequested && windowElement) {
if (layout === defaults.HORIZONTAL) {
if (direction === defaults.RTL) {
switch (utils.getRTLOffsetType()) {
case defaults.RTL_OFFSET_NAG: {
windowElement.scrollLeft = -scrollOffset;
break;
}
case defaults.RTL_OFFSET_POS_ASC: {
windowElement.scrollLeft = scrollOffset;
break;
}
default: {
const { clientWidth, scrollWidth } = windowElement;
windowElement.scrollLeft = scrollWidth - clientWidth - scrollOffset;
break;
}
}
} else {
windowElement.scrollLeft = scrollOffset;
}
} else {
windowElement.scrollTop = scrollOffset;
}
}
});
vue.onActivated(() => {
vue.unref(windowRef).scrollTop = vue.unref(states).scrollOffset;
});
const api = {
ns,
clientSize,
estimatedTotalSize,
windowStyle,
windowRef,
innerRef,
innerStyle,
itemsToRender,
scrollbarRef,
states,
getItemStyle,
onScroll,
onScrollbarScroll,
onWheel,
scrollTo,
scrollToItem,
resetScrollTop
};
expose({
windowRef,
innerRef,
getItemStyleCache,
scrollTo,
scrollToItem,
resetScrollTop,
states
});
return api;
},
render(ctx) {
var _a;
const {
$slots,
className,
clientSize,
containerElement,
data,
getItemStyle,
innerElement,
itemsToRender,
innerStyle,
layout,
total,
onScroll,
onScrollbarScroll,
states,
useIsScrolling,
windowStyle,
ns
} = ctx;
const [start, end] = itemsToRender;
const Container = vue.resolveDynamicComponent(containerElement);
const Inner = vue.resolveDynamicComponent(innerElement);
const children = [];
if (total > 0) {
for (let i = start; i <= end; i++) {
children.push(vue.h(vue.Fragment, { key: i }, (_a = $slots.default) == null ? void 0 : _a.call($slots, {
data,
index: i,
isScrolling: useIsScrolling ? states.isScrolling : void 0,
style: getItemStyle(i)
})));
}
}
const InnerNode = [
vue.h(Inner, {
style: innerStyle,
ref: "innerRef"
}, !shared.isString(Inner) ? {
default: () => children
} : children)
];
const scrollbar$1 = vue.h(scrollbar["default"], {
ref: "scrollbarRef",
clientSize,
layout,
onScroll: onScrollbarScroll,
ratio: clientSize * 100 / this.estimatedTotalSize,
scrollFrom: states.scrollOffset / (this.estimatedTotalSize - clientSize),
total
});
const listContainer = vue.h(Container, {
class: [ns.e("window"), className],
style: windowStyle,
onScroll,
ref: "windowRef",
key: 0
}, !shared.isString(Container) ? { default: () => [InnerNode] } : [InnerNode]);
return vue.h("div", {
key: 0,
class: [ns.e("wrapper"), states.scrollbarAlwaysOn ? "always-on" : ""]
}, [listContainer, scrollbar$1]);
}
});
};
exports["default"] = createList;
//# sourceMappingURL=build-list.js.map
;