ahooks-v2
Version:
react hooks library
196 lines (165 loc) • 4.59 kB
JavaScript
;
var __read = this && this.__read || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o),
r,
ar = [],
e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) {
ar.push(r.value);
}
} catch (error) {
e = {
error: error
};
} finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
} finally {
if (e) throw e.error;
}
}
return ar;
};
var __importDefault = this && this.__importDefault || function (mod) {
return mod && mod.__esModule ? mod : {
"default": mod
};
};
Object.defineProperty(exports, "__esModule", {
value: true
});
var react_1 = require("react");
var useSize_1 = __importDefault(require("../useSize"));
exports["default"] = function (list, options) {
var containerRef = react_1.useRef();
var size = useSize_1["default"](containerRef); // 暂时禁止 cache
// const distanceCache = useRef<{ [key: number]: number }>({});
var _a = __read(react_1.useState({
start: 0,
end: 10
}), 2),
state = _a[0],
setState = _a[1];
var itemHeight = options.itemHeight,
_b = options.overscan,
overscan = _b === void 0 ? 5 : _b;
if (!itemHeight) {
console.warn('please enter a valid itemHeight');
}
var getViewCapacity = function getViewCapacity(containerHeight) {
if (typeof itemHeight === 'number') {
return Math.ceil(containerHeight / itemHeight);
}
var _a = state.start,
start = _a === void 0 ? 0 : _a;
var sum = 0;
var capacity = 0;
for (var i = start; i < list.length; i++) {
var height = itemHeight(i, list[i]);
sum += height;
if (sum >= containerHeight) {
capacity = i;
break;
}
}
return capacity - start;
};
var getOffset = function getOffset(scrollTop) {
if (typeof itemHeight === 'number') {
return Math.floor(scrollTop / itemHeight) + 1;
}
var sum = 0;
var offset = 0;
for (var i = 0; i < list.length; i++) {
var height = itemHeight(i, list[i]);
sum += height;
if (sum >= scrollTop) {
offset = i;
break;
}
}
return offset + 1;
};
var calculateRange = function calculateRange() {
var element = containerRef.current;
if (element) {
var offset = getOffset(element.scrollTop);
var viewCapacity = getViewCapacity(element.clientHeight);
var from = offset - overscan;
var to = offset + viewCapacity + overscan;
setState({
start: from < 0 ? 0 : from,
end: to > list.length ? list.length : to
});
}
};
react_1.useEffect(function () {
calculateRange();
}, [size.width, size.height, list.length]);
var totalHeight = react_1.useMemo(function () {
if (typeof itemHeight === 'number') {
return list.length * itemHeight;
}
return list.reduce(function (sum, _, index) {
return sum + itemHeight(index, list[index]);
}, 0);
}, [list.length]);
var getDistanceTop = function getDistanceTop(index) {
// 如果有缓存,优先返回缓存值
// if (enableCache && distanceCache.current[index]) {
// return distanceCache.current[index];
// }
if (typeof itemHeight === 'number') {
var height_1 = index * itemHeight; // if (enableCache) {
// distanceCache.current[index] = height;
// }
return height_1;
}
var height = list.slice(0, index).reduce(function (sum, _, i) {
return sum + itemHeight(i, list[i]);
}, 0); // if (enableCache) {
// distanceCache.current[index] = height;
// }
return height;
};
var scrollTo = function scrollTo(index) {
if (containerRef.current) {
containerRef.current.scrollTop = getDistanceTop(index);
calculateRange();
}
};
var offsetTop = react_1.useMemo(function () {
return getDistanceTop(state.start);
}, [state.start]);
return {
list: list.slice(state.start, state.end).map(function (ele, index) {
return {
data: ele,
index: index + state.start
};
}),
scrollTo: scrollTo,
containerProps: {
ref: function ref(ele) {
containerRef.current = ele;
},
onScroll: function onScroll(e) {
e.preventDefault();
calculateRange();
},
style: {
overflowY: 'auto'
}
},
wrapperProps: {
style: {
width: '100%',
height: totalHeight - offsetTop,
marginTop: offsetTop
}
}
};
};