|
|
@@ -0,0 +1,925 @@
|
|
|
+module.exports =
|
|
|
+/******/ (function(modules) { // webpackBootstrap
|
|
|
+/******/ // The module cache
|
|
|
+/******/ var installedModules = {};
|
|
|
+/******/
|
|
|
+/******/ // The require function
|
|
|
+/******/ function __webpack_require__(moduleId) {
|
|
|
+/******/
|
|
|
+/******/ // Check if module is in cache
|
|
|
+/******/ if(installedModules[moduleId]) {
|
|
|
+/******/ return installedModules[moduleId].exports;
|
|
|
+/******/ }
|
|
|
+/******/ // Create a new module (and put it into the cache)
|
|
|
+/******/ var module = installedModules[moduleId] = {
|
|
|
+/******/ i: moduleId,
|
|
|
+/******/ l: false,
|
|
|
+/******/ exports: {}
|
|
|
+/******/ };
|
|
|
+/******/
|
|
|
+/******/ // Execute the module function
|
|
|
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
|
|
+/******/
|
|
|
+/******/ // Flag the module as loaded
|
|
|
+/******/ module.l = true;
|
|
|
+/******/
|
|
|
+/******/ // Return the exports of the module
|
|
|
+/******/ return module.exports;
|
|
|
+/******/ }
|
|
|
+/******/
|
|
|
+/******/
|
|
|
+/******/ // expose the modules object (__webpack_modules__)
|
|
|
+/******/ __webpack_require__.m = modules;
|
|
|
+/******/
|
|
|
+/******/ // expose the module cache
|
|
|
+/******/ __webpack_require__.c = installedModules;
|
|
|
+/******/
|
|
|
+/******/ // define getter function for harmony exports
|
|
|
+/******/ __webpack_require__.d = function(exports, name, getter) {
|
|
|
+/******/ if(!__webpack_require__.o(exports, name)) {
|
|
|
+/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
|
|
+/******/ }
|
|
|
+/******/ };
|
|
|
+/******/
|
|
|
+/******/ // define __esModule on exports
|
|
|
+/******/ __webpack_require__.r = function(exports) {
|
|
|
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
|
|
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
+/******/ }
|
|
|
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
+/******/ };
|
|
|
+/******/
|
|
|
+/******/ // create a fake namespace object
|
|
|
+/******/ // mode & 1: value is a module id, require it
|
|
|
+/******/ // mode & 2: merge all properties of value into the ns
|
|
|
+/******/ // mode & 4: return value when already ns object
|
|
|
+/******/ // mode & 8|1: behave like require
|
|
|
+/******/ __webpack_require__.t = function(value, mode) {
|
|
|
+/******/ if(mode & 1) value = __webpack_require__(value);
|
|
|
+/******/ if(mode & 8) return value;
|
|
|
+/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
|
|
+/******/ var ns = Object.create(null);
|
|
|
+/******/ __webpack_require__.r(ns);
|
|
|
+/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
|
|
+/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
|
|
+/******/ return ns;
|
|
|
+/******/ };
|
|
|
+/******/
|
|
|
+/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|
|
+/******/ __webpack_require__.n = function(module) {
|
|
|
+/******/ var getter = module && module.__esModule ?
|
|
|
+/******/ function getDefault() { return module['default']; } :
|
|
|
+/******/ function getModuleExports() { return module; };
|
|
|
+/******/ __webpack_require__.d(getter, 'a', getter);
|
|
|
+/******/ return getter;
|
|
|
+/******/ };
|
|
|
+/******/
|
|
|
+/******/ // Object.prototype.hasOwnProperty.call
|
|
|
+/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
|
|
+/******/
|
|
|
+/******/ // __webpack_public_path__
|
|
|
+/******/ __webpack_require__.p = "";
|
|
|
+/******/
|
|
|
+/******/
|
|
|
+/******/ // Load entry module and return exports
|
|
|
+/******/ return __webpack_require__(__webpack_require__.s = 6);
|
|
|
+/******/ })
|
|
|
+/************************************************************************/
|
|
|
+/******/ ({
|
|
|
+
|
|
|
+/***/ 0:
|
|
|
+/***/ (function(module, exports, __webpack_require__) {
|
|
|
+
|
|
|
+"use strict";
|
|
|
+
|
|
|
+
|
|
|
+var isIPhone = false;
|
|
|
+var deviceWidth = void 0;
|
|
|
+var deviceDPR = void 0;
|
|
|
+var BASE_DEVICE_WIDTH = 750;
|
|
|
+var checkDeviceWidth = function checkDeviceWidth() {
|
|
|
+ var info = wx.getSystemInfoSync();
|
|
|
+ // console.log('info', info)
|
|
|
+ isIPhone = info.platform === 'ios';
|
|
|
+ var newDeviceWidth = info.screenWidth || 375;
|
|
|
+ var newDeviceDPR = info.pixelRatio || 2;
|
|
|
+
|
|
|
+ if (!isIPhone) {
|
|
|
+ // HACK switch width and height when landscape
|
|
|
+ // const newDeviceHeight = info.screenHeight || 375
|
|
|
+ // 暂时不处理转屏的情况
|
|
|
+ }
|
|
|
+
|
|
|
+ if (newDeviceWidth !== deviceWidth || newDeviceDPR !== deviceDPR) {
|
|
|
+ deviceWidth = newDeviceWidth;
|
|
|
+ deviceDPR = newDeviceDPR;
|
|
|
+ // console.info('Updated device width: ' + newDeviceWidth + 'px DPR ' + newDeviceDPR)
|
|
|
+ }
|
|
|
+};
|
|
|
+checkDeviceWidth();
|
|
|
+
|
|
|
+var eps = 1e-4;
|
|
|
+var transformByDPR = function transformByDPR(number) {
|
|
|
+ if (number === 0) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ number = number / BASE_DEVICE_WIDTH * deviceWidth;
|
|
|
+ number = Math.floor(number + eps);
|
|
|
+ if (number === 0) {
|
|
|
+ if (deviceDPR === 1 || !isIPhone) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return 0.5;
|
|
|
+ }
|
|
|
+ return number;
|
|
|
+};
|
|
|
+
|
|
|
+var rpxRE = /([+-]?\d+(?:\.\d+)?)rpx/gi;
|
|
|
+// const inlineRpxRE = /(?::|\s|\(|\/)([+-]?\d+(?:\.\d+)?)rpx/g
|
|
|
+
|
|
|
+var transformRpx = function transformRpx(style, inline) {
|
|
|
+ if (typeof style !== 'string') {
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+ var re = rpxRE;
|
|
|
+ return style.replace(re, function (match, num) {
|
|
|
+ return transformByDPR(Number(num)) + (inline ? 'px' : '');
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+module.exports = {
|
|
|
+ transformRpx: transformRpx
|
|
|
+};
|
|
|
+
|
|
|
+/***/ }),
|
|
|
+
|
|
|
+/***/ 6:
|
|
|
+/***/ (function(module, exports, __webpack_require__) {
|
|
|
+
|
|
|
+"use strict";
|
|
|
+
|
|
|
+
|
|
|
+/* eslint complexity: ["error", {"max": 50}] */
|
|
|
+/* eslint-disable indent */
|
|
|
+var DEFAULT_SHOW_SCREENS = 4;
|
|
|
+var RECT_SIZE = 200;
|
|
|
+var systemInfo = wx.getSystemInfoSync();
|
|
|
+var DEBUG = false;
|
|
|
+var transformRpx = __webpack_require__(0).transformRpx;
|
|
|
+
|
|
|
+Component({
|
|
|
+ options: {
|
|
|
+ multipleSlots: true // 在组件定义时的选项中启用多slot支持
|
|
|
+ },
|
|
|
+ relations: {
|
|
|
+ '../recycle-item/recycle-item': {
|
|
|
+ type: 'child', // 关联的目标节点应为子节点
|
|
|
+ linked: function linked(target) {
|
|
|
+ // 检查第一个的尺寸就好了吧
|
|
|
+ if (!this._hasCheckSize) {
|
|
|
+ this._hasCheckSize = true;
|
|
|
+ var size = this.boundingClientRect(this._pos.beginIndex);
|
|
|
+ if (!size) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ setTimeout(function () {
|
|
|
+ try {
|
|
|
+ target.createSelectorQuery().select('.wx-recycle-item').boundingClientRect(function (rect) {
|
|
|
+ if (rect && (rect.width !== size.width || rect.height !== size.height)) {
|
|
|
+ // eslint-disable-next-line no-console
|
|
|
+ console.warn('[recycle-view] the size in <recycle-item> is not the same with param ' + ('itemSize, expect {width: ' + rect.width + ', height: ' + rect.height + '} but got ') + ('{width: ' + size.width + ', height: ' + size.height + '}'));
|
|
|
+ }
|
|
|
+ }).exec();
|
|
|
+ } catch (e) {
|
|
|
+ // do nothing
|
|
|
+ }
|
|
|
+ }, 10);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 组件的属性列表
|
|
|
+ */
|
|
|
+ properties: {
|
|
|
+ debug: {
|
|
|
+ type: Boolean,
|
|
|
+ value: false
|
|
|
+ },
|
|
|
+ scrollY: {
|
|
|
+ type: Boolean,
|
|
|
+ value: true
|
|
|
+ },
|
|
|
+ batch: {
|
|
|
+ type: Boolean,
|
|
|
+ value: false,
|
|
|
+ public: true,
|
|
|
+ observer: '_recycleInnerBatchDataChanged'
|
|
|
+ },
|
|
|
+ batchKey: {
|
|
|
+ type: String,
|
|
|
+ value: 'batchSetRecycleData',
|
|
|
+ public: true
|
|
|
+ },
|
|
|
+ scrollTop: {
|
|
|
+ type: Number,
|
|
|
+ value: 0,
|
|
|
+ public: true,
|
|
|
+ observer: '_scrollTopChanged',
|
|
|
+ observeAssignments: true
|
|
|
+ },
|
|
|
+ height: {
|
|
|
+ type: Number,
|
|
|
+ value: systemInfo.windowHeight,
|
|
|
+ public: true,
|
|
|
+ observer: '_heightChanged'
|
|
|
+ },
|
|
|
+ width: {
|
|
|
+ type: Number,
|
|
|
+ value: systemInfo.windowWidth,
|
|
|
+ public: true,
|
|
|
+ observer: '_widthChanged'
|
|
|
+ },
|
|
|
+ // 距顶部/左边多远时,触发bindscrolltoupper
|
|
|
+ upperThreshold: {
|
|
|
+ type: Number,
|
|
|
+ value: 50,
|
|
|
+ public: true
|
|
|
+ },
|
|
|
+ // 距底部/右边多远时,触发bindscrolltolower
|
|
|
+ lowerThreshold: {
|
|
|
+ type: Number,
|
|
|
+ value: 50,
|
|
|
+ public: true
|
|
|
+ },
|
|
|
+ scrollToIndex: {
|
|
|
+ type: Number,
|
|
|
+ public: true,
|
|
|
+ value: 0,
|
|
|
+ observer: '_scrollToIndexChanged',
|
|
|
+ observeAssignments: true
|
|
|
+ },
|
|
|
+ scrollWithAnimation: {
|
|
|
+ type: Boolean,
|
|
|
+ public: true,
|
|
|
+ value: false
|
|
|
+ },
|
|
|
+ enableBackToTop: {
|
|
|
+ type: Boolean,
|
|
|
+ public: true,
|
|
|
+ value: false
|
|
|
+ },
|
|
|
+ // 是否节流,默认是
|
|
|
+ throttle: {
|
|
|
+ type: Boolean,
|
|
|
+ public: true,
|
|
|
+ value: true
|
|
|
+ },
|
|
|
+ placeholderImage: {
|
|
|
+ type: String,
|
|
|
+ public: true,
|
|
|
+ value: ''
|
|
|
+ },
|
|
|
+ screen: { // 默认渲染多少屏的数据
|
|
|
+ type: Number,
|
|
|
+ public: true,
|
|
|
+ value: DEFAULT_SHOW_SCREENS
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组件的初始数据
|
|
|
+ */
|
|
|
+ data: {
|
|
|
+ innerBeforeHeight: 0,
|
|
|
+ innerAfterHeight: 0,
|
|
|
+ innerScrollTop: 0,
|
|
|
+ innerScrollIntoView: '',
|
|
|
+ placeholderImageStr: '',
|
|
|
+ totalHeight: 0,
|
|
|
+ useInPage: false
|
|
|
+ },
|
|
|
+ attached: function attached() {
|
|
|
+ if (this.data.placeholderImage) {
|
|
|
+ this.setData({
|
|
|
+ placeholderImageStr: transformRpx(this.data.placeholderImage, true)
|
|
|
+ });
|
|
|
+ }
|
|
|
+ this.setItemSize({
|
|
|
+ array: [],
|
|
|
+ map: {},
|
|
|
+ totalHeight: 0
|
|
|
+ });
|
|
|
+ },
|
|
|
+ ready: function ready() {
|
|
|
+ var _this = this;
|
|
|
+
|
|
|
+ this._initPosition(function () {
|
|
|
+ _this._isReady = true; // DOM结构ready了
|
|
|
+ // 有一个更新的timer在了
|
|
|
+ if (_this._updateTimerId) return;
|
|
|
+
|
|
|
+ _this._scrollViewDidScroll({
|
|
|
+ detail: {
|
|
|
+ scrollLeft: _this._pos.left,
|
|
|
+ scrollTop: _this._pos.top,
|
|
|
+ ignoreScroll: true
|
|
|
+ }
|
|
|
+ }, true);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ detached: function detached() {
|
|
|
+ this.page = null;
|
|
|
+ // 销毁对应的RecycleContext
|
|
|
+ if (this.context) {
|
|
|
+ this.context.destroy();
|
|
|
+ this.context = null;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组件的方法列表
|
|
|
+ */
|
|
|
+ methods: {
|
|
|
+ _log: function _log() {
|
|
|
+ var _console;
|
|
|
+
|
|
|
+ if (!DEBUG && !this.data.debug) return;
|
|
|
+ var h = new Date();
|
|
|
+ var str = h.getHours() + ':' + h.getMinutes() + ':' + h.getSeconds() + '.' + h.getMilliseconds();
|
|
|
+
|
|
|
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
|
|
+ args[_key] = arguments[_key];
|
|
|
+ }
|
|
|
+
|
|
|
+ Array.prototype.splice.call(args, 0, 0, str);
|
|
|
+ // eslint-disable-next-line no-console
|
|
|
+ (_console = console).log.apply(_console, args);
|
|
|
+ },
|
|
|
+ _scrollToUpper: function _scrollToUpper(e) {
|
|
|
+ this.triggerEvent('scrolltoupper', e.detail);
|
|
|
+ },
|
|
|
+ _scrollToLower: function _scrollToLower(e) {
|
|
|
+ this.triggerEvent('scrolltolower', e.detail);
|
|
|
+ },
|
|
|
+ _beginToScroll: function _beginToScroll() {
|
|
|
+ if (!this._lastScrollTop) {
|
|
|
+ this._lastScrollTop = this._pos && (this._pos.top || 0);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ _clearList: function _clearList(cb) {
|
|
|
+ this.currentScrollTop = 0;
|
|
|
+ this._lastScrollTop = 0;
|
|
|
+ var pos = this._pos;
|
|
|
+ pos.beginIndex = this._pos.endIndex = -1;
|
|
|
+ pos.afterHeight = pos.minTop = pos.maxTop = 0;
|
|
|
+ this.page._recycleViewportChange({
|
|
|
+ detail: {
|
|
|
+ data: pos,
|
|
|
+ id: this.id
|
|
|
+ }
|
|
|
+ }, cb);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 判断RecycleContext是否Ready
|
|
|
+ _isValid: function _isValid() {
|
|
|
+ return this.page && this.context && this.context.isDataReady;
|
|
|
+ },
|
|
|
+
|
|
|
+ // eslint-disable-next-line no-complexity
|
|
|
+ _scrollViewDidScroll: function _scrollViewDidScroll(e, force) {
|
|
|
+ // 如果RecycleContext还没有初始化, 不做任何事情
|
|
|
+ if (!this._isValid()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 监测白屏时间
|
|
|
+ if (!e.detail.ignoreScroll) {
|
|
|
+ this.triggerEvent('scroll', e.detail);
|
|
|
+ }
|
|
|
+ this.currentScrollTop = e.detail.scrollTop;
|
|
|
+ // 高度为0的情况, 不做任何渲染逻辑
|
|
|
+ if (!this._pos.height || !this.sizeArray.length) {
|
|
|
+ // 没有任何数据的情况下, 直接清理所有的状态
|
|
|
+ this._clearList(e.detail.cb);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 在scrollWithAnimation动画最后会触发一次scroll事件, 这次scroll事件必须要被忽略
|
|
|
+ if (this._isScrollingWithAnimation) {
|
|
|
+ this._isScrollingWithAnimation = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var pos = this._pos;
|
|
|
+ var that = this;
|
|
|
+ var scrollLeft = e.detail.scrollLeft;
|
|
|
+ var scrollTop = e.detail.scrollTop;
|
|
|
+ var scrollDistance = Math.abs(scrollTop - this._lastScrollTop);
|
|
|
+ if (!force && Math.abs(scrollTop - pos.top) < pos.height * 1.5) {
|
|
|
+ this._log('【not exceed height');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this._lastScrollTop = scrollTop;
|
|
|
+ var SHOW_SCREENS = this.data.screen; // 固定4屏幕
|
|
|
+ this._log('SHOW_SCREENS', SHOW_SCREENS, scrollTop);
|
|
|
+ this._calcViewportIndexes(scrollLeft, scrollTop, function (beginIndex, endIndex, minTop, afterHeight, maxTop) {
|
|
|
+ that._log('scrollDistance', scrollDistance, 'indexes', beginIndex, endIndex);
|
|
|
+ // 渲染的数据不变
|
|
|
+ if (!force && pos.beginIndex === beginIndex && pos.endIndex === endIndex && pos.minTop === minTop && pos.afterHeight === afterHeight) {
|
|
|
+ that._log('------------is the same beginIndex and endIndex');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 如果这次渲染的范围比上一次的范围小,则忽略
|
|
|
+ that._log('【check】before setData, old pos is', pos.minTop, pos.maxTop, minTop, maxTop);
|
|
|
+ that._throttle = false;
|
|
|
+ pos.left = scrollLeft;
|
|
|
+ pos.top = scrollTop;
|
|
|
+ pos.beginIndex = beginIndex;
|
|
|
+ pos.endIndex = endIndex;
|
|
|
+ // console.log('render indexes', endIndex - beginIndex + 1, endIndex, beginIndex)
|
|
|
+ pos.minTop = minTop;
|
|
|
+ pos.maxTop = maxTop;
|
|
|
+ pos.afterHeight = afterHeight;
|
|
|
+ pos.ignoreBeginIndex = pos.ignoreEndIndex = -1;
|
|
|
+ that.page._recycleViewportChange({
|
|
|
+ detail: {
|
|
|
+ data: that._pos,
|
|
|
+ id: that.id
|
|
|
+ }
|
|
|
+ }, function () {
|
|
|
+ if (e.detail.cb) {
|
|
|
+ e.detail.cb();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 计算在视窗内渲染的数据
|
|
|
+ _calcViewportIndexes: function _calcViewportIndexes(left, top, cb) {
|
|
|
+ var that = this;
|
|
|
+ // const st = +new Date
|
|
|
+ this._getBeforeSlotHeight(function () {
|
|
|
+ var _that$__calcViewportI = that.__calcViewportIndexes(left, top),
|
|
|
+ beginIndex = _that$__calcViewportI.beginIndex,
|
|
|
+ endIndex = _that$__calcViewportI.endIndex,
|
|
|
+ minTop = _that$__calcViewportI.minTop,
|
|
|
+ afterHeight = _that$__calcViewportI.afterHeight,
|
|
|
+ maxTop = _that$__calcViewportI.maxTop;
|
|
|
+
|
|
|
+ if (cb) {
|
|
|
+ cb(beginIndex, endIndex, minTop, afterHeight, maxTop);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ _getBeforeSlotHeight: function _getBeforeSlotHeight(cb) {
|
|
|
+ if (typeof this.data.beforeSlotHeight !== 'undefined') {
|
|
|
+ if (cb) {
|
|
|
+ cb(this.data.beforeSlotHeight);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.reRender(cb);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ _getAfterSlotHeight: function _getAfterSlotHeight(cb) {
|
|
|
+ if (typeof this.data.afterSlotHeight !== 'undefined') {
|
|
|
+ if (cb) {
|
|
|
+ cb(this.data.afterSlotHeight);
|
|
|
+ }
|
|
|
+ // cb && cb(this.data.afterSlotHeight)
|
|
|
+ } else {
|
|
|
+ this.reRender(cb);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ _getIndexes: function _getIndexes(minTop, maxTop) {
|
|
|
+ if (minTop === maxTop && maxTop === 0) {
|
|
|
+ return {
|
|
|
+ beginIndex: -1,
|
|
|
+ endIndex: -1
|
|
|
+ };
|
|
|
+ }
|
|
|
+ var startLine = Math.floor(minTop / RECT_SIZE);
|
|
|
+ var endLine = Math.ceil(maxTop / RECT_SIZE);
|
|
|
+ var rectEachLine = Math.floor(this.data.width / RECT_SIZE);
|
|
|
+ var beginIndex = void 0;
|
|
|
+ var endIndex = void 0;
|
|
|
+ var sizeMap = this.sizeMap;
|
|
|
+ for (var i = startLine; i <= endLine; i++) {
|
|
|
+ for (var col = 0; col < rectEachLine; col++) {
|
|
|
+ var key = i + '.' + col;
|
|
|
+ // 找到sizeMap里面的最小值和最大值即可
|
|
|
+ if (!sizeMap[key]) continue;
|
|
|
+ for (var j = 0; j < sizeMap[key].length; j++) {
|
|
|
+ if (typeof beginIndex === 'undefined') {
|
|
|
+ beginIndex = endIndex = sizeMap[key][j];
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (beginIndex > sizeMap[key][j]) {
|
|
|
+ beginIndex = sizeMap[key][j];
|
|
|
+ } else if (endIndex < sizeMap[key][j]) {
|
|
|
+ endIndex = sizeMap[key][j];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ beginIndex: beginIndex,
|
|
|
+ endIndex: endIndex
|
|
|
+ };
|
|
|
+ },
|
|
|
+ _isIndexValid: function _isIndexValid(beginIndex, endIndex) {
|
|
|
+ if (typeof beginIndex === 'undefined' || beginIndex === -1 || typeof endIndex === 'undefined' || endIndex === -1 || endIndex >= this.sizeArray.length) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ },
|
|
|
+ __calcViewportIndexes: function __calcViewportIndexes(left, top) {
|
|
|
+ if (!this.sizeArray.length) return {};
|
|
|
+ var pos = this._pos;
|
|
|
+ if (typeof left === 'undefined') {
|
|
|
+ left = pos.left;
|
|
|
+ }
|
|
|
+ if (typeof top === 'undefined') {
|
|
|
+ top = pos.top;
|
|
|
+ }
|
|
|
+ // top = Math.max(top, this.data.beforeSlotHeight)
|
|
|
+ var beforeSlotHeight = this.data.beforeSlotHeight || 0;
|
|
|
+ // 和direction无关了
|
|
|
+ var SHOW_SCREENS = this.data.screen;
|
|
|
+ var minTop = top - pos.height * SHOW_SCREENS - beforeSlotHeight;
|
|
|
+ var maxTop = top + pos.height * SHOW_SCREENS - beforeSlotHeight;
|
|
|
+ // maxTop或者是minTop超出了范围
|
|
|
+ if (maxTop > this.totalHeight) {
|
|
|
+ minTop -= maxTop - this.totalHeight;
|
|
|
+ maxTop = this.totalHeight;
|
|
|
+ }
|
|
|
+ if (minTop < beforeSlotHeight) {
|
|
|
+ maxTop += Math.min(beforeSlotHeight - minTop, this.totalHeight);
|
|
|
+ minTop = 0;
|
|
|
+ }
|
|
|
+ // 计算落在minTop和maxTop之间的方格有哪些
|
|
|
+ var indexObj = this._getIndexes(minTop, maxTop);
|
|
|
+ var beginIndex = indexObj.beginIndex;
|
|
|
+ var endIndex = indexObj.endIndex;
|
|
|
+ if (endIndex >= this.sizeArray.length) {
|
|
|
+ endIndex = this.sizeArray.length - 1;
|
|
|
+ }
|
|
|
+ // 校验一下beginIndex和endIndex的有效性,
|
|
|
+ if (!this._isIndexValid(beginIndex, endIndex)) {
|
|
|
+ return {
|
|
|
+ beginIndex: -1,
|
|
|
+ endIndex: -1,
|
|
|
+ minTop: 0,
|
|
|
+ afterHeight: 0,
|
|
|
+ maxTop: 0
|
|
|
+ };
|
|
|
+ }
|
|
|
+ // 计算白屏的默认占位的区域
|
|
|
+ var maxTopFull = this.sizeArray[endIndex].beforeHeight + this.sizeArray[endIndex].height;
|
|
|
+ var minTopFull = this.sizeArray[beginIndex].beforeHeight;
|
|
|
+
|
|
|
+ // console.log('render indexes', beginIndex, endIndex)
|
|
|
+ var afterHeight = this.totalHeight - maxTopFull;
|
|
|
+ return {
|
|
|
+ beginIndex: beginIndex,
|
|
|
+ endIndex: endIndex,
|
|
|
+ minTop: minTopFull, // 取整, beforeHeight的距离
|
|
|
+ afterHeight: afterHeight,
|
|
|
+ maxTop: maxTop
|
|
|
+ };
|
|
|
+ },
|
|
|
+ setItemSize: function setItemSize(size) {
|
|
|
+ this.sizeArray = size.array;
|
|
|
+ this.sizeMap = size.map;
|
|
|
+ if (size.totalHeight !== this.totalHeight) {
|
|
|
+ // console.log('---totalHeight is', size.totalHeight);
|
|
|
+ this.setData({
|
|
|
+ totalHeight: size.totalHeight,
|
|
|
+ useInPage: this.useInPage || false
|
|
|
+ });
|
|
|
+ }
|
|
|
+ this.totalHeight = size.totalHeight;
|
|
|
+ },
|
|
|
+ setList: function setList(key, newList) {
|
|
|
+ this._currentSetDataKey = key;
|
|
|
+ this._currentSetDataList = newList;
|
|
|
+ },
|
|
|
+ setPage: function setPage(page) {
|
|
|
+ this.page = page;
|
|
|
+ },
|
|
|
+ forceUpdate: function forceUpdate(cb, reInit) {
|
|
|
+ var _this2 = this;
|
|
|
+
|
|
|
+ if (!this._isReady) {
|
|
|
+ if (this._updateTimerId) {
|
|
|
+ // 合并多次的forceUpdate
|
|
|
+ clearTimeout(this._updateTimerId);
|
|
|
+ }
|
|
|
+ this._updateTimerId = setTimeout(function () {
|
|
|
+ _this2.forceUpdate(cb, reInit);
|
|
|
+ }, 10);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this._updateTimerId = null;
|
|
|
+ var that = this;
|
|
|
+ if (reInit) {
|
|
|
+ this.reRender(function () {
|
|
|
+ that._scrollViewDidScroll({
|
|
|
+ detail: {
|
|
|
+ scrollLeft: that._pos.left,
|
|
|
+ scrollTop: that.currentScrollTop || that.data.scrollTop || 0,
|
|
|
+ ignoreScroll: true,
|
|
|
+ cb: cb
|
|
|
+ }
|
|
|
+ }, true);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this._scrollViewDidScroll({
|
|
|
+ detail: {
|
|
|
+ scrollLeft: that._pos.left,
|
|
|
+ scrollTop: that.currentScrollTop || that.data.scrollTop || 0,
|
|
|
+ ignoreScroll: true,
|
|
|
+ cb: cb
|
|
|
+ }
|
|
|
+ }, true);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ _initPosition: function _initPosition(cb) {
|
|
|
+ var that = this;
|
|
|
+ that._pos = {
|
|
|
+ left: that.data.scrollLeft || 0,
|
|
|
+ top: that.data.scrollTop || 0,
|
|
|
+ width: this.data.width,
|
|
|
+ height: Math.max(500, this.data.height), // 一个屏幕的高度
|
|
|
+ direction: 0
|
|
|
+ };
|
|
|
+ this.reRender(cb);
|
|
|
+ },
|
|
|
+ _widthChanged: function _widthChanged(newVal) {
|
|
|
+ if (!this._isReady) return newVal;
|
|
|
+ this._pos.width = newVal;
|
|
|
+ this.forceUpdate();
|
|
|
+ return newVal;
|
|
|
+ },
|
|
|
+ _heightChanged: function _heightChanged(newVal) {
|
|
|
+ if (!this._isReady) return newVal;
|
|
|
+ this._pos.height = Math.max(500, newVal);
|
|
|
+ this.forceUpdate();
|
|
|
+ return newVal;
|
|
|
+ },
|
|
|
+ reRender: function reRender(cb) {
|
|
|
+ var _this3 = this;
|
|
|
+
|
|
|
+ var beforeSlotHeight = void 0;
|
|
|
+ var afterSlotHeight = void 0;
|
|
|
+ var that = this;
|
|
|
+ // const reRenderStart = Date.now()
|
|
|
+ function newCb() {
|
|
|
+ if (that._lastBeforeSlotHeight !== beforeSlotHeight || that._lastAfterSlotHeight !== afterSlotHeight) {
|
|
|
+ that.setData({
|
|
|
+ hasBeforeSlotHeight: true,
|
|
|
+ hasAfterSlotHeight: true,
|
|
|
+ beforeSlotHeight: beforeSlotHeight,
|
|
|
+ afterSlotHeight: afterSlotHeight
|
|
|
+ });
|
|
|
+ }
|
|
|
+ that._lastBeforeSlotHeight = beforeSlotHeight;
|
|
|
+ that._lastAfterSlotHeight = afterSlotHeight;
|
|
|
+ // console.log('_getBeforeSlotHeight use time', Date.now() - reRenderStart)
|
|
|
+ if (cb) {
|
|
|
+ cb();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 重新渲染事件发生
|
|
|
+ var beforeReady = false;
|
|
|
+ var afterReady = false;
|
|
|
+ // fix:#16 确保获取slot节点实际高度
|
|
|
+ this.setData({
|
|
|
+ hasBeforeSlotHeight: false,
|
|
|
+ hasAfterSlotHeight: false
|
|
|
+ }, function () {
|
|
|
+ _this3.createSelectorQuery().select('.slot-before').boundingClientRect(function (rect) {
|
|
|
+ beforeSlotHeight = rect.height;
|
|
|
+ beforeReady = true;
|
|
|
+ if (afterReady) {
|
|
|
+ if (newCb) {
|
|
|
+ newCb();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).exec();
|
|
|
+ _this3.createSelectorQuery().select('.slot-after').boundingClientRect(function (rect) {
|
|
|
+ afterSlotHeight = rect.height;
|
|
|
+ afterReady = true;
|
|
|
+ if (beforeReady) {
|
|
|
+ if (newCb) {
|
|
|
+ newCb();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).exec();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ _setInnerBeforeAndAfterHeight: function _setInnerBeforeAndAfterHeight(obj) {
|
|
|
+ if (typeof obj.beforeHeight !== 'undefined') {
|
|
|
+ this._tmpBeforeHeight = obj.beforeHeight;
|
|
|
+ }
|
|
|
+ if (obj.afterHeight) {
|
|
|
+ this._tmpAfterHeight = obj.afterHeight;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ _recycleInnerBatchDataChanged: function _recycleInnerBatchDataChanged(cb) {
|
|
|
+ var _this4 = this;
|
|
|
+
|
|
|
+ if (typeof this._tmpBeforeHeight !== 'undefined') {
|
|
|
+ var setObj = {
|
|
|
+ innerBeforeHeight: this._tmpBeforeHeight || 0,
|
|
|
+ innerAfterHeight: this._tmpAfterHeight || 0
|
|
|
+ };
|
|
|
+ if (typeof this._tmpInnerScrollTop !== 'undefined') {
|
|
|
+ setObj.innerScrollTop = this._tmpInnerScrollTop;
|
|
|
+ }
|
|
|
+ var pageObj = {};
|
|
|
+ var hasPageData = false;
|
|
|
+ if (typeof this._currentSetDataKey !== 'undefined') {
|
|
|
+ pageObj[this._currentSetDataKey] = this._currentSetDataList;
|
|
|
+ hasPageData = true;
|
|
|
+ }
|
|
|
+ var saveScrollWithAnimation = this.data.scrollWithAnimation;
|
|
|
+ var groupSetData = function groupSetData() {
|
|
|
+ // 如果有分页数据的话
|
|
|
+ if (hasPageData) {
|
|
|
+ _this4.page.setData(pageObj);
|
|
|
+ }
|
|
|
+ _this4.setData(setObj, function () {
|
|
|
+ _this4.setData({
|
|
|
+ scrollWithAnimation: saveScrollWithAnimation
|
|
|
+ });
|
|
|
+ if (typeof cb === 'function') {
|
|
|
+ cb();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+ groupSetData();
|
|
|
+ delete this._currentSetDataKey;
|
|
|
+ delete this._currentSetDataList;
|
|
|
+ this._tmpBeforeHeight = undefined;
|
|
|
+ this._tmpAfterHeight = undefined;
|
|
|
+ this._tmpInnerScrollTop = undefined;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ _renderByScrollTop: function _renderByScrollTop(scrollTop) {
|
|
|
+ // 先setData把目标位置的数据补齐
|
|
|
+ this._scrollViewDidScroll({
|
|
|
+ detail: {
|
|
|
+ scrollLeft: this._pos.scrollLeft,
|
|
|
+ scrollTop: scrollTop,
|
|
|
+ ignoreScroll: true
|
|
|
+ }
|
|
|
+ }, true);
|
|
|
+ if (this.data.scrollWithAnimation) {
|
|
|
+ this._isScrollingWithAnimation = true;
|
|
|
+ }
|
|
|
+ this.setData({
|
|
|
+ innerScrollTop: scrollTop
|
|
|
+ });
|
|
|
+ },
|
|
|
+ _scrollTopChanged: function _scrollTopChanged(newVal, oldVal) {
|
|
|
+ var _this5 = this;
|
|
|
+
|
|
|
+ // if (newVal === oldVal && newVal === 0) return
|
|
|
+ if (!this._isInitScrollTop && newVal === 0) {
|
|
|
+ this._isInitScrollTop = true;
|
|
|
+ return newVal;
|
|
|
+ }
|
|
|
+ this.currentScrollTop = newVal;
|
|
|
+ if (!this._isReady) {
|
|
|
+ if (this._scrollTopTimerId) {
|
|
|
+ clearTimeout(this._scrollTopTimerId);
|
|
|
+ }
|
|
|
+ this._scrollTopTimerId = setTimeout(function () {
|
|
|
+ _this5._scrollTopChanged(newVal, oldVal);
|
|
|
+ }, 10);
|
|
|
+ return newVal;
|
|
|
+ }
|
|
|
+ this._isInitScrollTop = true;
|
|
|
+ this._scrollTopTimerId = null;
|
|
|
+ // this._lastScrollTop = oldVal
|
|
|
+ if (typeof this._lastScrollTop === 'undefined') {
|
|
|
+ this._lastScrollTop = this.data.scrollTop;
|
|
|
+ }
|
|
|
+ // 滑动距离小于一个屏幕的高度, 直接setData
|
|
|
+ if (Math.abs(newVal - this._lastScrollTop) < this._pos.height) {
|
|
|
+ this.setData({
|
|
|
+ innerScrollTop: newVal
|
|
|
+ });
|
|
|
+ return newVal;
|
|
|
+ }
|
|
|
+ if (!this._isScrollTopChanged) {
|
|
|
+ // 首次的值需要延后一点执行才能生效
|
|
|
+ setTimeout(function () {
|
|
|
+ _this5._isScrollTopChanged = true;
|
|
|
+ _this5._renderByScrollTop(newVal);
|
|
|
+ }, 10);
|
|
|
+ } else {
|
|
|
+ this._renderByScrollTop(newVal);
|
|
|
+ }
|
|
|
+ return newVal;
|
|
|
+ },
|
|
|
+ _scrollToIndexChanged: function _scrollToIndexChanged(newVal, oldVal) {
|
|
|
+ var _this6 = this;
|
|
|
+
|
|
|
+ // if (newVal === oldVal && newVal === 0) return
|
|
|
+ // 首次滚动到0的不执行
|
|
|
+ if (!this._isInitScrollToIndex && newVal === 0) {
|
|
|
+ this._isInitScrollToIndex = true;
|
|
|
+ return newVal;
|
|
|
+ }
|
|
|
+ if (!this._isReady) {
|
|
|
+ if (this._scrollToIndexTimerId) {
|
|
|
+ clearTimeout(this._scrollToIndexTimerId);
|
|
|
+ }
|
|
|
+ this._scrollToIndexTimerId = setTimeout(function () {
|
|
|
+ _this6._scrollToIndexChanged(newVal, oldVal);
|
|
|
+ }, 10);
|
|
|
+ return newVal;
|
|
|
+ }
|
|
|
+ this._isInitScrollToIndex = true;
|
|
|
+ this._scrollToIndexTimerId = null;
|
|
|
+ if (typeof this._lastScrollTop === 'undefined') {
|
|
|
+ this._lastScrollTop = this.data.scrollTop;
|
|
|
+ }
|
|
|
+ var rect = this.boundingClientRect(newVal);
|
|
|
+ if (!rect) return newVal;
|
|
|
+ // console.log('rect top', rect, this.data.beforeSlotHeight)
|
|
|
+ var calScrollTop = rect.top + (this.data.beforeSlotHeight || 0);
|
|
|
+ this.currentScrollTop = calScrollTop;
|
|
|
+ if (Math.abs(calScrollTop - this._lastScrollTop) < this._pos.height) {
|
|
|
+ this.setData({
|
|
|
+ innerScrollTop: calScrollTop
|
|
|
+ });
|
|
|
+ return newVal;
|
|
|
+ }
|
|
|
+ if (!this._isScrollToIndexChanged) {
|
|
|
+ setTimeout(function () {
|
|
|
+ _this6._isScrollToIndexChanged = true;
|
|
|
+ _this6._renderByScrollTop(calScrollTop);
|
|
|
+ }, 10);
|
|
|
+ } else {
|
|
|
+ this._renderByScrollTop(calScrollTop);
|
|
|
+ }
|
|
|
+ return newVal;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 提供给开发者使用的接口
|
|
|
+ boundingClientRect: function boundingClientRect(idx) {
|
|
|
+ if (idx < 0 || idx >= this.sizeArray.length) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ left: 0,
|
|
|
+ top: this.sizeArray[idx].beforeHeight,
|
|
|
+ width: this.sizeArray[idx].width,
|
|
|
+ height: this.sizeArray[idx].height
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取当前出现在屏幕内数据项, 返回数据项组成的数组
|
|
|
+ // 参数inViewportPx表示当数据项至少有多少像素出现在屏幕内才算是出现在屏幕内,默认是1
|
|
|
+ getIndexesInViewport: function getIndexesInViewport(inViewportPx) {
|
|
|
+ if (!inViewportPx) {
|
|
|
+ inViewportPx = 1;
|
|
|
+ }
|
|
|
+ var scrollTop = this.currentScrollTop;
|
|
|
+ var minTop = scrollTop + inViewportPx;
|
|
|
+ if (minTop < 0) minTop = 0;
|
|
|
+ var maxTop = scrollTop + this.data.height - inViewportPx;
|
|
|
+ if (maxTop > this.totalHeight) maxTop = this.totalHeight;
|
|
|
+ var indexes = [];
|
|
|
+ for (var i = 0; i < this.sizeArray.length; i++) {
|
|
|
+ if (this.sizeArray[i].beforeHeight + this.sizeArray[i].height >= minTop && this.sizeArray[i].beforeHeight <= maxTop) {
|
|
|
+ indexes.push(i);
|
|
|
+ }
|
|
|
+ if (this.sizeArray[i].beforeHeight > maxTop) break;
|
|
|
+ }
|
|
|
+ return indexes;
|
|
|
+ },
|
|
|
+ getTotalHeight: function getTotalHeight() {
|
|
|
+ return this.totalHeight;
|
|
|
+ },
|
|
|
+ setUseInPage: function setUseInPage(useInPage) {
|
|
|
+ this.useInPage = useInPage;
|
|
|
+ },
|
|
|
+ setPlaceholderImage: function setPlaceholderImage(svgs, size) {
|
|
|
+ var fill = 'style=\'fill:rgb(204,204,204);\'';
|
|
|
+ var placeholderImages = ['data:image/svg+xml,%3Csvg height=\'' + size.height + '\' width=\'' + size.width + '\' xmlns=\'http://www.w3.org/2000/svg\'%3E'];
|
|
|
+ svgs.forEach(function (svg) {
|
|
|
+ placeholderImages.push('%3Crect width=\'' + svg.width + '\' x=\'' + svg.left + '\' height=\'' + svg.height + '\' y=\'' + svg.top + '\' ' + fill + ' /%3E');
|
|
|
+ });
|
|
|
+ placeholderImages.push('%3C/svg%3E');
|
|
|
+ this.setData({
|
|
|
+ placeholderImageStr: placeholderImages.join('')
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+/***/ })
|
|
|
+
|
|
|
+/******/ });
|