choo-taro-ui-vue3
Version:
Taro UI Rewritten in Vue 3.0
190 lines (182 loc) • 7.46 kB
JavaScript
import { defineComponent, ref, computed, watch, onMounted, toRefs, renderSlot, resolveComponent, withCtx, openBlock, createBlock, createCommentVNode, renderList, Fragment, createElementBlock, normalizeStyle, createVNode, mergeProps } from 'vue';
import { convertToUnit } from '../utils';
import { dimensionsFactory } from '../composables';
const { useDimensions, makeDimensionsProps } = dimensionsFactory();
const AtVirtualScroll = defineComponent({
name: "AtVirtualScroll",
emits: ["reach-top", "reach-bottom"],
props: {
...makeDimensionsProps(),
bench: {
type: [Number, String],
default: 0
},
itemHeight: {
type: [Number, String],
required: true
},
items: {
type: Array,
default: () => []
},
scrollToItem: [Number, String],
reachTopThreshold: {
type: [Number, String],
default: 50
},
reachBottomThreshold: {
type: [Number, String],
default: 50
}
},
setup(props) {
const first = ref(0);
const last = ref(0);
const scrollTop = ref(0);
const elRef = ref(null);
const anchor = computed(() => process.env.TARO_ENV === "h5" ? { scrollTop: scrollTop.value } : { scrollIntoView: `item-${props.scrollToItem || 0}` });
const __bench = computed(() => {
return parseInt(`${props.bench}`, 10);
});
const item_height = computed(() => {
return parseInt(`${props.itemHeight}`, 10);
});
const firstToRender = computed(() => {
return Math.max(0, first.value - __bench.value);
});
const lastToRender = computed(() => {
return Math.min(props.items.length, last.value + __bench.value);
});
const scrollContainerStyle = computed(() => ({
height: convertToUnit(props.items.length * item_height.value)
}));
const genScrollItemStyle = computed(() => (i) => ({
top: convertToUnit((i + firstToRender.value) * item_height.value)
}));
const { dimensions } = useDimensions(props);
watch(() => props.height, updateFirstAndLast);
watch(() => props.itemHeight, updateFirstAndLast);
watch(() => props.scrollToItem, (index, _prevIndex) => {
let parsedIndex = parseInt(`${index || 0}`, 10);
parsedIndex = Math.min(props.items.length - 1, Math.max(0, parsedIndex));
scrollTop.value = parsedIndex * item_height.value;
updateFirstAndLast();
});
onMounted(() => {
if (typeof props.scrollToItem !== "undefined") {
let parsedIndex = parseInt(`${props.scrollToItem}`, 10);
scrollTop.value = parsedIndex * item_height.value;
updateFirstAndLast();
} else {
last.value = getLast(0);
}
});
function getFirst() {
return Math.floor(scrollTop.value / item_height.value);
}
function getLast(first2) {
const height = parseInt(`${props.height}`, 10) || elRef.value.$el.clientHeight;
return first2 + Math.ceil(height / item_height.value);
}
function updateFirstAndLast() {
first.value = getFirst();
last.value = getLast(first.value);
}
function handleScroll(e) {
scrollTop.value = process.env.TARO_ENV === "h5" ? elRef.value.$el.scrollTop : e.detail.scrollTop;
updateFirstAndLast();
}
return {
...toRefs(props),
anchor,
elRef,
scrollTop,
dimensions,
item_height,
lastToRender,
firstToRender,
genScrollItemStyle,
scrollContainerStyle,
handleScroll
};
}
});
// Binding optimization for webpack code-split
const _renderSlot = renderSlot, _resolveComponent = resolveComponent, _withCtx = withCtx, _openBlock = openBlock, _createBlock = createBlock, _createCommentVNode = createCommentVNode, _renderList = renderList, _Fragment = Fragment, _createElementBlock = createElementBlock, _normalizeStyle = normalizeStyle, _createVNode = createVNode, _mergeProps = mergeProps;
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_taro_view = process.env.TARO_ENV === "h5" ? _resolveComponent("taro-view") : "view";
const _component_taro_scroll_view = process.env.TARO_ENV === "h5" ? _resolveComponent("taro-scroll-view") : "scroll-view";
return (_openBlock(), _createBlock(_component_taro_view, null, {
default: _withCtx(() => [
('header' in _ctx.$slots)
? (_openBlock(), _createBlock(_component_taro_view, {
key: 0,
class: "at-virtual-scroll__header"
}, {
default: _withCtx(() => [
_renderSlot(_ctx.$slots, "header")
]),
_: 3 /* FORWARDED */
}))
: _createCommentVNode("v-if", true),
_createVNode(_component_taro_scroll_view, _mergeProps({ class: "at-virtual-scroll" }, _ctx.anchor, {
ref: el => _ctx.elRef = el,
style: _ctx.dimensions.style,
"scroll-y": true,
"scroll-with-animation": true,
"upper-threshold": parseInt(`${_ctx.reachTopThreshold}`, 10),
"lower-threshold": parseInt(`${_ctx.reachBottomThreshold}`, 10),
onScroll: _ctx.handleScroll,
onScrolltoupper: _cache[0] || (_cache[0] = $event => (_ctx.$emit('reach-top', $event))),
onScrolltolower: _cache[1] || (_cache[1] = $event => (_ctx.$emit('reach-bottom', $event)))
}), {
default: _withCtx(() => [
_createVNode(_component_taro_view, null, {
default: _withCtx(() => [
_createVNode(_component_taro_view, {
class: "at-virtual-scroll__container",
style: _normalizeStyle(_ctx.scrollContainerStyle)
}, {
default: _withCtx(() => [
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.items.slice(_ctx.firstToRender, _ctx.lastToRender), (item, index) => {
return (_openBlock(), _createBlock(_component_taro_view, {
class: "at-virtual-scroll__item",
key: _ctx.firstToRender + index,
id: `item-${_ctx.firstToRender + index}`,
style: _normalizeStyle(_ctx.genScrollItemStyle(index))
}, {
default: _withCtx(() => [
_renderSlot(_ctx.$slots, "default", {
index: _ctx.firstToRender + index,
item: item
})
]),
_: 2 /* DYNAMIC */
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["id", "style"]))
}), 128 /* KEYED_FRAGMENT */))
]),
_: 3 /* FORWARDED */
}, 8 /* PROPS */, ["style"]),
('footer' in _ctx.$slots)
? (_openBlock(), _createBlock(_component_taro_view, {
key: 0,
class: "at-virtual-scroll__footer"
}, {
default: _withCtx(() => [
_renderSlot(_ctx.$slots, "footer")
]),
_: 3 /* FORWARDED */
}))
: _createCommentVNode("v-if", true)
]),
_: 3 /* FORWARDED */
})
]),
_: 3 /* FORWARDED */
}, 16 /* FULL_PROPS */, ["style", "upper-threshold", "lower-threshold", "onScroll"])
]),
_: 3 /* FORWARDED */
}))
}
AtVirtualScroll.render = _sfc_render;
export default AtVirtualScroll;