├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── LICENSE ├── README.md ├── build ├── base.conf.js ├── build-demo.js ├── build.js ├── check-versions.js ├── demo.dev.conf.js ├── demo.prod.conf.js ├── utils.js ├── vue-loader.conf.js └── webpack.prod.conf.js ├── config ├── dev.env.js ├── index.js ├── prod.env.js └── test.env.js ├── demo ├── App.vue ├── assets │ └── demo.jpeg └── main.js ├── dist ├── css │ ├── vue-virtual-infinite-scroll.css │ └── vue-virtual-infinite-scroll.css.map └── vue-virtual-infinite-scroll.js ├── index.html ├── package.json ├── src ├── assets │ └── icon │ │ ├── iconfont.css │ │ ├── iconfont.eot │ │ ├── iconfont.js │ │ ├── iconfont.svg │ │ ├── iconfont.ttf │ │ └── iconfont.woff ├── component │ └── VirtualScroll.vue ├── index.js └── iscroll-probe.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-vue-jsx", "transform-runtime", "transform-decorators-legacy", "transform-class-properties"], 12 | "env": { 13 | "test": { 14 | "presets": ["env", "stage-2"], 15 | "plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ 4 | /*.js 5 | /test/unit/coverage/ 6 | /src/vendors/ 7 | /src/iscroll-probe.js 8 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md 13 | extends: 'standard', 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'html' 17 | ], 18 | // add your custom rules here 19 | rules: { 20 | // allow async-await 21 | 'generator-star-spacing': 'off', 22 | // allow debugger during development 23 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 24 | }, 25 | globals: { 26 | Vue: true 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log* 4 | yarn-debug.log* 5 | yarn-error.log* 6 | /test/* 7 | virtual-scroll/ 8 | 9 | # Editor directories and files 10 | .idea 11 | .vscode 12 | *.suo 13 | *.ntvs* 14 | *.njsproj 15 | *.sln 16 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | "postcss-import": {}, 7 | "postcss-cssnext": {}, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Lei Zuo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-virtual-infinite-scroll 2 | > a vue2 component based on Iscroll, supports big data list with high performance scroll, infinite load and pull refresh. 3 | 4 | * Based on Iscroll, support iscroll configure options 5 | 6 | * Reuse the DOM element to get high performance in big data list 7 | 8 | * Support fixed height and variable height. 9 | 10 | * Support bottom loadmore and pulldown refresh event 11 | 12 | ## Demo 13 | https://zuolei828.github.io/virtual-scroll/ 14 | 15 | uncheck the virtual scroll means a normal big data list not use our component. It is used for performance comparison. 16 | 17 | ## How to use 18 | 19 | ``` 20 | npm install vue-virtual-infinite-scroll --save 21 | ``` 22 | 23 | ``` 24 | import virtualScroll from 'vue-virtual-infinite-scroll' 25 | import 'vue-virtual-infinite-scroll/dist/css/vue-virtual-infinite-scroll.css' 26 | 27 | Vue.component('virtual-list', virtualScroll) 28 | ``` 29 | ```vue 30 | 31 | 32 | 33 | 34 | 35 | 36 | {{props.item.text}} 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 105 | 114 | ``` 115 | 116 | ### Notice 117 | 118 | 1. You should init the items array during your own component created function before the vue-virtual-infinite-scroll component created. 119 | 2. You should put the vue-virtual-infinite-scroll component during a parent component, and set a css position property(relative, absolute or fixed) to the parent component. 120 | 121 | ## Prop Configures 122 | 123 | *Prop* | *Type* | *Required* | *Default* | *Description* | 124 | :--- | :--- | :--- | :--- | :--- | 125 | | items | Array | ✓ | [] |The list expected to render, each item in the list should contain id arrtibute for the unique identify, and in variable height mode, it should also contain height attribute with a string or number value. eg: [{ id: 1, height: 40 }, { id:2, height: 50 }] | 126 | | uniqueKey | String | ✓ | 'id' | The unique key for each list item | 127 | | iscrollOptions | Object | * | {} | The iscroll configure options. http://iscrolljs.com/#configuring | 128 | | variable | Boolean | * | false | Define the height mode of list item. If false, the component will get the item height automatically. If true, you should set the 'height' property to each item in the prop 'items' | 129 | | bufferSize | Number | * | 5 | Define the top and bottom buffer item size. It is used to cache the scoll item out of the visable component area, the larger the bufferSize, the higher the scroll performance will achieved. | 130 | | infinite | Boolean | * | false | True means you want to use the loadMore function when the component scolled to the bottom | 131 | | distance | Number | * | 50 | The loadMore infinite function will be called when scrolled into the distance value from bottom | 132 | | loadMore | Function | * | | The custom function called when prop infinite is true and component scrolled into the distance value from bottom. It has a callback param which can controll the loader state(see the How to use) | 133 | | pulldown | Boolean | * | false | True means you want to use the pullRefresh function when the component pulled out of the top boundary | 134 | | pullRefresh | Function | * | | The custom function called when prop pulldown is true and the component pulled out the top boundary and released. It has a callback param which can controll the puller state(see the How to use) | 135 | | pulldownText | Object | * | { begin: '下拉刷新',trigger: '释放更新',refresh: '更新中...',complete: '更新完成',error:'更新失败'} | The custom text object used to show in pull refresh | 136 | 137 | ## Slot Configures 138 | 139 | *Slot* | *Description* | 140 | :--- | :--- | 141 | | content | each list item content 142 | | infiniteLoader | the bottom infinite loader -------------------------------------------------------------------------------- /build/base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | var webpack = require('webpack') 7 | 8 | function resolve (dir) { 9 | return path.join(__dirname, '..', dir) 10 | } 11 | 12 | const createLintingRule = () => ({ 13 | test: /\.(js|vue)$/, 14 | loader: 'eslint-loader', 15 | enforce: 'pre', 16 | include: [resolve('src'), resolve('test')], 17 | options: { 18 | formatter: require('eslint-friendly-formatter'), 19 | emitWarning: !config.dev.showEslintErrorsInOverlay 20 | } 21 | }) 22 | 23 | module.exports = { 24 | context: path.resolve(__dirname, '../'), 25 | resolve: { 26 | extensions: ['.js', '.vue', '.json'], 27 | alias: { 28 | 'vue$': 'vue/dist/vue.esm.js', 29 | '@': resolve('src'), 30 | } 31 | }, 32 | module: { 33 | rules: [ 34 | ...(config.dev.useEslint ? [createLintingRule()] : []), 35 | { 36 | test: /\.vue$/, 37 | loader: 'vue-loader', 38 | options: vueLoaderConfig 39 | }, 40 | { 41 | test: /\.js$/, 42 | loader: 'babel-loader', 43 | include: [resolve('src'), resolve('test'), resolve('demo')], 44 | exclude: [resolve('src/iscroll-probe.js')] 45 | }, 46 | { 47 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 48 | loader: 'url-loader', 49 | options: { 50 | limit: 10000, 51 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 52 | } 53 | }, 54 | { 55 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 56 | loader: 'url-loader', 57 | options: { 58 | limit: 10000, 59 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 60 | } 61 | }, 62 | { 63 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 64 | loader: 'url-loader', 65 | options: { 66 | limit: 10000, 67 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 68 | } 69 | } 70 | ] 71 | }, 72 | node: { 73 | // prevent webpack from injecting useless setImmediate polyfill because Vue 74 | // source contains it (although only uses it if it's native). 75 | setImmediate: false, 76 | // prevent webpack from injecting mocks to Node native modules 77 | // that does not make sense for the client 78 | dgram: 'empty', 79 | fs: 'empty', 80 | net: 'empty', 81 | tls: 'empty', 82 | child_process: 'empty' 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /build/build-demo.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./demo.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, (err, stats) => { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, // if you are using ts-loader, setting this to true will make tyescript errors show up during build 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, (err, stats) => { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, // if you are using ts-loader, setting this to true will make tyescript errors show up during build 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | 7 | function exec (cmd) { 8 | return require('child_process').execSync(cmd).toString().trim() 9 | } 10 | 11 | const versionRequirements = [ 12 | { 13 | name: 'node', 14 | currentVersion: semver.clean(process.version), 15 | versionRequirement: packageConfig.engines.node 16 | } 17 | ] 18 | 19 | if (shell.which('npm')) { 20 | versionRequirements.push({ 21 | name: 'npm', 22 | currentVersion: exec('npm --version'), 23 | versionRequirement: packageConfig.engines.npm 24 | }) 25 | } 26 | 27 | module.exports = function () { 28 | const warnings = [] 29 | 30 | for (let i = 0; i < versionRequirements.length; i++) { 31 | const mod = versionRequirements[i] 32 | 33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 34 | warnings.push(mod.name + ': ' + 35 | chalk.red(mod.currentVersion) + ' should be ' + 36 | chalk.green(mod.versionRequirement) 37 | ) 38 | } 39 | } 40 | 41 | if (warnings.length) { 42 | console.log('') 43 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 44 | console.log() 45 | 46 | for (let i = 0; i < warnings.length; i++) { 47 | const warning = warnings[i] 48 | console.log(' ' + warning) 49 | } 50 | 51 | console.log() 52 | process.exit(1) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /build/demo.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const baseWebpackConfig = require('./base.conf') 7 | const HtmlWebpackPlugin = require('html-webpack-plugin') 8 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 9 | const portfinder = require('portfinder') 10 | 11 | const HOST = process.env.HOST 12 | const PORT = process.env.PORT && Number(process.env.PORT) 13 | 14 | const devWebpackConfig = merge(baseWebpackConfig, { 15 | entry: { 16 | app: './demo/main.js' 17 | }, 18 | output: { 19 | path: config.build.assetsRoot, 20 | filename: '[name].js', 21 | publicPath: config.dev.assetsPublicPath 22 | }, 23 | module: { 24 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap}) 25 | }, 26 | // cheap-module-eval-source-map is faster for development 27 | devtool: config.dev.devtool, 28 | 29 | // these devServer options should be customized in /config/index.js 30 | devServer: { 31 | clientLogLevel: 'warning', 32 | historyApiFallback: true, 33 | hot: true, 34 | compress: true, 35 | host: HOST || config.dev.host, 36 | port: PORT || config.dev.port, 37 | open: config.dev.autoOpenBrowser, 38 | overlay: config.dev.errorOverlay 39 | ? { warnings: false, errors: true } 40 | : false, 41 | publicPath: config.dev.assetsPublicPath, 42 | proxy: config.dev.proxyTable, 43 | quiet: true, // necessary for FriendlyErrorsPlugin 44 | watchOptions: { 45 | poll: config.dev.poll, 46 | } 47 | }, 48 | plugins: [ 49 | new webpack.DefinePlugin({ 50 | 'process.env': require('../config/dev.env') 51 | }), 52 | new webpack.HotModuleReplacementPlugin(), 53 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. 54 | new webpack.NoEmitOnErrorsPlugin(), 55 | // https://github.com/ampedandwired/html-webpack-plugin 56 | new HtmlWebpackPlugin({ 57 | filename: 'index.html', 58 | template: 'index.html', 59 | inject: true 60 | }), 61 | ] 62 | }) 63 | 64 | module.exports = new Promise((resolve, reject) => { 65 | portfinder.basePort = process.env.PORT || config.dev.port 66 | portfinder.getPort((err, port) => { 67 | if (err) { 68 | reject(err) 69 | } else { 70 | // publish the new Port, necessary for e2e tests 71 | process.env.PORT = port 72 | // add port to devServer config 73 | devWebpackConfig.devServer.port = port 74 | 75 | // Add FriendlyErrorsPlugin 76 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ 77 | compilationSuccessInfo: { 78 | messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], 79 | }, 80 | onErrors: config.dev.notifyOnErrors 81 | ? utils.createNotifierCallback() 82 | : undefined 83 | })) 84 | 85 | resolve(devWebpackConfig) 86 | } 87 | }) 88 | }) 89 | -------------------------------------------------------------------------------- /build/demo.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var utils = require('./utils') 3 | var webpack = require('webpack') 4 | var config = require('../config') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./base.conf') 7 | var CopyWebpackPlugin = require('copy-webpack-plugin') 8 | var HtmlWebpackPlugin = require('html-webpack-plugin') 9 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 10 | var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 11 | 12 | var env = process.env.NODE_ENV === 'testing' 13 | ? require('../config/test.env') 14 | : config.build.env 15 | 16 | var webpackConfig = merge(baseWebpackConfig, { 17 | module: { 18 | rules: utils.styleLoaders({ 19 | sourceMap: config.build.productionSourceMap, 20 | extract: true 21 | }) 22 | }, 23 | devtool: config.build.productionSourceMap ? '#source-map' : false, 24 | entry: { 25 | app: './demo/main.js' 26 | }, 27 | output: { 28 | path: config.build.assetsRoot, 29 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 30 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 31 | }, 32 | plugins: [ 33 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 34 | new webpack.DefinePlugin({ 35 | 'process.env': env 36 | }), 37 | new webpack.optimize.UglifyJsPlugin({ 38 | compress: { 39 | warnings: false 40 | }, 41 | sourceMap: true 42 | }), 43 | // extract css into its own file 44 | new ExtractTextPlugin({ 45 | filename: utils.assetsPath('css/[name].[contenthash].css') 46 | }), 47 | // Compress extracted CSS. We are using this plugin so that possible 48 | // duplicated CSS from different components can be deduped. 49 | new OptimizeCSSPlugin({ 50 | cssProcessorOptions: { 51 | safe: true 52 | } 53 | }), 54 | // generate dist index.html with correct asset hash for caching. 55 | // you can customize output by editing /index.html 56 | // see https://github.com/ampedandwired/html-webpack-plugin 57 | new HtmlWebpackPlugin({ 58 | filename: process.env.NODE_ENV === 'testing' 59 | ? 'index.html' 60 | : config.build.index, 61 | template: './index.html', 62 | inject: true, 63 | minify: { 64 | removeComments: true, 65 | collapseWhitespace: true, 66 | removeAttributeQuotes: true 67 | // more options: 68 | // https://github.com/kangax/html-minifier#options-quick-reference 69 | }, 70 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 71 | chunksSortMode: 'dependency' 72 | }), 73 | // split vendor js into its own file 74 | new webpack.optimize.CommonsChunkPlugin({ 75 | name: 'vendor', 76 | minChunks: function (module, count) { 77 | // any required modules inside node_modules are extracted to vendor 78 | return ( 79 | module.resource && 80 | /\.js$/.test(module.resource) && 81 | module.resource.indexOf( 82 | path.join(__dirname, '../../node_modules') 83 | ) === 0 84 | ) 85 | } 86 | }), 87 | // extract webpack runtime and module manifest to its own file in order to 88 | // prevent vendor hash from being updated whenever app bundle is updated 89 | new webpack.optimize.CommonsChunkPlugin({ 90 | name: 'manifest', 91 | chunks: ['vendor'] 92 | }), 93 | // copy custom static assets 94 | new CopyWebpackPlugin([ 95 | { 96 | from: path.resolve(__dirname, '../static'), 97 | to: config.build.assetsSubDirectory, 98 | ignore: ['.*'] 99 | } 100 | ]) 101 | ] 102 | }) 103 | 104 | if (config.build.productionGzip) { 105 | var CompressionWebpackPlugin = require('compression-webpack-plugin') 106 | 107 | webpackConfig.plugins.push( 108 | new CompressionWebpackPlugin({ 109 | asset: '[path].gz[query]', 110 | algorithm: 'gzip', 111 | test: new RegExp( 112 | '\\.(' + 113 | config.build.productionGzipExtensions.join('|') + 114 | ')$' 115 | ), 116 | threshold: 10240, 117 | minRatio: 0.8 118 | }) 119 | ) 120 | } 121 | 122 | if (config.build.bundleAnalyzerReport) { 123 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 124 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 125 | } 126 | 127 | module.exports = webpackConfig 128 | -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const config = require('../config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | const packageConfig = require('../package.json') 6 | 7 | exports.assetsPath = function (_path) { 8 | const assetsSubDirectory = process.env.NODE_ENV === 'production' 9 | ? config.build.assetsSubDirectory 10 | : config.dev.assetsSubDirectory 11 | 12 | return path.posix.join(assetsSubDirectory, _path) 13 | } 14 | 15 | exports.cssLoaders = function (options) { 16 | options = options || {} 17 | 18 | const cssLoader = { 19 | loader: 'css-loader', 20 | options: { 21 | sourceMap: options.sourceMap 22 | } 23 | } 24 | 25 | const postcssLoader = { 26 | loader: 'postcss-loader', 27 | options: { 28 | sourceMap: options.sourceMap 29 | } 30 | } 31 | 32 | // generate loader string to be used with extract text plugin 33 | function generateLoaders (loader, loaderOptions) { 34 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] 35 | 36 | if (loader) { 37 | loaders.push({ 38 | loader: loader + '-loader', 39 | options: Object.assign({}, loaderOptions, { 40 | sourceMap: options.sourceMap 41 | }) 42 | }) 43 | } 44 | 45 | // Extract CSS when that option is specified 46 | // (which is the case during production build) 47 | if (options.extract) { 48 | return ExtractTextPlugin.extract({ 49 | use: loaders, 50 | fallback: 'vue-style-loader' 51 | }) 52 | } else { 53 | return ['vue-style-loader'].concat(loaders) 54 | } 55 | } 56 | 57 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 58 | return { 59 | css: generateLoaders(), 60 | postcss: generateLoaders(), 61 | less: generateLoaders('less'), 62 | sass: generateLoaders('sass', { indentedSyntax: true }), 63 | scss: generateLoaders('sass'), 64 | stylus: generateLoaders('stylus'), 65 | styl: generateLoaders('stylus') 66 | } 67 | } 68 | 69 | // Generate loaders for standalone style files (outside of .vue) 70 | exports.styleLoaders = function (options) { 71 | const output = [] 72 | const loaders = exports.cssLoaders(options) 73 | 74 | for (const extension in loaders) { 75 | const loader = loaders[extension] 76 | output.push({ 77 | test: new RegExp('\\.' + extension + '$'), 78 | use: loader 79 | }) 80 | } 81 | 82 | return output 83 | } 84 | 85 | exports.createNotifierCallback = () => { 86 | const notifier = require('node-notifier') 87 | 88 | return (severity, errors) => { 89 | if (severity !== 'error') return 90 | 91 | const error = errors[0] 92 | const filename = error.file && error.file.split('!').pop() 93 | 94 | notifier.notify({ 95 | title: packageConfig.name, 96 | message: severity + ': ' + error.name, 97 | subtitle: filename || '', 98 | icon: path.join(__dirname, 'logo.png') 99 | }) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | module.exports = { 10 | loaders: utils.cssLoaders({ 11 | sourceMap: sourceMapEnabled, 12 | extract: isProduction 13 | }), 14 | cssSourceMap: sourceMapEnabled, 15 | cacheBusting: config.dev.cacheBusting, 16 | transformToRequire: { 17 | video: ['src', 'poster'], 18 | source: 'src', 19 | img: 'src', 20 | image: 'xlink:href' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const webpack = require('webpack') 5 | const config = require('../config') 6 | const merge = require('webpack-merge') 7 | const baseWebpackConfig = require('./base.conf') 8 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin') 9 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 10 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 11 | 12 | const env = process.env.NODE_ENV === 'testing' 13 | ? require('../config/test.env') 14 | : require('../config/prod.env') 15 | 16 | const webpackConfig = merge(baseWebpackConfig, { 17 | entry: { 18 | 'vue-virtual-infinite-scroll': './src/index.js' 19 | }, 20 | module: { 21 | rules: utils.styleLoaders({ 22 | sourceMap: config.build.productionSourceMap, 23 | extract: true 24 | }) 25 | }, 26 | output: { 27 | path: path.join(__dirname, '../dist'), 28 | filename: '[name].js', 29 | publicPath: '/', 30 | library: 'VueVirtualInfiniteScroll', 31 | libraryTarget: 'umd' 32 | }, 33 | devtool: config.build.productionSourceMap ? config.build.devtool : false, 34 | plugins: [ 35 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 36 | new webpack.DefinePlugin({ 37 | 'process.env': env 38 | }), 39 | new UglifyJsPlugin({ 40 | uglifyOptions: { 41 | compress: { 42 | warnings: false 43 | } 44 | }, 45 | sourceMap: config.build.productionSourceMap, 46 | parallel: true 47 | }), 48 | // enable scope hoisting 49 | new webpack.optimize.ModuleConcatenationPlugin(), 50 | // extract css into its own file 51 | new ExtractTextPlugin({ 52 | filename: 'css/[name].css', 53 | // Setting the following option to `false` will not extract CSS from codesplit chunks. 54 | // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack. 55 | // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, 56 | // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110 57 | allChunks: true, 58 | }), 59 | // Compress extracted CSS. We are using this plugin so that possible 60 | // duplicated CSS from different components can be deduped. 61 | new OptimizeCSSPlugin({ 62 | cssProcessorOptions: config.build.productionSourceMap 63 | ? { safe: true, map: { inline: false } } 64 | : { safe: true } 65 | }) 66 | ] 67 | }) 68 | 69 | if (config.build.productionGzip) { 70 | const CompressionWebpackPlugin = require('compression-webpack-plugin') 71 | 72 | webpackConfig.plugins.push( 73 | new CompressionWebpackPlugin({ 74 | asset: '[path].gz[query]', 75 | algorithm: 'gzip', 76 | test: new RegExp( 77 | '\\.(' + 78 | config.build.productionGzipExtensions.join('|') + 79 | ')$' 80 | ), 81 | threshold: 10240, 82 | minRatio: 0.8 83 | }) 84 | ) 85 | } 86 | 87 | if (config.build.bundleAnalyzerReport) { 88 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 89 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 90 | } 91 | 92 | module.exports = webpackConfig 93 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.2.7 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'demo.scroll.com', // can be overwritten by process.env.HOST 17 | port: 8880, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | // Use Eslint Loader? 24 | // If true, your code will be linted during bundling and 25 | // linting errors and warnings will be shown in the console. 26 | useEslint: true, 27 | // If true, eslint errors and warnings will also be shown in the error overlay 28 | // in the browser. 29 | showEslintErrorsInOverlay: false, 30 | 31 | /** 32 | * Source Maps 33 | */ 34 | 35 | // https://webpack.js.org/configuration/devtool/#development 36 | devtool: 'eval-source-map', 37 | 38 | // If you have problems debugging vue-files in devtools, 39 | // set this to false - it *may* help 40 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 41 | cacheBusting: true, 42 | 43 | // CSS Sourcemaps off by default because relative paths are "buggy" 44 | // with this option, according to the CSS-Loader README 45 | // (https://github.com/webpack/css-loader#sourcemaps) 46 | // In our experience, they generally work as expected, 47 | // just be aware of this issue when enabling this option. 48 | cssSourceMap: false, 49 | }, 50 | 51 | build: { 52 | env: require('./prod.env'), 53 | index: path.resolve(__dirname, '../virtual-scroll/index.html'), 54 | assetsRoot: path.resolve(__dirname, '../virtual-scroll/'), 55 | assetsSubDirectory: 'static', 56 | assetsPublicPath: '/virtual-scroll/', 57 | productionSourceMap: true, 58 | // Gzip off by default as many popular static hosts such as 59 | // Surge or Netlify already gzip all static assets for you. 60 | // Before setting to `true`, make sure to: 61 | // npm install --save-dev compression-webpack-plugin 62 | productionGzip: false, 63 | productionGzipExtensions: ['js', 'css'], 64 | // Run the build command with an extra argument to 65 | // View the bundle analyzer report after build finishes: 66 | // `npm run build --report` 67 | // Set to `true` or `false` to always turn it on or off 68 | bundleAnalyzerReport: process.env.npm_config_report 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /config/test.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const devEnv = require('./dev.env') 4 | 5 | module.exports = merge(devEnv, { 6 | NODE_ENV: '"testing"' 7 | }) 8 | -------------------------------------------------------------------------------- /demo/App.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | variable height 7 | 8 | 9 | 10 | virtual scroll 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {{props.item.text}} 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | {{item.text}} 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 147 | 148 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /demo/assets/demo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zuolei828/vue-virtual-infinite-scroll/f40f50a6be95f1bda407b3997bb00e8d5618a9d8/demo/assets/demo.jpeg -------------------------------------------------------------------------------- /demo/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VirtualScroll from '../src' 3 | import App from './App.vue' 4 | 5 | Vue.component('virtual-list', VirtualScroll) 6 | 7 | /* eslint-disable no-new */ 8 | new Vue({ 9 | el: '#app', 10 | render: h => h(App) 11 | }) 12 | -------------------------------------------------------------------------------- /dist/css/vue-virtual-infinite-scroll.css: -------------------------------------------------------------------------------- 1 | #wrapper{position:absolute;top:0;bottom:0;left:0;width:100%;z-index:1;overflow:hidden}#wrapper .refresh-loader{text-align:center;padding:5px 0}#wrapper .refresh-loader i{font-size:20px;color:#999;vertical-align:middle}#wrapper .refresh-loader .icon-pulldown{transition:transform .3s;transform:rotate(180deg);display:inline-block}#wrapper .refresh-loader .icon-pullup{transform:rotate(0deg);transition:transform .3s}#wrapper .refresh-loader .icon-complete,#wrapper .refresh-loader .icon-error{font-size:23px}#wrapper .refresh-loader .text-default{vertical-align:middle;color:#999;font-size:14px}#wrapper .scroll-list{list-style:none;margin:0;padding:0}#wrapper .scroll-list .list-item{position:absolute;left:0;top:0;width:100%}#wrapper .infinite-loader{position:absolute;width:100%;z-index:10000;text-align:center;padding:5px 0}#wrapper .infinite-loader .text-default{vertical-align:middle;font-size:14px;color:#999}#wrapper .spinner-default{display:inline-block;width:18px;height:18px;line-height:28px;border-radius:50%;vertical-align:middle;position:relative;border:1px solid #999;animation:loading-rotating ease 1.5s infinite}#wrapper .spinner-default:before{content:"";width:6px;height:6px;position:absolute;display:block;top:0;left:50%;margin-top:-3px;margin-left:-3px;background-color:#999;border-radius:50%}@keyframes loading-rotating{0%{transform:rotate(0)}to{transform:rotate(1turn)}}@font-face{font-family:iconfont;src:url(data:application/vnd.ms-fontobject;base64,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);src:url(data:application/vnd.ms-fontobject;base64,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#iefix) format("embedded-opentype"),url("data:application/x-font-woff;charset=utf-8;base64,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") format("woff"),url(data:application/x-font-ttf;base64,AAEAAAALAIAAAwAwR1NVQrD+s+0AAAE4AAAAQk9TLzJW7kkUAAABfAAAAFZjbWFwBETUNAAAAegAAAGyZ2x5ZrJ6zOcAAAOoAAACIGhlYWQRgK49AAAA4AAAADZoaGVhB94DhgAAALwAAAAkaG10eBPpAAAAAAHUAAAAFGxvY2EBQAGsAAADnAAAAAxtYXhwARQAXQAAARgAAAAgbmFtZT5U/n0AAAXIAAACbXBvc3TQUZmjAAAIOAAAAEsAAQAAA4D/gABcBAAAAAAABAAAAQAAAAAAAAAAAAAAAAAAAAUAAQAAAAEAAGRmTJFfDzz1AAsEAAAAAADXMLUjAAAAANcwtSMAAP+sBAADTgAAAAgAAgAAAAAAAAABAAAABQBRAAUAAAAAAAIAAAAKAAoAAAD/AAAAAAAAAAEAAAAKAB4ALAABREZMVAAIAAQAAAAAAAAAAQAAAAFsaWdhAAgAAAABAAAAAQAEAAQAAAABAAgAAQAGAAAAAQAAAAAAAQP7AZAABQAIAokCzAAAAI8CiQLMAAAB6wAyAQgAAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZABAAHjnJwOA/4AAXAOAAIAAAAABAAAAAAAABAAAAAPpAAAEAAAABAAAAAQAAAAAAAAFAAAAAwAAACwAAAAEAAABcgABAAAAAABsAAMAAQAAACwAAwAKAAABcgAEAEAAAAAKAAgAAgACAHjmSuaI5yf//wAAAHjmSuaI5yf//wAAAAAAAAAAAAEACgAKAAoACgAAAAEAAwAEAAIAAAEGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAEAAAAAAAAAABAAAAHgAAAB4AAAAAQAA5koAAOZKAAAAAwAA5ogAAOaIAAAABAAA5ycAAOcnAAAAAgAAAAAAAAB2AJwAygEQAAUAAP/hA7wDGAATACgAMQBEAFAAAAEGKwEiDgIdASEnNC4CKwEVIQUVFxQOAycjJyEHIyIuAz0BFyIGFBYyNjQmFwYHBg8BDgEeATMhMjYnLgInATU0PgI7ATIWHQEBGRsaUxIlHBIDkAEKGCcehf5KAqIBFR8jHA8+Lf5JLD8UMiATCHcMEhIZEhKMCAYFBQgCAgQPDgFtFxYJBQkKBv6kBQ8aFbwfKQIfAQwZJxpMWQ0gGxJhiDRuHSUXCQEBgIABExsgDqc/ERoRERoRfBoWExIZBxANCBgaDSMkFAF35AsYEwwdJuMAAAAAAwAA/9UDqwMrAAsADwATAAABDgEHHgEXPgE3LgEDIzUzNSMRMwIAtfEFBfG1tfEFBfGKVlZWVgMrBfG1tfEFBfG1tfH9hVVVAQAAAAEAAP+sA3EDTgAYAAAJASYiBwEGFBYyNwERFBYyNjURARYyNz4BA2r+nAcRCP6dBw8RBwE9DRMNATYIEQcMAgHdAWkICP6QBxEPBwFK/MMKDAwKAzf+wwcHCBMAAwAA/8IDtwMzAAsAFwApAAAFLgEnPgE3HgEXDgEDDgEHHgEXPgE3LgETBzEGIi8BJjQ2Mh8BNzYyFhQCAbv3BQX3u7r3BQX3vZ3RBATRnZ3RBATRLtAKHgqKChQdCnK4Ch0UPQT5u7r5BAT5urv5AycE0p2e0QQE0Z6d0v7Q0goKjAodFApzuQoTHgAAABIA3gABAAAAAAAAABUAAAABAAAAAAABAAgAFQABAAAAAAACAAcAHQABAAAAAAADAAgAJAABAAAAAAAEAAgALAABAAAAAAAFAAsANAABAAAAAAAGAAgAPwABAAAAAAAKACsARwABAAAAAAALABMAcgADAAEECQAAACoAhQADAAEECQABABAArwADAAEECQACAA4AvwADAAEECQADABAAzQADAAEECQAEABAA3QADAAEECQAFABYA7QADAAEECQAGABABAwADAAEECQAKAFYBEwADAAEECQALACYBaQpDcmVhdGVkIGJ5IGljb25mb250Cmljb25mb250UmVndWxhcmljb25mb250aWNvbmZvbnRWZXJzaW9uIDEuMGljb25mb250R2VuZXJhdGVkIGJ5IHN2ZzJ0dGYgZnJvbSBGb250ZWxsbyBwcm9qZWN0Lmh0dHA6Ly9mb250ZWxsby5jb20ACgBDAHIAZQBhAHQAZQBkACAAYgB5ACAAaQBjAG8AbgBmAG8AbgB0AAoAaQBjAG8AbgBmAG8AbgB0AFIAZQBnAHUAbABhAHIAaQBjAG8AbgBmAG8AbgB0AGkAYwBvAG4AZgBvAG4AdABWAGUAcgBzAGkAbwBuACAAMQAuADAAaQBjAG8AbgBmAG8AbgB0AEcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAAcwB2AGcAMgB0AHQAZgAgAGYAcgBvAG0AIABGAG8AbgB0AGUAbABsAG8AIABwAHIAbwBqAGUAYwB0AC4AaAB0AHQAcAA6AC8ALwBmAG8AbgB0AGUAbABsAG8ALgBjAG8AbQAAAAACAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUBAgEDAQQBBQEGAAF4BWVycm9yCHNoYW5nZmFuCnlpd2FuY2hlbmcAAAA=) format("truetype"),url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiID4KPCEtLQoyMDEzLTktMzA6IENyZWF0ZWQuCi0tPgo8c3ZnPgo8bWV0YWRhdGE+CkNyZWF0ZWQgYnkgaWNvbmZvbnQKPC9tZXRhZGF0YT4KPGRlZnM+Cgo8Zm9udCBpZD0iaWNvbmZvbnQiIGhvcml6LWFkdi14PSIxMDI0IiA+CiAgPGZvbnQtZmFjZQogICAgZm9udC1mYW1pbHk9Imljb25mb250IgogICAgZm9udC13ZWlnaHQ9IjUwMCIKICAgIGZvbnQtc3RyZXRjaD0ibm9ybWFsIgogICAgdW5pdHMtcGVyLWVtPSIxMDI0IgogICAgYXNjZW50PSI4OTYiCiAgICBkZXNjZW50PSItMTI4IgogIC8+CiAgICA8bWlzc2luZy1nbHlwaCAvPgogICAgCiAgICA8Z2x5cGggZ2x5cGgtbmFtZT0ieCIgdW5pY29kZT0ieCIgaG9yaXotYWR2LXg9IjEwMDEiCmQ9Ik0yODEgNTQzcS0yNyAtMSAtNTMgLTFoLTgzcS0xOCAwIC0zNi41IC02dC0zMi41IC0xOC41dC0yMyAtMzJ0LTkgLTQ1LjV2LTc2aDkxMnY0MXEwIDE2IC0wLjUgMzB0LTAuNSAxOHEwIDEzIC01IDI5dC0xNyAyOS41dC0zMS41IDIyLjV0LTQ5LjUgOWgtMTMzdi05N2gtNDM4djk3ek05NTUgMzEwdi01MnEwIC0yMyAwLjUgLTUydDAuNSAtNTh0LTEwLjUgLTQ3LjV0LTI2IC0zMHQtMzMgLTE2dC0zMS41IC00LjVxLTE0IC0xIC0yOS41IC0wLjUKdC0yOS41IDAuNWgtMzJsLTQ1IDEyOGgtNDM5bC00NCAtMTI4aC0yOWgtMzRxLTIwIDAgLTQ1IDFxLTI1IDAgLTQxIDkuNXQtMjUuNSAyM3QtMTMuNSAyOS41dC00IDMwdjE2N2g5MTF6TTE2MyAyNDdxLTEyIDAgLTIxIC04LjV0LTkgLTIxLjV0OSAtMjEuNXQyMSAtOC41cTEzIDAgMjIgOC41dDkgMjEuNXQtOSAyMS41dC0yMiA4LjV6TTMxNiAxMjNxLTggLTI2IC0xNCAtNDhxLTUgLTE5IC0xMC41IC0zN3QtNy41IC0yNXQtMyAtMTV0MSAtMTQuNQp0OS41IC0xMC41dDIxLjUgLTRoMzdoNjdoODFoODBoNjRoMzZxMjMgMCAzNCAxMnQyIDM4cS01IDEzIC05LjUgMzAuNXQtOS41IDM0LjVxLTUgMTkgLTExIDM5aC0zNjh6TTMzNiA0OTh2MjI4cTAgMTEgMi41IDIzdDEwIDIxLjV0MjAuNSAxNS41dDM0IDZoMTg4cTMxIDAgNTEuNSAtMTQuNXQyMC41IC01Mi41di0yMjdoLTMyN3oiIC8+CiAgICAKCiAgICAKICAgIDxnbHlwaCBnbHlwaC1uYW1lPSJlcnJvciIgdW5pY29kZT0iJiM1OTE3NTsiIGQ9Ik01MTIgODEwLjY2NjY2N2MtMjM1LjUyIDAtNDI2LjY2NjY2Ny0xOTAuOTMzMzMzLTQyNi42NjY2NjctNDI2LjY2NjY2N3MxOTEuMTQ2NjY3LTQyNi42NjY2NjcgNDI2LjY2NjY2Ny00MjYuNjY2NjY3IDQyNi42NjY2NjcgMTkwLjkzMzMzMyA0MjYuNjY2NjY3IDQyNi42NjY2NjctMTkxLjE0NjY2NyA0MjYuNjY2NjY3LTQyNi42NjY2NjcgNDI2LjY2NjY2N3pNNTU0LjY2NjY2NyAxNzAuNjY2NjY3bC04NS4zMzMzMzMgMCAwIDg1LjMzMzMzMyA4NS4zMzMzMzMgMCAwLTg1LjMzMzMzM3pNNTU0LjY2NjY2NyAzNDEuMzMzMzMzbC04NS4zMzMzMzMgMCAwIDI1NiA4NS4zMzMzMzMgMCAwLTI1NnoiICBob3Jpei1hZHYteD0iMTAyNCIgLz4KCiAgICAKICAgIDxnbHlwaCBnbHlwaC1uYW1lPSJzaGFuZ2ZhbiIgdW5pY29kZT0iJiM1ODk1NDsiIGQ9Ik04NzMuNiA0NzYuOGwtMzU1LjIgMzYxLjZjLTkuNiA5LjYtMjIuNCA5LjYtMzIgMGwtMzU1LjItMzY4Yy05LjYtOS42LTkuNi0yMi40IDAtMzIgOS42LTkuNiAyMi40LTkuNiAzMiAwbDMxNi44IDMyOS42IDAtODI4LjhjMC0xMi44IDkuNi0yMi40IDIyLjQtMjIuNHMyMi40IDkuNiAyMi40IDIyLjRsMCA4MjIuNCAzMTAuNC0zMTYuOGM5LjYtOS42IDIyLjQtOS42IDMyIDBDODgzLjIgNDU0LjQgODgzLjIgNDcwLjQgODczLjYgNDc2Ljh6IiAgaG9yaXotYWR2LXg9IjEwMjQiIC8+CgogICAgCiAgICA8Z2x5cGggZ2x5cGgtbmFtZT0ieWl3YW5jaGVuZyIgdW5pY29kZT0iJiM1OTAxNjsiIGQ9Ik01MTIuNTQ0LTYxLjI2M2MtMjQyLjA3NCAwLTQzOC4zMDQgMTk2LjkwNC00MzguMzA0IDQzOS44MDRTMjcwLjQ2OSA4MTguMzQgNTEyLjU0NCA4MTguMzRjMjQyLjA2NCAwIDQzOC4zMDQtMTk2LjkgNDM4LjMwNC00MzkuNzk5Uzc1NC42MDgtNjEuMjYzIDUxMi41NDQtNjEuMjYzek01MTAuMTc0IDc0OS45M2MtMjA0LjMwOSAwLTM2OS45MDktMTY2LjE3Ny0zNjkuOTA5LTM3MS4xNzkgMC0yMDQuOTk1IDE2NS42LTM3MS4xNzkgMzY5LjkwOS0zNzEuMTc5IDIwNC4yNzUgMCAzNjkuODk5IDE2Ni4xODUgMzY5Ljg5OSAzNzEuMTc5Qzg4MC4wNzMgNTgzLjc1MyA3MTQuNDQ4IDc0OS45MyA1MTAuMTc0IDc0OS45M3pNNzEzLjE0OCA0NDIuMDk2IDUwNC41MjkgMjMyLjIzN2wwIDAuMDJjLTYuMzEtNi4zNDUtMTQuOTg3LTEwLjI0NS0yNC42MjUtMTAuMjQ1LTkuNiAwLTE4LjMxNSAzLjk0LTI0LjYwNSAxMC4yNDVsLTEzOC42MDUgMTM5LjU5Yy02LjI4NyA2LjMtMTAuMTY3IDE1LjAwNS0xMC4xNjcgMjQuNjIgMCAxOS4zIDE1LjU5MiAzNC45MTUgMzQuNzcgMzQuOTE1IDkuNjIyIDAgMTguMzItMy45MiAyNC42MjctMTAuMjVsMTEzLjk4LTExNC44MTUgMTg0LjAyIDE4NS4wOTJjNi4yOTUgNi4zMjUgMTUuMDI1IDEwLjIyMiAyNC42MiAxMC4yMjIgMTkuMTg1IDAgMzQuNzU1LTE1LjYxNSAzNC43NTUtMzQuODdDNzIzLjI5OCA0NTcuMTI0IDcxOS40MTggNDQ4LjQwNiA3MTMuMTQ4IDQ0Mi4wOTZ6IiAgaG9yaXotYWR2LXg9IjEwMjQiIC8+CgogICAgCgoKICA8L2ZvbnQ+CjwvZGVmcz48L3N2Zz4K#iconfont) format("svg")}.iconfont{font-family:iconfont!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-error:before{content:"\E727"}.icon-pulldown:before{content:"\E64A"}.icon-complete:before{content:"\E688"} 2 | /*# sourceMappingURL=vue-virtual-infinite-scroll.css.map */ -------------------------------------------------------------------------------- /dist/css/vue-virtual-infinite-scroll.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["vue-virtual-infinite-scroll.css"],"names":[],"mappings":"AACA,SACE,kBAAmB,AACnB,MAAS,AACT,SAAY,AACZ,OAAU,AACV,WAAY,AACZ,UAAW,AACX,eAAgB,CACjB,AACD,yBACE,kBAAmB,AACnB,aAAc,CACf,AACD,2BACE,eAAgB,AAChB,WAAY,AACZ,qBAAuB,CACxB,AACD,wCAGE,yBAA0B,AAGlB,yBAA0B,AAClC,oBAAsB,CACvB,AACD,sCAEU,uBAAwB,AAGhC,wBAA0B,CAE3B,AACD,6EACE,cAAgB,CACjB,AACD,uCACE,sBAAuB,AACvB,WAAY,AACZ,cAAgB,CACjB,AACD,sBACE,gBAAiB,AACjB,SAAU,AACV,SAAU,CACX,AACD,iCACE,kBAAmB,AACnB,OAAQ,AACR,MAAO,AACP,UAAY,CACb,AACD,0BACE,kBAAmB,AACnB,WAAY,AACZ,cAAe,AACf,kBAAmB,AACnB,aAAc,CACf,AACD,wCACE,sBAAuB,AACvB,eAAgB,AAChB,UAAY,CACb,AACD,0BACE,qBAAsB,AACtB,WAAY,AACZ,YAAa,AACb,iBAAkB,AAClB,kBAAmB,AACnB,sBAAuB,AACvB,kBAAmB,AACnB,sBAAuB,AAEf,6CAA8C,CACvD,AACD,iCACE,WAAY,AACZ,UAAW,AACX,WAAY,AACZ,kBAAmB,AACnB,cAAe,AACf,MAAO,AACP,SAAU,AACV,gBAAiB,AACjB,iBAAkB,AAClB,sBAAuB,AACvB,iBAAmB,CACpB,AAWD,4BACA,GAEY,mBAAqB,CAChC,AACD,GAEY,uBAA0B,CACrC,CACA,AAED,WAAY,qBAAwB,AAClC,gnGAAinG,AACjnG,qzXAGutH,CACxtH,AAED,UACE,+BAAkC,AAClC,eAAe,AACf,kBAAkB,AAClB,mCAAoC,AACpC,iCAAmC,CACpC,AAED,mBAAqB,eAAiB,CAAE,AAExC,sBAAwB,eAAiB,CAAE,AAE3C,sBAAwB,eAAiB,CAAE","file":"vue-virtual-infinite-scroll.css","sourcesContent":["\n#wrapper {\n position: absolute;\n top: 0px;\n bottom: 0px;\n left: 0px;\n width: 100%;\n z-index: 1;\n overflow: hidden\n}\n#wrapper .refresh-loader {\n text-align: center;\n padding: 5px 0\n}\n#wrapper .refresh-loader i {\n font-size: 20px;\n color: #999;\n vertical-align: middle;\n}\n#wrapper .refresh-loader .icon-pulldown {\n -webkit-transition: -webkit-transform .3s;\n transition: -webkit-transform .3s;\n transition: transform .3s;\n transition: transform .3s, -webkit-transform .3s;\n -webkit-transform: rotate(180deg);\n transform: rotate(180deg);\n display: inline-block;\n}\n#wrapper .refresh-loader .icon-pullup {\n -webkit-transform: rotate(0deg);\n transform: rotate(0deg);\n -webkit-transition: -webkit-transform .3s;\n transition: -webkit-transform .3s;\n transition: transform .3s;\n transition: transform .3s, -webkit-transform .3s;\n}\n#wrapper .refresh-loader .icon-complete, #wrapper .refresh-loader .icon-error {\n font-size: 23px;\n}\n#wrapper .refresh-loader .text-default {\n vertical-align: middle;\n color: #999;\n font-size: 14px;\n}\n#wrapper .scroll-list {\n list-style: none;\n margin: 0;\n padding: 0\n}\n#wrapper .scroll-list .list-item {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n}\n#wrapper .infinite-loader {\n position: absolute;\n width: 100%;\n z-index: 10000;\n text-align: center;\n padding: 5px 0\n}\n#wrapper .infinite-loader .text-default {\n vertical-align: middle;\n font-size: 14px;\n color: #999;\n}\n#wrapper .spinner-default {\n display: inline-block;\n width: 18px;\n height: 18px;\n line-height: 28px;\n border-radius: 50%;\n vertical-align: middle;\n position: relative;\n border: 1px solid #999;\n -webkit-animation: loading-rotating ease 1.5s infinite;\n animation: loading-rotating ease 1.5s infinite\n}\n#wrapper .spinner-default:before {\n content: '';\n width: 6px;\n height: 6px;\n position: absolute;\n display: block;\n top: 0;\n left: 50%;\n margin-top: -3px;\n margin-left: -3px;\n background-color: #999;\n border-radius: 50%;\n}\n@-webkit-keyframes loading-rotating {\n0%{\n -webkit-transform: rotate(0);\n transform: rotate(0);\n}\n100%{\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n}\n}\n@keyframes loading-rotating {\n0%{\n -webkit-transform: rotate(0);\n transform: rotate(0);\n}\n100%{\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n}\n}\n\n@font-face {font-family: \"iconfont\";\n src: url(data:application/vnd.ms-fontobject;base64,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); /* IE9*/\n src: url(data:application/vnd.ms-fontobject;base64,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#iefix) format('embedded-opentype'), \n url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),\n url(data:application/x-font-ttf;base64,AAEAAAALAIAAAwAwR1NVQrD+s+0AAAE4AAAAQk9TLzJW7kkUAAABfAAAAFZjbWFwBETUNAAAAegAAAGyZ2x5ZrJ6zOcAAAOoAAACIGhlYWQRgK49AAAA4AAAADZoaGVhB94DhgAAALwAAAAkaG10eBPpAAAAAAHUAAAAFGxvY2EBQAGsAAADnAAAAAxtYXhwARQAXQAAARgAAAAgbmFtZT5U/n0AAAXIAAACbXBvc3TQUZmjAAAIOAAAAEsAAQAAA4D/gABcBAAAAAAABAAAAQAAAAAAAAAAAAAAAAAAAAUAAQAAAAEAAGRmTJFfDzz1AAsEAAAAAADXMLUjAAAAANcwtSMAAP+sBAADTgAAAAgAAgAAAAAAAAABAAAABQBRAAUAAAAAAAIAAAAKAAoAAAD/AAAAAAAAAAEAAAAKAB4ALAABREZMVAAIAAQAAAAAAAAAAQAAAAFsaWdhAAgAAAABAAAAAQAEAAQAAAABAAgAAQAGAAAAAQAAAAAAAQP7AZAABQAIAokCzAAAAI8CiQLMAAAB6wAyAQgAAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZABAAHjnJwOA/4AAXAOAAIAAAAABAAAAAAAABAAAAAPpAAAEAAAABAAAAAQAAAAAAAAFAAAAAwAAACwAAAAEAAABcgABAAAAAABsAAMAAQAAACwAAwAKAAABcgAEAEAAAAAKAAgAAgACAHjmSuaI5yf//wAAAHjmSuaI5yf//wAAAAAAAAAAAAEACgAKAAoACgAAAAEAAwAEAAIAAAEGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAEAAAAAAAAAABAAAAHgAAAB4AAAAAQAA5koAAOZKAAAAAwAA5ogAAOaIAAAABAAA5ycAAOcnAAAAAgAAAAAAAAB2AJwAygEQAAUAAP/hA7wDGAATACgAMQBEAFAAAAEGKwEiDgIdASEnNC4CKwEVIQUVFxQOAycjJyEHIyIuAz0BFyIGFBYyNjQmFwYHBg8BDgEeATMhMjYnLgInATU0PgI7ATIWHQEBGRsaUxIlHBIDkAEKGCcehf5KAqIBFR8jHA8+Lf5JLD8UMiATCHcMEhIZEhKMCAYFBQgCAgQPDgFtFxYJBQkKBv6kBQ8aFbwfKQIfAQwZJxpMWQ0gGxJhiDRuHSUXCQEBgIABExsgDqc/ERoRERoRfBoWExIZBxANCBgaDSMkFAF35AsYEwwdJuMAAAAAAwAA/9UDqwMrAAsADwATAAABDgEHHgEXPgE3LgEDIzUzNSMRMwIAtfEFBfG1tfEFBfGKVlZWVgMrBfG1tfEFBfG1tfH9hVVVAQAAAAEAAP+sA3EDTgAYAAAJASYiBwEGFBYyNwERFBYyNjURARYyNz4BA2r+nAcRCP6dBw8RBwE9DRMNATYIEQcMAgHdAWkICP6QBxEPBwFK/MMKDAwKAzf+wwcHCBMAAwAA/8IDtwMzAAsAFwApAAAFLgEnPgE3HgEXDgEDDgEHHgEXPgE3LgETBzEGIi8BJjQ2Mh8BNzYyFhQCAbv3BQX3u7r3BQX3vZ3RBATRnZ3RBATRLtAKHgqKChQdCnK4Ch0UPQT5u7r5BAT5urv5AycE0p2e0QQE0Z6d0v7Q0goKjAodFApzuQoTHgAAABIA3gABAAAAAAAAABUAAAABAAAAAAABAAgAFQABAAAAAAACAAcAHQABAAAAAAADAAgAJAABAAAAAAAEAAgALAABAAAAAAAFAAsANAABAAAAAAAGAAgAPwABAAAAAAAKACsARwABAAAAAAALABMAcgADAAEECQAAACoAhQADAAEECQABABAArwADAAEECQACAA4AvwADAAEECQADABAAzQADAAEECQAEABAA3QADAAEECQAFABYA7QADAAEECQAGABABAwADAAEECQAKAFYBEwADAAEECQALACYBaQpDcmVhdGVkIGJ5IGljb25mb250Cmljb25mb250UmVndWxhcmljb25mb250aWNvbmZvbnRWZXJzaW9uIDEuMGljb25mb250R2VuZXJhdGVkIGJ5IHN2ZzJ0dGYgZnJvbSBGb250ZWxsbyBwcm9qZWN0Lmh0dHA6Ly9mb250ZWxsby5jb20ACgBDAHIAZQBhAHQAZQBkACAAYgB5ACAAaQBjAG8AbgBmAG8AbgB0AAoAaQBjAG8AbgBmAG8AbgB0AFIAZQBnAHUAbABhAHIAaQBjAG8AbgBmAG8AbgB0AGkAYwBvAG4AZgBvAG4AdABWAGUAcgBzAGkAbwBuACAAMQAuADAAaQBjAG8AbgBmAG8AbgB0AEcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAAcwB2AGcAMgB0AHQAZgAgAGYAcgBvAG0AIABGAG8AbgB0AGUAbABsAG8AIABwAHIAbwBqAGUAYwB0AC4AaAB0AHQAcAA6AC8ALwBmAG8AbgB0AGUAbABsAG8ALgBjAG8AbQAAAAACAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUBAgEDAQQBBQEGAAF4BWVycm9yCHNoYW5nZmFuCnlpd2FuY2hlbmcAAAA=) format('truetype'), \n url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiID4KPCEtLQoyMDEzLTktMzA6IENyZWF0ZWQuCi0tPgo8c3ZnPgo8bWV0YWRhdGE+CkNyZWF0ZWQgYnkgaWNvbmZvbnQKPC9tZXRhZGF0YT4KPGRlZnM+Cgo8Zm9udCBpZD0iaWNvbmZvbnQiIGhvcml6LWFkdi14PSIxMDI0IiA+CiAgPGZvbnQtZmFjZQogICAgZm9udC1mYW1pbHk9Imljb25mb250IgogICAgZm9udC13ZWlnaHQ9IjUwMCIKICAgIGZvbnQtc3RyZXRjaD0ibm9ybWFsIgogICAgdW5pdHMtcGVyLWVtPSIxMDI0IgogICAgYXNjZW50PSI4OTYiCiAgICBkZXNjZW50PSItMTI4IgogIC8+CiAgICA8bWlzc2luZy1nbHlwaCAvPgogICAgCiAgICA8Z2x5cGggZ2x5cGgtbmFtZT0ieCIgdW5pY29kZT0ieCIgaG9yaXotYWR2LXg9IjEwMDEiCmQ9Ik0yODEgNTQzcS0yNyAtMSAtNTMgLTFoLTgzcS0xOCAwIC0zNi41IC02dC0zMi41IC0xOC41dC0yMyAtMzJ0LTkgLTQ1LjV2LTc2aDkxMnY0MXEwIDE2IC0wLjUgMzB0LTAuNSAxOHEwIDEzIC01IDI5dC0xNyAyOS41dC0zMS41IDIyLjV0LTQ5LjUgOWgtMTMzdi05N2gtNDM4djk3ek05NTUgMzEwdi01MnEwIC0yMyAwLjUgLTUydDAuNSAtNTh0LTEwLjUgLTQ3LjV0LTI2IC0zMHQtMzMgLTE2dC0zMS41IC00LjVxLTE0IC0xIC0yOS41IC0wLjUKdC0yOS41IDAuNWgtMzJsLTQ1IDEyOGgtNDM5bC00NCAtMTI4aC0yOWgtMzRxLTIwIDAgLTQ1IDFxLTI1IDAgLTQxIDkuNXQtMjUuNSAyM3QtMTMuNSAyOS41dC00IDMwdjE2N2g5MTF6TTE2MyAyNDdxLTEyIDAgLTIxIC04LjV0LTkgLTIxLjV0OSAtMjEuNXQyMSAtOC41cTEzIDAgMjIgOC41dDkgMjEuNXQtOSAyMS41dC0yMiA4LjV6TTMxNiAxMjNxLTggLTI2IC0xNCAtNDhxLTUgLTE5IC0xMC41IC0zN3QtNy41IC0yNXQtMyAtMTV0MSAtMTQuNQp0OS41IC0xMC41dDIxLjUgLTRoMzdoNjdoODFoODBoNjRoMzZxMjMgMCAzNCAxMnQyIDM4cS01IDEzIC05LjUgMzAuNXQtOS41IDM0LjVxLTUgMTkgLTExIDM5aC0zNjh6TTMzNiA0OTh2MjI4cTAgMTEgMi41IDIzdDEwIDIxLjV0MjAuNSAxNS41dDM0IDZoMTg4cTMxIDAgNTEuNSAtMTQuNXQyMC41IC01Mi41di0yMjdoLTMyN3oiIC8+CiAgICAKCiAgICAKICAgIDxnbHlwaCBnbHlwaC1uYW1lPSJlcnJvciIgdW5pY29kZT0iJiM1OTE3NTsiIGQ9Ik01MTIgODEwLjY2NjY2N2MtMjM1LjUyIDAtNDI2LjY2NjY2Ny0xOTAuOTMzMzMzLTQyNi42NjY2NjctNDI2LjY2NjY2N3MxOTEuMTQ2NjY3LTQyNi42NjY2NjcgNDI2LjY2NjY2Ny00MjYuNjY2NjY3IDQyNi42NjY2NjcgMTkwLjkzMzMzMyA0MjYuNjY2NjY3IDQyNi42NjY2NjctMTkxLjE0NjY2NyA0MjYuNjY2NjY3LTQyNi42NjY2NjcgNDI2LjY2NjY2N3pNNTU0LjY2NjY2NyAxNzAuNjY2NjY3bC04NS4zMzMzMzMgMCAwIDg1LjMzMzMzMyA4NS4zMzMzMzMgMCAwLTg1LjMzMzMzM3pNNTU0LjY2NjY2NyAzNDEuMzMzMzMzbC04NS4zMzMzMzMgMCAwIDI1NiA4NS4zMzMzMzMgMCAwLTI1NnoiICBob3Jpei1hZHYteD0iMTAyNCIgLz4KCiAgICAKICAgIDxnbHlwaCBnbHlwaC1uYW1lPSJzaGFuZ2ZhbiIgdW5pY29kZT0iJiM1ODk1NDsiIGQ9Ik04NzMuNiA0NzYuOGwtMzU1LjIgMzYxLjZjLTkuNiA5LjYtMjIuNCA5LjYtMzIgMGwtMzU1LjItMzY4Yy05LjYtOS42LTkuNi0yMi40IDAtMzIgOS42LTkuNiAyMi40LTkuNiAzMiAwbDMxNi44IDMyOS42IDAtODI4LjhjMC0xMi44IDkuNi0yMi40IDIyLjQtMjIuNHMyMi40IDkuNiAyMi40IDIyLjRsMCA4MjIuNCAzMTAuNC0zMTYuOGM5LjYtOS42IDIyLjQtOS42IDMyIDBDODgzLjIgNDU0LjQgODgzLjIgNDcwLjQgODczLjYgNDc2Ljh6IiAgaG9yaXotYWR2LXg9IjEwMjQiIC8+CgogICAgCiAgICA8Z2x5cGggZ2x5cGgtbmFtZT0ieWl3YW5jaGVuZyIgdW5pY29kZT0iJiM1OTAxNjsiIGQ9Ik01MTIuNTQ0LTYxLjI2M2MtMjQyLjA3NCAwLTQzOC4zMDQgMTk2LjkwNC00MzguMzA0IDQzOS44MDRTMjcwLjQ2OSA4MTguMzQgNTEyLjU0NCA4MTguMzRjMjQyLjA2NCAwIDQzOC4zMDQtMTk2LjkgNDM4LjMwNC00MzkuNzk5Uzc1NC42MDgtNjEuMjYzIDUxMi41NDQtNjEuMjYzek01MTAuMTc0IDc0OS45M2MtMjA0LjMwOSAwLTM2OS45MDktMTY2LjE3Ny0zNjkuOTA5LTM3MS4xNzkgMC0yMDQuOTk1IDE2NS42LTM3MS4xNzkgMzY5LjkwOS0zNzEuMTc5IDIwNC4yNzUgMCAzNjkuODk5IDE2Ni4xODUgMzY5Ljg5OSAzNzEuMTc5Qzg4MC4wNzMgNTgzLjc1MyA3MTQuNDQ4IDc0OS45MyA1MTAuMTc0IDc0OS45M3pNNzEzLjE0OCA0NDIuMDk2IDUwNC41MjkgMjMyLjIzN2wwIDAuMDJjLTYuMzEtNi4zNDUtMTQuOTg3LTEwLjI0NS0yNC42MjUtMTAuMjQ1LTkuNiAwLTE4LjMxNSAzLjk0LTI0LjYwNSAxMC4yNDVsLTEzOC42MDUgMTM5LjU5Yy02LjI4NyA2LjMtMTAuMTY3IDE1LjAwNS0xMC4xNjcgMjQuNjIgMCAxOS4zIDE1LjU5MiAzNC45MTUgMzQuNzcgMzQuOTE1IDkuNjIyIDAgMTguMzItMy45MiAyNC42MjctMTAuMjVsMTEzLjk4LTExNC44MTUgMTg0LjAyIDE4NS4wOTJjNi4yOTUgNi4zMjUgMTUuMDI1IDEwLjIyMiAyNC42MiAxMC4yMjIgMTkuMTg1IDAgMzQuNzU1LTE1LjYxNSAzNC43NTUtMzQuODdDNzIzLjI5OCA0NTcuMTI0IDcxOS40MTggNDQ4LjQwNiA3MTMuMTQ4IDQ0Mi4wOTZ6IiAgaG9yaXotYWR2LXg9IjEwMjQiIC8+CgogICAgCgoKICA8L2ZvbnQ+CjwvZGVmcz48L3N2Zz4K#iconfont) format('svg'); /* iOS 4.1- */\n}\n\n.iconfont {\n font-family:\"iconfont\" !important;\n font-size:16px;\n font-style:normal;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n.icon-error:before { content: \"\\E727\"; }\n\n.icon-pulldown:before { content: \"\\E64A\"; }\n\n.icon-complete:before { content: \"\\E688\"; }\n\n"]} -------------------------------------------------------------------------------- /dist/vue-virtual-infinite-scroll.js: -------------------------------------------------------------------------------- 1 | !function(t,i){"object"==typeof exports&&"object"==typeof module?module.exports=i():"function"==typeof define&&define.amd?define([],i):"object"==typeof exports?exports.VueVirtualInfiniteScroll=i():t.VueVirtualInfiniteScroll=i()}("undefined"!=typeof self?self:this,function(){return function(t){var i={};function e(s){if(i[s])return i[s].exports;var o=i[s]={i:s,l:!1,exports:{}};return t[s].call(o.exports,o,o.exports,e),o.l=!0,o.exports}return e.m=t,e.c=i,e.d=function(t,i,s){e.o(t,i)||Object.defineProperty(t,i,{configurable:!1,enumerable:!0,get:s})},e.n=function(t){var i=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(i,"a",i),i},e.o=function(t,i){return Object.prototype.hasOwnProperty.call(t,i)},e.p="/",e(e.s=0)}([function(t,i,e){"use strict";Object.defineProperty(i,"__esModule",{value:!0});var s=e(3),o=e.n(s),n=(e(4),{name:"virtual-scroll",props:{items:{type:Array,required:!0},uniqueKey:{type:String,required:!0,default:"id"},infinite:Boolean,pulldown:Boolean,pulldownText:{type:Object,default:function(){return{begin:"下拉刷新",trigger:"释放更新",refresh:"更新中...",complete:"更新完成",error:"更新失败"}}},variable:{type:Boolean,default:!1},distance:{type:Number,default:50},bufferSize:[String,Number],iscrollOptions:{type:Object,default:function(){return{scrollbars:!0,interactiveScrollbars:!0,probeType:3,mouseWheel:!0,mouseWheelSpeed:1}}},loadMore:Function,pullRefresh:Function},data:function(){return{myScroll:null,viewInited:!1,wrapperHeight:0,itemHeight:0,buffer:0,poolLength:0,pool:[],infiniteLoading:!1,infiniteComplete:!1,pullerTop:0,pullState:"",accumulator:0,oriItemLength:0,scrolledItem:null}},created:function(){this.buffer=this.bufferSize||5,this.pool=this.items.slice(0,this.buffer)},mounted:function(){var t=this;this.$nextTick(function(){t.initScroller()})},watch:{items:function(t,i){var e=this;if(this.viewInited||(this.pool=this.items.slice(0,this.buffer),this.$nextTick(function(){e.generateItemAccumulator(!0),e.initScrollView()})),this.pool.length=o._top&&t0&&this.myScroll.maxScrollY>this.myScroll.y-this.distance?this.triggerLoadmore():this.pulldown&&this.myScroll.y>0?this.triggerPulldownRefresh():this.updateScrollView()},handleScrollEndEvent:function(){"complete"!==this.pullState&&"error"!==this.pullState&&"begin"!==this.pullState||(this.pullState="",this.myScroll.pullState="")},handlePullDownEndEvent:function(){"trigger"===this.pullState&&(this.pullState="refresh",this.myScroll.pullState="refresh",this.$emit("pullRefresh",this.pullStateManager))},triggerLoadmore:function(){var t=this;this.infinite&&(this.isPulling=!1,this.infiniteLoading=!0,this.oriItemLength=this.items.length,this.$nextTick(function(){t.resetScroller(t.$el.querySelector(".infinite-loader").offsetHeight)}),this.$emit("loadMore",this.infiniteStateManager))},triggerPulldownRefresh:function(){var t=this;this.pulldown&&(this.infiniteLoading||"refresh"===this.pullState||"complete"===this.pullState||"error"===this.pullState||(!this.pullState||this.myScroll.y<=this.pullerTop?(this.pullState="begin",this.myScroll.pullerHeight=0,this.pullerTop||this.$nextTick(function(){t.pullerTop=t.$el.querySelector(".refresh-loader").offsetHeight})):this.myScroll.y>this.pullerTop&&(this.pullState="trigger",this.myScroll.pullerHeight=this.pullerTop)))},infiniteStateManager:function(t){var i=this;switch(t){case"loaded":this.infiniteLoading=!1,this.generateItemAccumulator(!1),this.$nextTick(function(){i.resetScroller(),i.updateScrollView()});break;case"error":this.infiniteLoading=!1,this.$nextTick(function(){i.resetScroller()});break;case"complete":this.infiniteLoading=!1,this.infiniteComplete=!0,this.generateItemAccumulator(!1),this.$nextTick(function(){i.resetScroller()})}},pullStateManager:function(t){var i=this;"complete"===t?(this.myScroll.pullerHeight=0,this.pullState="complete",this.generateItemAccumulator(!0),setTimeout(function(){i.resetScroller(null,600),i.resetParams()},500)):(this.myScroll.pullerHeight=0,this.pullState="error",setTimeout(function(){i.resetScroller(null,600),i.resetParams()},500))},resetScroller:function(t,i){var e=t||0;this.variable?(this.myScroll.scrollerHeight=this.accumulator+e,this.myScroll.maxScrollY=this.wrapperHeight-this.accumulator-e):(this.myScroll.scrollerHeight=this.itemHeight*this.items.length+e,this.myScroll.maxScrollY=-this.itemHeight*this.items.length+this.wrapperHeight-e),this.myScroll.refresh(i)},updateScrollView:function(){if(this.variable)for(var t=this.getScrolledIndex(-this.myScroll.y),i=Math.max(t-this.buffer,0),e=Math.floor(i/this.pool.length),s=i%this.pool.length,o=0,n=0;o0,expression:"pullState.length > 0"}],staticClass:"refresh-loader",style:t.getPullerStyle},[t._t("pullRefresh",[e("i",{staticClass:"iconfont",class:t.getPullerClass}),t._v(" "),e("span",{staticClass:"text-default"},[t._v(t._s(t.pullText))])])],2):t._e(),t._v(" "),e("ul",{staticClass:"scroll-list"},t._l(t.pool,function(i){return e("li",{key:i[t.uniqueKey],staticClass:"list-item",style:t.getItemStyle(i)},[t._t("content",null,{item:i})],2)})),t._v(" "),t.infinite?e("div",{directives:[{name:"show",rawName:"v-show",value:t.infiniteLoading,expression:"infiniteLoading"}],staticClass:"infinite-loader",style:t.getSpinnerStyle},[t._t("infiniteLoader",[e("i",{staticClass:"spinner-default"}),t._v(" "),e("span",{staticClass:"text-default"},[t._v("加载中...")])])],2):t._e()])])},staticRenderFns:[]};var h=e(2)(n,r,!1,function(t){e(1)},null,null).exports;i.default=h},function(t,i){},function(t,i){t.exports=function(t,i,e,s,o,n){var r,h=t=t||{},a=typeof t.default;"object"!==a&&"function"!==a||(r=t,h=t.default);var l,c="function"==typeof h?h.options:h;if(i&&(c.render=i.render,c.staticRenderFns=i.staticRenderFns,c._compiled=!0),e&&(c.functional=!0),o&&(c._scopeId=o),n?(l=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),s&&s.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(n)},c._ssrRegister=l):s&&(l=s),l){var p=c.functional,u=p?c.render:c.beforeCreate;p?(c._injectStyles=l,c.render=function(t,i){return l.call(i),u(t,i)}):c.beforeCreate=u?[].concat(u,l):[l]}return{esModule:r,exports:h,options:c}}},function(t,i,e){var s;/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */ /*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */ 2 | !function(o,n,r){var h=o.requestAnimationFrame||o.webkitRequestAnimationFrame||o.mozRequestAnimationFrame||o.oRequestAnimationFrame||o.msRequestAnimationFrame||function(t){o.setTimeout(t,1e3/60)},a=function(){var t={},i=n.createElement("div").style,e=function(){for(var t=["t","webkitT","MozT","msT","OT"],e=0,s=t.length;e0&&(h=o?o/2.5*(c/8):0,a=(l=r.abs(t)+h)/c),{destination:r.round(h),duration:a}};var h=s("transform");return t.extend(t,{hasTransform:!1!==h,hasPerspective:s("perspective")in i,hasTouch:"ontouchstart"in o,hasPointer:!(!o.PointerEvent&&!o.MSPointerEvent),hasTransition:s("transition")in i}),t.isBadAndroid=function(){var t=o.navigator.appVersion;if(/Android/.test(t)&&!/Chrome\/\d/.test(t)){var i=t.match(/Safari\/(\d+.\d)/);return!(i&&"object"==typeof i&&i.length>=2)||parseFloat(i[1])<535.19}return!1}(),t.extend(t.style={},{transform:h,transitionTimingFunction:s("transitionTimingFunction"),transitionDuration:s("transitionDuration"),transitionDelay:s("transitionDelay"),transformOrigin:s("transformOrigin")}),t.hasClass=function(t,i){return new RegExp("(^|\\s)"+i+"(\\s|$)").test(t.className)},t.addClass=function(i,e){if(!t.hasClass(i,e)){var s=i.className.split(" ");s.push(e),i.className=s.join(" ")}},t.removeClass=function(i,e){if(t.hasClass(i,e)){var s=new RegExp("(^|\\s)"+e+"(\\s|$)","g");i.className=i.className.replace(s," ")}},t.offset=function(t){for(var i=-t.offsetLeft,e=-t.offsetTop;t=t.offsetParent;)i-=t.offsetLeft,e-=t.offsetTop;return{left:i,top:e}},t.preventDefaultException=function(t,i){for(var e in i)if(i[e].test(t[e]))return!0;return!1},t.extend(t.eventType={},{touchstart:1,touchmove:1,touchend:1,mousedown:2,mousemove:2,mouseup:2,pointerdown:3,pointermove:3,pointerup:3,MSPointerDown:3,MSPointerMove:3,MSPointerUp:3}),t.extend(t.ease={},{quadratic:{style:"cubic-bezier(0.25, 0.46, 0.45, 0.94)",fn:function(t){return t*(2-t)}},circular:{style:"cubic-bezier(0.1, 0.57, 0.1, 1)",fn:function(t){return r.sqrt(1- --t*t)}},back:{style:"cubic-bezier(0.175, 0.885, 0.32, 1.275)",fn:function(t){return(t-=1)*t*(5*t+4)+1}},bounce:{style:"",fn:function(t){return(t/=1)<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}},elastic:{style:"",fn:function(t){return 0===t?0:1==t?1:.4*r.pow(2,-10*t)*r.sin((t-.055)*(2*r.PI)/.22)+1}}}),t.tap=function(t,i){var e=n.createEvent("Event");e.initEvent(i,!0,!0),e.pageX=t.pageX,e.pageY=t.pageY,t.target.dispatchEvent(e)},t.click=function(t){var i,e=t.target;/(SELECT|INPUT|TEXTAREA)/i.test(e.tagName)||((i=n.createEvent("MouseEvents")).initMouseEvent("click",!0,!0,t.view,1,e.screenX,e.screenY,e.clientX,e.clientY,t.ctrlKey,t.altKey,t.shiftKey,t.metaKey,0,null),i._constructed=!0,e.dispatchEvent(i))},t}();function l(t,i){for(var e in this.wrapper="string"==typeof t?n.querySelector(t):t,this.scroller=this.wrapper.children[0],this.scrollerStyle=this.scroller.style,this.options={resizeScrollbars:!0,mouseWheelSpeed:20,snapThreshold:.334,disablePointer:!a.hasPointer,disableTouch:a.hasPointer||!a.hasTouch,disableMouse:a.hasPointer||a.hasTouch,startX:0,startY:0,scrollY:!0,directionLockThreshold:5,momentum:!0,bounce:!0,bounceTime:600,bounceEasing:"",preventDefault:!0,preventDefaultException:{tagName:/^(INPUT|TEXTAREA|BUTTON|SELECT)$/},HWCompositing:!0,useTransition:!0,useTransform:!0,bindToWrapper:void 0===o.onmousedown},i)this.options[e]=i[e];this.translateZ=this.options.HWCompositing&&a.hasPerspective?" translateZ(0)":"",this.options.useTransition=a.hasTransition&&this.options.useTransition,this.options.useTransform=a.hasTransform&&this.options.useTransform,this.options.eventPassthrough=!0===this.options.eventPassthrough?"vertical":this.options.eventPassthrough,this.options.preventDefault=!this.options.eventPassthrough&&this.options.preventDefault,this.options.scrollY="vertical"!=this.options.eventPassthrough&&this.options.scrollY,this.options.scrollX="horizontal"!=this.options.eventPassthrough&&this.options.scrollX,this.options.freeScroll=this.options.freeScroll&&!this.options.eventPassthrough,this.options.directionLockThreshold=this.options.eventPassthrough?0:this.options.directionLockThreshold,this.options.bounceEasing="string"==typeof this.options.bounceEasing?a.ease[this.options.bounceEasing]||a.ease.circular:this.options.bounceEasing,this.options.resizePolling=void 0===this.options.resizePolling?60:this.options.resizePolling,!0===this.options.tap&&(this.options.tap="tap"),"scale"==this.options.shrinkScrollbars&&(this.options.useTransition=!1),this.options.invertWheelDirection=this.options.invertWheelDirection?-1:1,3==this.options.probeType&&(this.options.useTransition=!1),this.x=0,this.y=0,this.directionX=0,this.directionY=0,this._events={},this._init(),this.refresh(),this.scrollTo(this.options.startX,this.options.startY),this.enable()}function c(t,i,e){var s=n.createElement("div"),o=n.createElement("div");return!0===e&&(s.style.cssText="position:absolute;z-index:9999",o.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px"),o.className="iScrollIndicator","h"==t?(!0===e&&(s.style.cssText+=";height:7px;left:2px;right:2px;bottom:0",o.style.height="100%"),s.className="iScrollHorizontalScrollbar"):(!0===e&&(s.style.cssText+=";width:7px;bottom:2px;top:2px;right:1px",o.style.width="100%"),s.className="iScrollVerticalScrollbar"),s.style.cssText+=";overflow:hidden",i||(s.style.pointerEvents="none"),s.appendChild(o),s}function p(t,i){for(var e in this.wrapper="string"==typeof i.el?n.querySelector(i.el):i.el,this.wrapperStyle=this.wrapper.style,this.indicator=this.wrapper.children[0],this.indicatorStyle=this.indicator.style,this.scroller=t,this.options={listenX:!0,listenY:!0,interactive:!1,resize:!0,defaultScrollbars:!1,shrink:!1,fade:!1,speedRatioX:0,speedRatioY:0},i)this.options[e]=i[e];if(this.sizeRatioX=1,this.sizeRatioY=1,this.maxPosX=0,this.maxPosY=0,this.options.interactive&&(this.options.disableTouch||(a.addEvent(this.indicator,"touchstart",this),a.addEvent(o,"touchend",this)),this.options.disablePointer||(a.addEvent(this.indicator,a.prefixPointerEvent("pointerdown"),this),a.addEvent(o,a.prefixPointerEvent("pointerup"),this)),this.options.disableMouse||(a.addEvent(this.indicator,"mousedown",this),a.addEvent(o,"mouseup",this))),this.options.fade){this.wrapperStyle[a.style.transform]=this.scroller.translateZ;var s=a.style.transitionDuration;this.wrapperStyle[s]=a.isBadAndroid?"0.0001ms":"0ms";var r=this;a.isBadAndroid&&h(function(){"0.0001ms"===r.wrapperStyle[s]&&(r.wrapperStyle[s]="0s")}),this.wrapperStyle.opacity="0"}}l.prototype={version:"5.2.0",_init:function(){this._initEvents(),(this.options.scrollbars||this.options.indicators)&&this._initIndicators(),this.options.mouseWheel&&this._initWheel(),this.options.snap&&this._initSnap(),this.options.keyBindings&&this._initKeys()},destroy:function(){this._initEvents(!0),clearTimeout(this.resizeTimeout),this.resizeTimeout=null,this._execEvent("destroy")},_transitionEnd:function(t){t.target==this.scroller&&this.isInTransition&&(this._transitionTime(),this.resetPosition(this.options.bounceTime)||(this.isInTransition=!1,this._execEvent("scrollEnd")))},_start:function(t){if(1!=a.eventType[t.type]&&0!==(t.which?t.button:t.button<2?0:4==t.button?1:2))return;if(this.enabled&&(!this.initiated||a.eventType[t.type]===this.initiated)){!this.options.preventDefault||a.isBadAndroid||a.preventDefaultException(t.target,this.options.preventDefaultException)||t.preventDefault();var i,e=t.touches?t.touches[0]:t;this.initiated=a.eventType[t.type],this.moved=!1,this.distX=0,this.distY=0,this.directionX=0,this.directionY=0,this.directionLocked=0,this.startTime=a.getTime(),this.options.useTransition&&this.isInTransition?(this._transitionTime(),this.isInTransition=!1,i=this.getComputedPosition(),this._translate(r.round(i.x),r.round(i.y)),this._execEvent("scrollEnd")):!this.options.useTransition&&this.isAnimating&&(this.isAnimating=!1,this._execEvent("scrollEnd")),this.startX=this.x,this.startY=this.y,this.absStartX=this.x,this.absStartY=this.y,this.pointX=e.pageX,this.pointY=e.pageY,this._execEvent("beforeScrollStart")}},_move:function(t){if(this.enabled&&a.eventType[t.type]===this.initiated){this.options.preventDefault&&t.preventDefault();var i,e,s,o,n=t.touches?t.touches[0]:t,h=n.pageX-this.pointX,l=n.pageY-this.pointY,c=a.getTime();if(this.pointX=n.pageX,this.pointY=n.pageY,this.distX+=h,this.distY+=l,s=r.abs(this.distX),o=r.abs(this.distY),!(c-this.endTime>300&&s<10&&o<10)){if(this.directionLocked||this.options.freeScroll||(s>o+this.options.directionLockThreshold?this.directionLocked="h":o>=s+this.options.directionLockThreshold?this.directionLocked="v":this.directionLocked="n"),"h"==this.directionLocked){if("vertical"==this.options.eventPassthrough)t.preventDefault();else if("horizontal"==this.options.eventPassthrough)return void(this.initiated=!1);l=0}else if("v"==this.directionLocked){if("horizontal"==this.options.eventPassthrough)t.preventDefault();else if("vertical"==this.options.eventPassthrough)return void(this.initiated=!1);h=0}h=this.hasHorizontalScroll?h:0,l=this.hasVerticalScroll?l:0,i=this.x+h,e=this.y+l,(i>0||i0?0:this.maxScrollX),(e>0||e0?0:this.maxScrollY),this.directionX=h>0?-1:h<0?1:0,this.directionY=l>0?-1:l<0?1:0,this.moved||this._execEvent("scrollStart"),this.moved=!0,this._translate(i,e),c-this.startTime>300&&(this.startTime=c,this.startX=this.x,this.startY=this.y,1==this.options.probeType&&this._execEvent("scroll")),this.options.probeType>1&&this._execEvent("scroll")}}},_end:function(t){if(this.enabled&&a.eventType[t.type]===this.initiated){this.options.preventDefault&&!a.preventDefaultException(t.target,this.options.preventDefaultException)&&t.preventDefault();t.changedTouches&&t.changedTouches[0];var i,e,s=a.getTime()-this.startTime,o=r.round(this.x),n=r.round(this.y),h=r.abs(o-this.startX),l=r.abs(n-this.startY),c=0,p="";if(this.isInTransition=0,this.initiated=0,this.endTime=a.getTime(),this.resetPosition(this.options.bounceTime))this.y>0&&this._execEvent("pullDownEnd");else{if(this.scrollTo(o,n),!this.moved)return this.options.tap&&a.tap(t,this.options.tap),this.options.click&&a.click(t),void this._execEvent("scrollCancel");if(this._events.flick&&s<200&&h<100&&l<100)this._execEvent("flick");else{if(this.options.momentum&&s<300&&(i=this.hasHorizontalScroll?a.momentum(this.x,this.startX,s,this.maxScrollX,this.options.bounce?this.wrapperWidth:0,this.options.deceleration):{destination:o,duration:0},e=this.hasVerticalScroll?a.momentum(this.y,this.startY,s,this.maxScrollY,this.options.bounce?this.wrapperHeight:0,this.options.deceleration):{destination:n,duration:0},o=i.destination,n=e.destination,c=r.max(i.duration,e.duration),this.isInTransition=1),this.options.snap){var u=this._nearestSnap(o,n);this.currentPage=u,c=this.options.snapSpeed||r.max(r.max(r.min(r.abs(o-u.x),1e3),r.min(r.abs(n-u.y),1e3)),300),o=u.x,n=u.y,this.directionX=0,this.directionY=0,p=this.options.bounceEasing}if(n>0&&(n=0),o!=this.x||n!=this.y)return(o>0||o0||n0?i=0:this.x0?e=0:this.y0&&(e=this.pullerHeight),(i!=this.x||e!=this.y)&&(this.scrollTo(i,e,t,this.options.bounceEasing),!0)},disable:function(){this.enabled=!1},enable:function(){this.enabled=!0},refresh:function(t){this.wrapper.offsetHeight;this.wrapperWidth=this.wrapper.clientWidth,this.wrapperHeight=this.wrapper.clientHeight,this.scrollerWidth=this.scroller.offsetWidth,this.maxScrollX=this.wrapperWidth-this.scrollerWidth,this.hasHorizontalScroll=this.options.scrollX&&this.maxScrollX<0,this.hasVerticalScroll=this.options.scrollY&&this.maxScrollY<0,this.hasHorizontalScroll||(this.maxScrollX=0,this.scrollerWidth=this.wrapperWidth),this.hasVerticalScroll||(this.maxScrollY=0,this.scrollerHeight=this.wrapperHeight),this.endTime=0,this.directionX=0,this.directionY=0,this.wrapperOffset=a.offset(this.wrapper),this._execEvent("refresh"),this.resetPosition(t)},on:function(t,i){this._events[t]||(this._events[t]=[]),this._events[t].push(i)},off:function(t,i){if(this._events[t]){var e=this._events[t].indexOf(i);e>-1&&this._events[t].splice(e,1)}},_execEvent:function(t){if(this._events[t]){var i=0,e=this._events[t].length;if(e)for(;i0;var o=this.options.useTransition&&s.style;!e||o?(o&&(this._transitionTimingFunction(s.style),this._transitionTime(e)),this._translate(t,i)):this._animate(t,i,e,s.fn)},scrollToElement:function(t,i,e,s,o){if(t=t.nodeType?t:this.scroller.querySelector(t)){var n=a.offset(t);n.left-=this.wrapperOffset.left,n.top-=this.wrapperOffset.top,!0===e&&(e=r.round(t.offsetWidth/2-this.wrapper.offsetWidth/2)),!0===s&&(s=r.round(t.offsetHeight/2-this.wrapper.offsetHeight/2)),n.left-=e||0,n.top-=s||0,n.left=n.left>0?0:n.left0?0:n.top0?s--:i<0&&s++,e>0?o--:e<0&&o++,void this.goToPage(s,o);s=this.x+r.round(this.hasHorizontalScroll?i:0),o=this.y+r.round(this.hasVerticalScroll?e:0),this.directionX=i>0?-1:i<0?1:0,this.directionY=e>0?-1:e<0?1:0,s>0?s=0:s0?o=0:o1&&this._execEvent("scroll")}},_initSnap:function(){this.currentPage={},"string"==typeof this.options.snap&&(this.options.snap=this.scroller.querySelectorAll(this.options.snap)),this.on("refresh",function(){var t,i,e,s,o,n,h=0,a=0,l=0,c=this.options.snapStepX||this.wrapperWidth,p=this.options.snapStepY||this.wrapperHeight;if(this.pages=[],this.wrapperWidth&&this.wrapperHeight&&this.scrollerWidth&&this.scrollerHeight){if(!0===this.options.snap)for(e=r.round(c/2),s=r.round(p/2);l>-this.scrollerWidth;){for(this.pages[h]=[],t=0,o=0;o>-this.scrollerHeight;)this.pages[h][t]={x:r.max(l,this.maxScrollX),y:r.max(o,this.maxScrollY),width:c,height:p,cx:l-e,cy:o-s},o-=p,t++;l-=c,h++}else for(t=(n=this.options.snap).length,i=-1;hthis.maxScrollX&&a++;this.goToPage(this.currentPage.pageX||0,this.currentPage.pageY||0,0),this.options.snapThreshold%1==0?(this.snapThresholdX=this.options.snapThreshold,this.snapThresholdY=this.options.snapThreshold):(this.snapThresholdX=r.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width*this.options.snapThreshold),this.snapThresholdY=r.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height*this.options.snapThreshold))}}),this.on("flick",function(){var t=this.options.snapSpeed||r.max(r.max(r.min(r.abs(this.x-this.startX),1e3),r.min(r.abs(this.y-this.startY),1e3)),300);this.goToPage(this.currentPage.pageX+this.directionX,this.currentPage.pageY+this.directionY,t)})},_nearestSnap:function(t,i){if(!this.pages.length)return{x:0,y:0,pageX:0,pageY:0};var e=0,s=this.pages.length,o=0;if(r.abs(t-this.absStartX)0?t=0:t0?i=0:i=this.pages[e][0].cx){t=this.pages[e][0].x;break}for(s=this.pages[e].length;o=this.pages[0][o].cy){i=this.pages[0][o].y;break}return e==this.currentPage.pageX&&((e+=this.directionX)<0?e=0:e>=this.pages.length&&(e=this.pages.length-1),t=this.pages[e][0].x),o==this.currentPage.pageY&&((o+=this.directionY)<0?o=0:o>=this.pages[0].length&&(o=this.pages[0].length-1),i=this.pages[0][o].y),{x:t,y:i,pageX:e,pageY:o}},goToPage:function(t,i,e,s){s=s||this.options.bounceEasing,t>=this.pages.length?t=this.pages.length-1:t<0&&(t=0),i>=this.pages[t].length?i=this.pages[t].length-1:i<0&&(i=0);var o=this.pages[t][i].x,n=this.pages[t][i].y;e=void 0===e?this.options.snapSpeed||r.max(r.max(r.min(r.abs(o-this.x),1e3),r.min(r.abs(n-this.y),1e3)),300):e,this.currentPage={x:o,y:n,pageX:t,pageY:i},this.scrollTo(o,n,e,s)},next:function(t,i){var e=this.currentPage.pageX,s=this.currentPage.pageY;++e>=this.pages.length&&this.hasVerticalScroll&&(e=0,s++),this.goToPage(e,s,t,i)},prev:function(t,i){var e=this.currentPage.pageX,s=this.currentPage.pageY;--e<0&&this.hasVerticalScroll&&(e=0,s--),this.goToPage(e,s,t,i)},_initKeys:function(t){var i,e={pageUp:33,pageDown:34,end:35,home:36,left:37,up:38,right:39,down:40};if("object"==typeof this.options.keyBindings)for(i in this.options.keyBindings)"string"==typeof this.options.keyBindings[i]&&(this.options.keyBindings[i]=this.options.keyBindings[i].toUpperCase().charCodeAt(0));else this.options.keyBindings={};for(i in e)this.options.keyBindings[i]=this.options.keyBindings[i]||e[i];a.addEvent(o,"keydown",this),this.on("destroy",function(){a.removeEvent(o,"keydown",this)})},_key:function(t){if(this.enabled){var i,e=this.options.snap,s=e?this.currentPage.pageX:this.x,o=e?this.currentPage.pageY:this.y,n=a.getTime(),h=this.keyTime||0;switch(this.options.useTransition&&this.isInTransition&&(i=this.getComputedPosition(),this._translate(r.round(i.x),r.round(i.y)),this.isInTransition=!1),this.keyAcceleration=n-h<200?r.min(this.keyAcceleration+.25,50):0,t.keyCode){case this.options.keyBindings.pageUp:this.hasHorizontalScroll&&!this.hasVerticalScroll?s+=e?1:this.wrapperWidth:o+=e?1:this.wrapperHeight;break;case this.options.keyBindings.pageDown:this.hasHorizontalScroll&&!this.hasVerticalScroll?s-=e?1:this.wrapperWidth:o-=e?1:this.wrapperHeight;break;case this.options.keyBindings.end:s=e?this.pages.length-1:this.maxScrollX,o=e?this.pages[0].length-1:this.maxScrollY;break;case this.options.keyBindings.home:s=0,o=0;break;case this.options.keyBindings.left:s+=e?-1:5+this.keyAcceleration>>0;break;case this.options.keyBindings.up:o+=e?1:5+this.keyAcceleration>>0;break;case this.options.keyBindings.right:s-=e?-1:5+this.keyAcceleration>>0;break;case this.options.keyBindings.down:o-=e?1:5+this.keyAcceleration>>0;break;default:return}e?this.goToPage(s,o):(s>0?(s=0,this.keyAcceleration=0):s0?(o=0,this.keyAcceleration=0):o=c)return o.isAnimating=!1,o._translate(t,i),void(o.resetPosition(o.options.bounceTime)||o._execEvent("scrollEnd"));f=s(m=(m-l)/e),u=(t-n)*f+n,d=(i-r)*f+r,o._translate(u,d),o.isAnimating&&h(p),3==o.options.probeType&&o._execEvent("scroll")}()},handleEvent:function(t){if("refresh"!==this.pullState)switch(t.type){case"touchstart":case"pointerdown":case"MSPointerDown":case"mousedown":this._start(t);break;case"touchmove":case"pointermove":case"MSPointerMove":case"mousemove":this._move(t);break;case"touchend":case"pointerup":case"MSPointerUp":case"mouseup":case"touchcancel":case"pointercancel":case"MSPointerCancel":case"mousecancel":this._end(t);break;case"orientationchange":case"resize":this._resize();break;case"transitionend":case"webkitTransitionEnd":case"oTransitionEnd":case"MSTransitionEnd":this._transitionEnd(t);break;case"wheel":case"DOMMouseScroll":case"mousewheel":this._wheel(t);break;case"keydown":this._key(t);break;case"click":this.enabled&&!t._constructed&&(t.preventDefault(),t.stopPropagation())}}},p.prototype={handleEvent:function(t){if("refresh"!==this.scroller.pullState)switch(t.type){case"touchstart":case"pointerdown":case"MSPointerDown":case"mousedown":this._start(t);break;case"touchmove":case"pointermove":case"MSPointerMove":case"mousemove":this._move(t);break;case"touchend":case"pointerup":case"MSPointerUp":case"mouseup":case"touchcancel":case"pointercancel":case"MSPointerCancel":case"mousecancel":this._end(t)}},destroy:function(){this.options.fadeScrollbars&&(clearTimeout(this.fadeTimeout),this.fadeTimeout=null),this.options.interactive&&(a.removeEvent(this.indicator,"touchstart",this),a.removeEvent(this.indicator,a.prefixPointerEvent("pointerdown"),this),a.removeEvent(this.indicator,"mousedown",this),a.removeEvent(o,"touchmove",this),a.removeEvent(o,a.prefixPointerEvent("pointermove"),this),a.removeEvent(o,"mousemove",this),a.removeEvent(o,"touchend",this),a.removeEvent(o,a.prefixPointerEvent("pointerup"),this),a.removeEvent(o,"mouseup",this)),this.options.defaultScrollbars&&this.wrapper.parentNode.removeChild(this.wrapper)},_start:function(t){var i=t.touches?t.touches[0]:t;t.preventDefault(),t.stopPropagation(),this.transitionTime(),this.initiated=!0,this.moved=!1,this.lastPointX=i.pageX,this.lastPointY=i.pageY,this.startTime=a.getTime(),this.options.disableTouch||a.addEvent(o,"touchmove",this),this.options.disablePointer||a.addEvent(o,a.prefixPointerEvent("pointermove"),this),this.options.disableMouse||a.addEvent(o,"mousemove",this),this.scroller._execEvent("beforeScrollStart")},_move:function(t){var i,e,s,o,n=t.touches?t.touches[0]:t,r=a.getTime();this.moved||this.scroller._execEvent("scrollStart"),this.moved=!0,i=n.pageX-this.lastPointX,this.lastPointX=n.pageX,e=n.pageY-this.lastPointY,this.lastPointY=n.pageY,s=this.x+i,o=this.y+e,this.scroller.directionX=i>0?1:i<0?-1:0,this.scroller.directionY=e>0?1:e<0?-1:0,this._pos(s,o),1==this.scroller.options.probeType&&r-this.startTime>300?(this.startTime=r,this.scroller._execEvent("scroll")):this.scroller.options.probeType>1&&this.scroller._execEvent("scroll"),t.preventDefault(),t.stopPropagation()},_end:function(t){if(this.initiated){if(this.initiated=!1,t.preventDefault(),t.stopPropagation(),a.removeEvent(o,"touchmove",this),a.removeEvent(o,a.prefixPointerEvent("pointermove"),this),a.removeEvent(o,"mousemove",this),this.scroller.options.snap){var i=this.scroller._nearestSnap(this.scroller.x,this.scroller.y),e=this.options.snapSpeed||r.max(r.max(r.min(r.abs(this.scroller.x-i.x),1e3),r.min(r.abs(this.scroller.y-i.y),1e3)),300);this.scroller.x==i.x&&this.scroller.y==i.y||(this.scroller.directionX=0,this.scroller.directionY=0,this.scroller.currentPage=i,this.scroller.scrollTo(i.x,i.y,e,this.scroller.options.bounceEasing))}this.moved&&this.scroller._execEvent("scrollEnd")}},transitionTime:function(t){t=t||0;var i=a.style.transitionDuration;if(this.indicatorStyle[i]=t+"ms",!t&&a.isBadAndroid){this.indicatorStyle[i]="0.0001ms";var e=this;h(function(){"0.0001ms"===e.indicatorStyle[i]&&(e.indicatorStyle[i]="0s")})}},transitionTimingFunction:function(t){this.indicatorStyle[a.style.transitionTimingFunction]=t},refresh:function(){this.transitionTime(),this.options.listenX&&!this.options.listenY?this.indicatorStyle.display=this.scroller.hasHorizontalScroll?"block":"none":this.options.listenY&&!this.options.listenX?this.indicatorStyle.display=this.scroller.hasVerticalScroll?"block":"none":this.indicatorStyle.display=this.scroller.hasHorizontalScroll||this.scroller.hasVerticalScroll?"block":"none",this.scroller.hasHorizontalScroll&&this.scroller.hasVerticalScroll?(a.addClass(this.wrapper,"iScrollBothScrollbars"),a.removeClass(this.wrapper,"iScrollLoneScrollbar"),this.options.defaultScrollbars&&this.options.customStyle&&(this.options.listenX?this.wrapper.style.right="8px":this.wrapper.style.bottom="8px")):(a.removeClass(this.wrapper,"iScrollBothScrollbars"),a.addClass(this.wrapper,"iScrollLoneScrollbar"),this.options.defaultScrollbars&&this.options.customStyle&&(this.options.listenX?this.wrapper.style.right="2px":this.wrapper.style.bottom="2px"));this.wrapper.offsetHeight;this.options.listenX&&(this.wrapperWidth=this.wrapper.clientWidth,this.options.resize?(this.indicatorWidth=r.max(r.round(this.wrapperWidth*this.wrapperWidth/(this.scroller.scrollerWidth||this.wrapperWidth||1)),8),this.indicatorStyle.width=this.indicatorWidth+"px"):this.indicatorWidth=this.indicator.clientWidth,this.maxPosX=this.wrapperWidth-this.indicatorWidth,"clip"==this.options.shrink?(this.minBoundaryX=8-this.indicatorWidth,this.maxBoundaryX=this.wrapperWidth-8):(this.minBoundaryX=0,this.maxBoundaryX=this.maxPosX),this.sizeRatioX=this.options.speedRatioX||this.scroller.maxScrollX&&this.maxPosX/this.scroller.maxScrollX),this.options.listenY&&(this.wrapperHeight=this.wrapper.clientHeight,this.options.resize?(this.indicatorHeight=r.max(r.round(this.wrapperHeight*this.wrapperHeight/(this.scroller.scrollerHeight||this.wrapperHeight||1)),8),this.indicatorStyle.height=this.indicatorHeight+"px"):this.indicatorHeight=this.indicator.clientHeight,this.maxPosY=this.wrapperHeight-this.indicatorHeight,"clip"==this.options.shrink?(this.minBoundaryY=8-this.indicatorHeight,this.maxBoundaryY=this.wrapperHeight-8):(this.minBoundaryY=0,this.maxBoundaryY=this.maxPosY),this.maxPosY=this.wrapperHeight-this.indicatorHeight,this.sizeRatioY=this.options.speedRatioY||this.scroller.maxScrollY&&this.maxPosY/this.scroller.maxScrollY),this.updatePosition()},updatePosition:function(){var t=this.options.listenX&&r.round(this.sizeRatioX*this.scroller.x)||0,i=this.options.listenY&&r.round(this.sizeRatioY*this.scroller.y)||0;this.options.ignoreBoundaries||(tthis.maxBoundaryX?"scale"==this.options.shrink?(this.width=r.max(this.indicatorWidth-(t-this.maxPosX),8),this.indicatorStyle.width=this.width+"px",t=this.maxPosX+this.indicatorWidth-this.width):t=this.maxBoundaryX:"scale"==this.options.shrink&&this.width!=this.indicatorWidth&&(this.width=this.indicatorWidth,this.indicatorStyle.width=this.width+"px"),ithis.maxBoundaryY?"scale"==this.options.shrink?(this.height=r.max(this.indicatorHeight-3*(i-this.maxPosY),8),this.indicatorStyle.height=this.height+"px",i=this.maxPosY+this.indicatorHeight-this.height):i=this.maxBoundaryY:"scale"==this.options.shrink&&this.height!=this.indicatorHeight&&(this.height=this.indicatorHeight,this.indicatorStyle.height=this.height+"px")),this.x=t,this.y=i,this.scroller.options.useTransform?this.indicatorStyle[a.style.transform]="translate("+t+"px,"+i+"px)"+this.scroller.translateZ:(this.indicatorStyle.left=t+"px",this.indicatorStyle.top=i+"px")},_pos:function(t,i){t<0?t=0:t>this.maxPosX&&(t=this.maxPosX),i<0?i=0:i>this.maxPosY&&(i=this.maxPosY),t=this.options.listenX?r.round(t/this.sizeRatioX):this.scroller.x,i=this.options.listenY?r.round(i/this.sizeRatioY):this.scroller.y,this.scroller.scrollTo(t,i)},fade:function(t,i){if(!i||this.visible){clearTimeout(this.fadeTimeout),this.fadeTimeout=null;var e=t?250:500,s=t?0:300;t=t?"1":"0",this.wrapperStyle[a.style.transitionDuration]=e+"ms",this.fadeTimeout=setTimeout(function(t){this.wrapperStyle.opacity=t,this.visible=+t}.bind(this,t),s)}}},l.utils=a,void 0!==t&&t.exports?t.exports=l:void 0===(s=function(){return l}.call(i,e,i,t))||(t.exports=s)}(window,document,Math)},function(t,i){}])}); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | virtual scroll 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-virtual-infinite-scroll", 3 | "version": "0.2.5", 4 | "description": "vue virtual infinite scroll", 5 | "author": "zuolei ", 6 | "private": false, 7 | "main": "dist/vue-virtual-infinite-scroll.js", 8 | "license": "MIT", 9 | "scripts": { 10 | "dev": "webpack-dev-server --inline --progress --config build/demo.dev.conf.js", 11 | "start": "npm run dev", 12 | "unit": "jest --config test/unit/jest.conf.js --coverage", 13 | "test": "npm run unit", 14 | "lint": "eslint --ext .js,.vue src test/unit/specs", 15 | "build": "node build/build.js", 16 | "build-demo": "node build/build-demo.js" 17 | }, 18 | "peerDependencies": { 19 | "vue": "^2.5.2" 20 | }, 21 | "devDependencies": { 22 | "autoprefixer": "^7.1.2", 23 | "babel-core": "^6.22.1", 24 | "babel-eslint": "^7.1.1", 25 | "babel-jest": "^21.0.2", 26 | "babel-loader": "^7.1.1", 27 | "babel-plugin-transform-runtime": "^6.22.0", 28 | "babel-preset-env": "^1.3.2", 29 | "babel-preset-stage-2": "^6.22.0", 30 | "chalk": "^2.0.1", 31 | "copy-webpack-plugin": "^4.0.1", 32 | "css-loader": "^0.28.0", 33 | "eslint": "^3.19.0", 34 | "eslint-config-standard": "^10.2.1", 35 | "eslint-friendly-formatter": "^3.0.0", 36 | "eslint-loader": "^1.7.1", 37 | "eslint-plugin-html": "^3.0.0", 38 | "eslint-plugin-import": "^2.7.0", 39 | "eslint-plugin-node": "^5.2.0", 40 | "eslint-plugin-promise": "^3.4.0", 41 | "eslint-plugin-standard": "^3.0.1", 42 | "extract-text-webpack-plugin": "^3.0.0", 43 | "file-loader": "^1.1.4", 44 | "friendly-errors-webpack-plugin": "^1.6.1", 45 | "html-webpack-plugin": "^2.30.1", 46 | "jest": "^21.2.0", 47 | "jest-serializer-vue": "^0.3.0", 48 | "node-notifier": "^5.1.2", 49 | "normalizr": "^3.2.4", 50 | "optimize-css-assets-webpack-plugin": "^3.2.0", 51 | "ora": "^1.2.0", 52 | "portfinder": "^1.0.13", 53 | "postcss-cssnext": "^3.0.2", 54 | "postcss-import": "^11.0.0", 55 | "rimraf": "^2.6.0", 56 | "semver": "^5.3.0", 57 | "shelljs": "^0.7.6", 58 | "style-loader": "^0.16.1", 59 | "uglifyjs-webpack-plugin": "^1.1.1", 60 | "url-loader": "^0.5.8", 61 | "vue": "^2.5.2", 62 | "vue-jest": "^1.0.2", 63 | "vue-loader": "^13.3.0", 64 | "vue-property-decorator": "^6.0.0", 65 | "vue-style-loader": "^3.0.1", 66 | "vue-template-compiler": "^2.5.2", 67 | "webpack": "^3.6.0", 68 | "webpack-bundle-analyzer": "^2.9.0", 69 | "webpack-dev-server": "^2.9.1", 70 | "webpack-merge": "^4.1.0" 71 | }, 72 | "engines": { 73 | "node": ">= 4.0.0", 74 | "npm": ">= 3.0.0" 75 | }, 76 | "browserslist": [ 77 | "> 1%", 78 | "last 2 versions", 79 | "not ie <= 8" 80 | ] 81 | } 82 | -------------------------------------------------------------------------------- /src/assets/icon/iconfont.css: -------------------------------------------------------------------------------- 1 | 2 | @font-face {font-family: "iconfont"; 3 | src: url('iconfont.eot?t=1527419939127'); /* IE9*/ 4 | src: url('iconfont.eot?t=1527419939127#iefix') format('embedded-opentype'), /* IE6-IE8 */ 5 | url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAXwAAsAAAAACIQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFZW7kkUY21hcAAAAYAAAABxAAABsgRE1DRnbHlmAAAB9AAAAekAAAIgsnrM52hlYWQAAAPgAAAALwAAADYRgK49aGhlYQAABBAAAAAcAAAAJAfeA4ZobXR4AAAELAAAABMAAAAUE+kAAGxvY2EAAARAAAAADAAAAAwBQAGsbWF4cAAABEwAAAAeAAAAIAEUAF1uYW1lAAAEbAAAAUUAAAJtPlT+fXBvc3QAAAW0AAAAOgAAAEvQUZmjeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2Bk/s04gYGVgYOpk+kMAwNDP4RmfM1gxMjBwMDEwMrMgBUEpLmmMDgwVDxXZ27438AQw9zA0AAUZgTJAQAnTgyXeJzFkcENgCAQBOdAjTH24ccifFuLL1+UYKVYhi6cD63AvQzZ2xyBANACUcyiAdsxijalVvPIUPOGRf1AT1ClvObjnK5L2du7THNexUftDTIdv8n+O/qrsa7L0+nFSQ+6Yl6d8iP5cMrMOTmEG/JGF0QAAAB4nE2Qz2sTURDHZ97bt2/zutl1fySbbLr5tTZria50s0kOkvTixSIiSAWPHhUU1EMvHnopSOmhf4DpQQQPei1qUi/2H2gDHj2I/gM9lYBufQkIDjNfZmAYPt8BBnDxgx7REjhwBdbgJtwFQLWNTYME2IjSmLSx0GAFzzVoFEYNHjZjOkCvqbrFpJe2PJWrJhpYxU4j6UUxibCbDskNTIoBYrni37NXlm26j6IUVXeyDfIGC7Vw2Rxey25dXXeTuqNt6bZdtu09TWVMI0QxDXziFXMsJ9TsLTP9wlFtldRQL0f+7Qf5esV++Cp9Gqx4OcTtbXQqdePduuVbMl/6Rccu80t5reTnw8subv1aKjl60PoJMqj0+o2+p21YAlP6BYnNq+gNsR8jDbudbmh1CByeMXZ2uNDd+zJo+98o9c/O5ibKW7IuPtBn9A6UAHLYanKcP6SP1vwtXQtlP0T6OHvNLS0bcdPiOMg7eexpFtcJfsdHmpbtc8vkuPH7WOi6oP3smHPNWXB+pR9pR3J6sArAYowkpEQ1kP7H7PA1tXkdW2kvqWG/lxRdgpNzxs4n47l+GZ0qyuloofGJqIpd4Qbi+ScRuANlNhnPFGU2nsxopExHB/Olg9E0O5kKsSc3xIvPwqn+Bf0bco0AAAB4nGNgZGBgAOKUNJ+J8fw2Xxm4WRhA4LrBVmUE/X8NCwOzH5DLwcAEEgUACBUJIAB4nGNgZGBgbvjfwBDDwgACQJKRARWwAgBHCwJueJxjYWBgYH7JwMDCgMAADpsA/QAAAAAAAHYAnADKARB4nGNgZGBgYGUIBGIQYAJiLiBkYPgP5jMAABEtAXIAAHicZY9NTsMwEIVf+gekEqqoYIfkBWIBKP0Rq25YVGr3XXTfpk6bKokjx63UA3AejsAJOALcgDvwSCebNpbH37x5Y08A3OAHHo7fLfeRPVwyO3INF7gXrlN/EG6QX4SbaONVuEX9TdjHM6bCbXRheYPXuGL2hHdhDx18CNdwjU/hOvUv4Qb5W7iJO/wKt9Dx6sI+5l5XuI1HL/bHVi+cXqnlQcWhySKTOb+CmV7vkoWt0uqca1vEJlODoF9JU51pW91T7NdD5yIVWZOqCas6SYzKrdnq0AUb5/JRrxeJHoQm5Vhj/rbGAo5xBYUlDowxQhhkiMro6DtVZvSvsUPCXntWPc3ndFsU1P9zhQEC9M9cU7qy0nk6T4E9XxtSdXQrbsuelDSRXs1JErJCXta2VELqATZlV44RelzRiT8oZ0j/AAlabsgAAAB4nGNgYoAALgbsgJWRiZGZkYWRlZGNgbGCNbWoKL+IozgjMS89LTGPqzKzPDEvOSM1L52BAQCmUgpYAAA=') format('woff'), 6 | url('iconfont.ttf?t=1527419939127') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ 7 | url('iconfont.svg?t=1527419939127#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .iconfont { 11 | font-family:"iconfont" !important; 12 | font-size:16px; 13 | font-style:normal; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | 18 | .icon-error:before { content: "\e727"; } 19 | 20 | .icon-pulldown:before { content: "\e64a"; } 21 | 22 | .icon-complete:before { content: "\e688"; } 23 | 24 | -------------------------------------------------------------------------------- /src/assets/icon/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zuolei828/vue-virtual-infinite-scroll/f40f50a6be95f1bda407b3997bb00e8d5618a9d8/src/assets/icon/iconfont.eot -------------------------------------------------------------------------------- /src/assets/icon/iconfont.js: -------------------------------------------------------------------------------- 1 | (function(window){var svgSprite='';var script=function(){var scripts=document.getElementsByTagName("script");return scripts[scripts.length-1]}();var shouldInjectCss=script.getAttribute("data-injectcss");var ready=function(fn){if(document.addEventListener){if(~["complete","loaded","interactive"].indexOf(document.readyState)){setTimeout(fn,0)}else{var loadFn=function(){document.removeEventListener("DOMContentLoaded",loadFn,false);fn()};document.addEventListener("DOMContentLoaded",loadFn,false)}}else if(document.attachEvent){IEContentLoaded(window,fn)}function IEContentLoaded(w,fn){var d=w.document,done=false,init=function(){if(!done){done=true;fn()}};var polling=function(){try{d.documentElement.doScroll("left")}catch(e){setTimeout(polling,50);return}init()};polling();d.onreadystatechange=function(){if(d.readyState=="complete"){d.onreadystatechange=null;init()}}}};var before=function(el,target){target.parentNode.insertBefore(el,target)};var prepend=function(el,target){if(target.firstChild){before(el,target.firstChild)}else{target.appendChild(el)}};function appendSvg(){var div,svg;div=document.createElement("div");div.innerHTML=svgSprite;svgSprite=null;svg=div.getElementsByTagName("svg")[0];if(svg){svg.setAttribute("aria-hidden","true");svg.style.position="absolute";svg.style.width=0;svg.style.height=0;svg.style.overflow="hidden";prepend(svg,document.body)}}if(shouldInjectCss&&!window.__iconfont__svg__cssinject__){window.__iconfont__svg__cssinject__=true;try{document.write("")}catch(e){console&&console.log(e)}}ready(appendSvg)})(window) -------------------------------------------------------------------------------- /src/assets/icon/iconfont.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Created by iconfont 9 | 10 | 11 | 12 | 13 | 21 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/assets/icon/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zuolei828/vue-virtual-infinite-scroll/f40f50a6be95f1bda407b3997bb00e8d5618a9d8/src/assets/icon/iconfont.ttf -------------------------------------------------------------------------------- /src/assets/icon/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zuolei828/vue-virtual-infinite-scroll/f40f50a6be95f1bda407b3997bb00e8d5618a9d8/src/assets/icon/iconfont.woff -------------------------------------------------------------------------------- /src/component/VirtualScroll.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{pullText}} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 加载中... 22 | 23 | 24 | 25 | 26 | 27 | 28 | 390 | 482 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import VirtualScroll from './component/VirtualScroll' 2 | 3 | export default VirtualScroll 4 | -------------------------------------------------------------------------------- /src/iscroll-probe.js: -------------------------------------------------------------------------------- 1 | /*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */ 2 | (function (window, document, Math) { 3 | var rAF = window.requestAnimationFrame || 4 | window.webkitRequestAnimationFrame || 5 | window.mozRequestAnimationFrame || 6 | window.oRequestAnimationFrame || 7 | window.msRequestAnimationFrame || 8 | function (callback) { window.setTimeout(callback, 1000 / 60); }; 9 | 10 | var utils = (function () { 11 | var me = {}; 12 | 13 | var _elementStyle = document.createElement('div').style; 14 | var _vendor = (function () { 15 | var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'], 16 | transform, 17 | i = 0, 18 | l = vendors.length; 19 | 20 | for ( ; i < l; i++ ) { 21 | transform = vendors[i] + 'ransform'; 22 | if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1); 23 | } 24 | 25 | return false; 26 | })(); 27 | 28 | function _prefixStyle (style) { 29 | if ( _vendor === false ) return false; 30 | if ( _vendor === '' ) return style; 31 | return _vendor + style.charAt(0).toUpperCase() + style.substr(1); 32 | } 33 | 34 | me.getTime = Date.now || function getTime () { return new Date().getTime(); }; 35 | 36 | me.extend = function (target, obj) { 37 | for ( var i in obj ) { 38 | target[i] = obj[i]; 39 | } 40 | }; 41 | 42 | me.addEvent = function (el, type, fn, capture) { 43 | el.addEventListener(type, fn, !!capture); 44 | }; 45 | 46 | me.removeEvent = function (el, type, fn, capture) { 47 | el.removeEventListener(type, fn, !!capture); 48 | }; 49 | 50 | me.prefixPointerEvent = function (pointerEvent) { 51 | return window.MSPointerEvent ? 52 | 'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8): 53 | pointerEvent; 54 | }; 55 | 56 | me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) { 57 | var distance = current - start, 58 | speed = Math.abs(distance) / time, 59 | destination, 60 | duration; 61 | 62 | deceleration = deceleration === undefined ? 0.0006 : deceleration; 63 | 64 | destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); 65 | duration = speed / deceleration; 66 | 67 | if ( destination < lowerMargin ) { 68 | destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; 69 | distance = Math.abs(destination - current); 70 | duration = distance / speed; 71 | } else if ( destination > 0 ) { 72 | destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; 73 | distance = Math.abs(current) + destination; 74 | duration = distance / speed; 75 | } 76 | 77 | return { 78 | destination: Math.round(destination), 79 | duration: duration 80 | }; 81 | }; 82 | 83 | var _transform = _prefixStyle('transform'); 84 | 85 | me.extend(me, { 86 | hasTransform: _transform !== false, 87 | hasPerspective: _prefixStyle('perspective') in _elementStyle, 88 | hasTouch: 'ontouchstart' in window, 89 | hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed 90 | hasTransition: _prefixStyle('transition') in _elementStyle 91 | }); 92 | 93 | /* 94 | This should find all Android browsers lower than build 535.19 (both stock browser and webview) 95 | - galaxy S2 is ok 96 | - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1` 97 | - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 98 | - galaxy S3 is badAndroid (stock brower, webview) 99 | `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 100 | - galaxy S4 is badAndroid (stock brower, webview) 101 | `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 102 | - galaxy S5 is OK 103 | `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` 104 | - galaxy S6 is OK 105 | `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` 106 | */ 107 | me.isBadAndroid = (function() { 108 | var appVersion = window.navigator.appVersion; 109 | // Android browser is not a chrome browser. 110 | if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) { 111 | var safariVersion = appVersion.match(/Safari\/(\d+.\d)/); 112 | if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) { 113 | return parseFloat(safariVersion[1]) < 535.19; 114 | } else { 115 | return true; 116 | } 117 | } else { 118 | return false; 119 | } 120 | })(); 121 | 122 | me.extend(me.style = {}, { 123 | transform: _transform, 124 | transitionTimingFunction: _prefixStyle('transitionTimingFunction'), 125 | transitionDuration: _prefixStyle('transitionDuration'), 126 | transitionDelay: _prefixStyle('transitionDelay'), 127 | transformOrigin: _prefixStyle('transformOrigin') 128 | }); 129 | 130 | me.hasClass = function (e, c) { 131 | var re = new RegExp("(^|\\s)" + c + "(\\s|$)"); 132 | return re.test(e.className); 133 | }; 134 | 135 | me.addClass = function (e, c) { 136 | if ( me.hasClass(e, c) ) { 137 | return; 138 | } 139 | 140 | var newclass = e.className.split(' '); 141 | newclass.push(c); 142 | e.className = newclass.join(' '); 143 | }; 144 | 145 | me.removeClass = function (e, c) { 146 | if ( !me.hasClass(e, c) ) { 147 | return; 148 | } 149 | 150 | var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g'); 151 | e.className = e.className.replace(re, ' '); 152 | }; 153 | 154 | me.offset = function (el) { 155 | var left = -el.offsetLeft, 156 | top = -el.offsetTop; 157 | 158 | // jshint -W084 159 | while (el = el.offsetParent) { 160 | left -= el.offsetLeft; 161 | top -= el.offsetTop; 162 | } 163 | // jshint +W084 164 | 165 | return { 166 | left: left, 167 | top: top 168 | }; 169 | }; 170 | 171 | me.preventDefaultException = function (el, exceptions) { 172 | for ( var i in exceptions ) { 173 | if ( exceptions[i].test(el[i]) ) { 174 | return true; 175 | } 176 | } 177 | 178 | return false; 179 | }; 180 | 181 | me.extend(me.eventType = {}, { 182 | touchstart: 1, 183 | touchmove: 1, 184 | touchend: 1, 185 | 186 | mousedown: 2, 187 | mousemove: 2, 188 | mouseup: 2, 189 | 190 | pointerdown: 3, 191 | pointermove: 3, 192 | pointerup: 3, 193 | 194 | MSPointerDown: 3, 195 | MSPointerMove: 3, 196 | MSPointerUp: 3 197 | }); 198 | 199 | me.extend(me.ease = {}, { 200 | quadratic: { 201 | style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', 202 | fn: function (k) { 203 | return k * ( 2 - k ); 204 | } 205 | }, 206 | circular: { 207 | style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1) 208 | fn: function (k) { 209 | return Math.sqrt( 1 - ( --k * k ) ); 210 | } 211 | }, 212 | back: { 213 | style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)', 214 | fn: function (k) { 215 | var b = 4; 216 | return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1; 217 | } 218 | }, 219 | bounce: { 220 | style: '', 221 | fn: function (k) { 222 | if ( ( k /= 1 ) < ( 1 / 2.75 ) ) { 223 | return 7.5625 * k * k; 224 | } else if ( k < ( 2 / 2.75 ) ) { 225 | return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75; 226 | } else if ( k < ( 2.5 / 2.75 ) ) { 227 | return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375; 228 | } else { 229 | return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375; 230 | } 231 | } 232 | }, 233 | elastic: { 234 | style: '', 235 | fn: function (k) { 236 | var f = 0.22, 237 | e = 0.4; 238 | 239 | if ( k === 0 ) { return 0; } 240 | if ( k == 1 ) { return 1; } 241 | 242 | return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 ); 243 | } 244 | } 245 | }); 246 | 247 | me.tap = function (e, eventName) { 248 | var ev = document.createEvent('Event'); 249 | ev.initEvent(eventName, true, true); 250 | ev.pageX = e.pageX; 251 | ev.pageY = e.pageY; 252 | e.target.dispatchEvent(ev); 253 | }; 254 | 255 | me.click = function (e) { 256 | var target = e.target, 257 | ev; 258 | 259 | if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) { 260 | ev = document.createEvent('MouseEvents'); 261 | ev.initMouseEvent('click', true, true, e.view, 1, 262 | target.screenX, target.screenY, target.clientX, target.clientY, 263 | e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, 264 | 0, null); 265 | 266 | ev._constructed = true; 267 | target.dispatchEvent(ev); 268 | } 269 | }; 270 | 271 | return me; 272 | })(); 273 | function IScroll (el, options) { 274 | this.wrapper = typeof el == 'string' ? document.querySelector(el) : el; 275 | this.scroller = this.wrapper.children[0]; 276 | this.scrollerStyle = this.scroller.style; // cache style for better performance 277 | 278 | this.options = { 279 | 280 | resizeScrollbars: true, 281 | 282 | mouseWheelSpeed: 20, 283 | 284 | snapThreshold: 0.334, 285 | 286 | // INSERT POINT: OPTIONS 287 | disablePointer : !utils.hasPointer, 288 | disableTouch : utils.hasPointer || !utils.hasTouch, 289 | disableMouse : utils.hasPointer || utils.hasTouch, 290 | startX: 0, 291 | startY: 0, 292 | scrollY: true, 293 | directionLockThreshold: 5, 294 | momentum: true, 295 | 296 | bounce: true, 297 | bounceTime: 600, 298 | bounceEasing: '', 299 | 300 | preventDefault: true, 301 | preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/ }, 302 | 303 | HWCompositing: true, 304 | useTransition: true, 305 | useTransform: true, 306 | bindToWrapper: typeof window.onmousedown === "undefined" 307 | }; 308 | 309 | for ( var i in options ) { 310 | this.options[i] = options[i]; 311 | } 312 | 313 | // Normalize options 314 | this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : ''; 315 | 316 | this.options.useTransition = utils.hasTransition && this.options.useTransition; 317 | this.options.useTransform = utils.hasTransform && this.options.useTransform; 318 | 319 | this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough; 320 | this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault; 321 | 322 | // If you want eventPassthrough I have to lock one of the axes 323 | this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY; 324 | this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX; 325 | 326 | // With eventPassthrough we also need lockDirection mechanism 327 | this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough; 328 | this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold; 329 | 330 | this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing; 331 | 332 | this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling; 333 | 334 | if ( this.options.tap === true ) { 335 | this.options.tap = 'tap'; 336 | } 337 | 338 | if ( this.options.shrinkScrollbars == 'scale' ) { 339 | this.options.useTransition = false; 340 | } 341 | 342 | this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1; 343 | 344 | if ( this.options.probeType == 3 ) { 345 | this.options.useTransition = false; } 346 | 347 | // INSERT POINT: NORMALIZATION 348 | 349 | // Some defaults 350 | this.x = 0; 351 | this.y = 0; 352 | this.directionX = 0; 353 | this.directionY = 0; 354 | this._events = {}; 355 | 356 | // INSERT POINT: DEFAULTS 357 | 358 | this._init(); 359 | this.refresh(); 360 | 361 | this.scrollTo(this.options.startX, this.options.startY); 362 | this.enable(); 363 | } 364 | 365 | IScroll.prototype = { 366 | version: '5.2.0', 367 | 368 | _init: function () { 369 | this._initEvents(); 370 | 371 | if ( this.options.scrollbars || this.options.indicators ) { 372 | this._initIndicators(); 373 | } 374 | 375 | if ( this.options.mouseWheel ) { 376 | this._initWheel(); 377 | } 378 | 379 | if ( this.options.snap ) { 380 | this._initSnap(); 381 | } 382 | 383 | if ( this.options.keyBindings ) { 384 | this._initKeys(); 385 | } 386 | 387 | // INSERT POINT: _init 388 | 389 | }, 390 | 391 | destroy: function () { 392 | this._initEvents(true); 393 | clearTimeout(this.resizeTimeout); 394 | this.resizeTimeout = null; 395 | this._execEvent('destroy'); 396 | }, 397 | 398 | _transitionEnd: function (e) { 399 | if ( e.target != this.scroller || !this.isInTransition ) { 400 | return; 401 | } 402 | 403 | this._transitionTime(); 404 | if ( !this.resetPosition(this.options.bounceTime) ) { 405 | this.isInTransition = false; 406 | this._execEvent('scrollEnd'); 407 | } 408 | }, 409 | 410 | _start: function (e) { 411 | // React to left mouse button only 412 | if ( utils.eventType[e.type] != 1 ) { 413 | // for button property 414 | // http://unixpapa.com/js/mouse.html 415 | var button; 416 | if (!e.which) { 417 | /* IE case */ 418 | button = (e.button < 2) ? 0 : 419 | ((e.button == 4) ? 1 : 2); 420 | } else { 421 | /* All others */ 422 | button = e.button; 423 | } 424 | if ( button !== 0 ) { 425 | return; 426 | } 427 | } 428 | 429 | if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) { 430 | return; 431 | } 432 | 433 | if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { 434 | e.preventDefault(); 435 | } 436 | 437 | var point = e.touches ? e.touches[0] : e, 438 | pos; 439 | 440 | this.initiated = utils.eventType[e.type]; 441 | this.moved = false; 442 | this.distX = 0; 443 | this.distY = 0; 444 | this.directionX = 0; 445 | this.directionY = 0; 446 | this.directionLocked = 0; 447 | 448 | this.startTime = utils.getTime(); 449 | 450 | if ( this.options.useTransition && this.isInTransition ) { 451 | this._transitionTime(); 452 | this.isInTransition = false; 453 | pos = this.getComputedPosition(); 454 | this._translate(Math.round(pos.x), Math.round(pos.y)); 455 | this._execEvent('scrollEnd'); 456 | } else if ( !this.options.useTransition && this.isAnimating ) { 457 | this.isAnimating = false; 458 | this._execEvent('scrollEnd'); 459 | } 460 | 461 | this.startX = this.x; 462 | this.startY = this.y; 463 | this.absStartX = this.x; 464 | this.absStartY = this.y; 465 | this.pointX = point.pageX; 466 | this.pointY = point.pageY; 467 | 468 | this._execEvent('beforeScrollStart'); 469 | }, 470 | 471 | _move: function (e) { 472 | if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { 473 | return; 474 | } 475 | 476 | if ( this.options.preventDefault ) { // increases performance on Android? TODO: check! 477 | e.preventDefault(); 478 | } 479 | 480 | var point = e.touches ? e.touches[0] : e, 481 | deltaX = point.pageX - this.pointX, 482 | deltaY = point.pageY - this.pointY, 483 | timestamp = utils.getTime(), 484 | newX, newY, 485 | absDistX, absDistY; 486 | 487 | this.pointX = point.pageX; 488 | this.pointY = point.pageY; 489 | 490 | this.distX += deltaX; 491 | this.distY += deltaY; 492 | absDistX = Math.abs(this.distX); 493 | absDistY = Math.abs(this.distY); 494 | 495 | // We need to move at least 10 pixels for the scrolling to initiate 496 | if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) { 497 | return; 498 | } 499 | 500 | // If you are scrolling in one direction lock the other 501 | if ( !this.directionLocked && !this.options.freeScroll ) { 502 | if ( absDistX > absDistY + this.options.directionLockThreshold ) { 503 | this.directionLocked = 'h'; // lock horizontally 504 | } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) { 505 | this.directionLocked = 'v'; // lock vertically 506 | } else { 507 | this.directionLocked = 'n'; // no lock 508 | } 509 | } 510 | 511 | if ( this.directionLocked == 'h' ) { 512 | if ( this.options.eventPassthrough == 'vertical' ) { 513 | e.preventDefault(); 514 | } else if ( this.options.eventPassthrough == 'horizontal' ) { 515 | this.initiated = false; 516 | return; 517 | } 518 | 519 | deltaY = 0; 520 | } else if ( this.directionLocked == 'v' ) { 521 | if ( this.options.eventPassthrough == 'horizontal' ) { 522 | e.preventDefault(); 523 | } else if ( this.options.eventPassthrough == 'vertical' ) { 524 | this.initiated = false; 525 | return; 526 | } 527 | 528 | deltaX = 0; 529 | } 530 | 531 | deltaX = this.hasHorizontalScroll ? deltaX : 0; 532 | deltaY = this.hasVerticalScroll ? deltaY : 0; 533 | 534 | newX = this.x + deltaX; 535 | newY = this.y + deltaY; 536 | 537 | // Slow down if outside of the boundaries 538 | if ( newX > 0 || newX < this.maxScrollX ) { 539 | newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX; 540 | } 541 | 542 | if ( newY > 0 || newY < this.maxScrollY ) { 543 | newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY; 544 | } 545 | 546 | this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; 547 | this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; 548 | 549 | if ( !this.moved ) { 550 | this._execEvent('scrollStart'); 551 | } 552 | 553 | this.moved = true; 554 | this._translate(newX, newY); 555 | 556 | /* REPLACE START: _move */ 557 | if ( timestamp - this.startTime > 300 ) { 558 | this.startTime = timestamp; 559 | this.startX = this.x; 560 | this.startY = this.y; 561 | 562 | if ( this.options.probeType == 1 ) { 563 | this._execEvent('scroll'); 564 | } 565 | } 566 | if ( this.options.probeType > 1 ) { 567 | this._execEvent('scroll'); 568 | } 569 | /* REPLACE END: _move */ 570 | 571 | }, 572 | 573 | _end: function (e) { 574 | if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { 575 | return; 576 | } 577 | 578 | if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { 579 | e.preventDefault(); 580 | } 581 | 582 | var point = e.changedTouches ? e.changedTouches[0] : e, 583 | momentumX, 584 | momentumY, 585 | duration = utils.getTime() - this.startTime, 586 | newX = Math.round(this.x), 587 | newY = Math.round(this.y), 588 | distanceX = Math.abs(newX - this.startX), 589 | distanceY = Math.abs(newY - this.startY), 590 | time = 0, 591 | easing = ''; 592 | 593 | this.isInTransition = 0; 594 | this.initiated = 0; 595 | this.endTime = utils.getTime(); 596 | 597 | // reset if we are outside of the boundaries 598 | if ( this.resetPosition(this.options.bounceTime) ) { 599 | if (this.y > 0) { 600 | this._execEvent('pullDownEnd'); 601 | } 602 | return; 603 | } 604 | 605 | this.scrollTo(newX, newY); // ensures that the last position is rounded 606 | 607 | // we scrolled less than 10 pixels 608 | if ( !this.moved ) { 609 | if ( this.options.tap ) { 610 | utils.tap(e, this.options.tap); 611 | } 612 | 613 | if ( this.options.click ) { 614 | utils.click(e); 615 | } 616 | 617 | this._execEvent('scrollCancel'); 618 | return; 619 | } 620 | 621 | if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) { 622 | this._execEvent('flick'); 623 | return; 624 | } 625 | 626 | // start momentum animation if needed 627 | if ( this.options.momentum && duration < 300 ) { 628 | momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration) : { destination: newX, duration: 0 }; 629 | momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { destination: newY, duration: 0 }; 630 | newX = momentumX.destination; 631 | newY = momentumY.destination; 632 | time = Math.max(momentumX.duration, momentumY.duration); 633 | this.isInTransition = 1; 634 | } 635 | 636 | 637 | if ( this.options.snap ) { 638 | var snap = this._nearestSnap(newX, newY); 639 | this.currentPage = snap; 640 | time = this.options.snapSpeed || Math.max( 641 | Math.max( 642 | Math.min(Math.abs(newX - snap.x), 1000), 643 | Math.min(Math.abs(newY - snap.y), 1000) 644 | ), 300); 645 | newX = snap.x; 646 | newY = snap.y; 647 | 648 | this.directionX = 0; 649 | this.directionY = 0; 650 | easing = this.options.bounceEasing; 651 | } 652 | 653 | // INSERT POINT: _end 654 | 655 | if ( newY > 0 ) { 656 | newY = 0; 657 | } 658 | 659 | if ( newX != this.x || newY != this.y ) { 660 | // change easing function when scroller goes out of the boundaries 661 | if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) { 662 | easing = utils.ease.quadratic; 663 | } 664 | 665 | this.scrollTo(newX, newY, time, easing); 666 | return; 667 | } 668 | 669 | this._execEvent('scrollEnd'); 670 | }, 671 | 672 | _resize: function () { 673 | var that = this; 674 | 675 | clearTimeout(this.resizeTimeout); 676 | 677 | this.resizeTimeout = setTimeout(function () { 678 | that.refresh(); 679 | }, this.options.resizePolling); 680 | }, 681 | 682 | resetPosition: function (time) { 683 | var x = this.x, 684 | y = this.y; 685 | 686 | time = time || 0; 687 | 688 | if ( !this.hasHorizontalScroll || this.x > 0 ) { 689 | x = 0; 690 | } else if ( this.x < this.maxScrollX ) { 691 | x = this.maxScrollX; 692 | } 693 | 694 | if ( !this.hasVerticalScroll || this.y > 0 ) { 695 | y = 0; 696 | } else if ( this.y < this.maxScrollY ) { 697 | y = this.maxScrollY; 698 | } 699 | 700 | if ( this.pullerHeight && this.y > 0) { 701 | y = this.pullerHeight 702 | } 703 | 704 | if ( x == this.x && y == this.y ) { 705 | return false; 706 | } 707 | 708 | this.scrollTo(x, y, time, this.options.bounceEasing); 709 | 710 | return true; 711 | }, 712 | 713 | disable: function () { 714 | this.enabled = false; 715 | }, 716 | 717 | enable: function () { 718 | this.enabled = true; 719 | }, 720 | 721 | refresh: function (time) { 722 | var rf = this.wrapper.offsetHeight; // Force reflow 723 | 724 | this.wrapperWidth = this.wrapper.clientWidth; 725 | this.wrapperHeight = this.wrapper.clientHeight; 726 | 727 | /* REPLACE START: refresh */ 728 | 729 | this.scrollerWidth = this.scroller.offsetWidth; 730 | // this.scrollerHeight = this.scroller.offsetHeight; 731 | 732 | this.maxScrollX = this.wrapperWidth - this.scrollerWidth; 733 | // this.maxScrollY = this.wrapperHeight - this.scrollerHeight; 734 | 735 | /* REPLACE END: refresh */ 736 | 737 | this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0; 738 | this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0; 739 | 740 | if ( !this.hasHorizontalScroll ) { 741 | this.maxScrollX = 0; 742 | this.scrollerWidth = this.wrapperWidth; 743 | } 744 | 745 | if ( !this.hasVerticalScroll ) { 746 | this.maxScrollY = 0; 747 | this.scrollerHeight = this.wrapperHeight; 748 | } 749 | 750 | this.endTime = 0; 751 | this.directionX = 0; 752 | this.directionY = 0; 753 | 754 | this.wrapperOffset = utils.offset(this.wrapper); 755 | 756 | this._execEvent('refresh'); 757 | 758 | this.resetPosition(time); 759 | 760 | // INSERT POINT: _refresh 761 | 762 | }, 763 | 764 | on: function (type, fn) { 765 | if ( !this._events[type] ) { 766 | this._events[type] = []; 767 | } 768 | 769 | this._events[type].push(fn); 770 | }, 771 | 772 | off: function (type, fn) { 773 | if ( !this._events[type] ) { 774 | return; 775 | } 776 | 777 | var index = this._events[type].indexOf(fn); 778 | 779 | if ( index > -1 ) { 780 | this._events[type].splice(index, 1); 781 | } 782 | }, 783 | 784 | _execEvent: function (type) { 785 | if ( !this._events[type] ) { 786 | return; 787 | } 788 | 789 | var i = 0, 790 | l = this._events[type].length; 791 | 792 | if ( !l ) { 793 | return; 794 | } 795 | 796 | for ( ; i < l; i++ ) { 797 | this._events[type][i].apply(this, [].slice.call(arguments, 1)); 798 | } 799 | }, 800 | 801 | scrollBy: function (x, y, time, easing) { 802 | x = this.x + x; 803 | y = this.y + y; 804 | time = time || 0; 805 | 806 | this.scrollTo(x, y, time, easing); 807 | }, 808 | 809 | scrollTo: function (x, y, time, easing) { 810 | easing = easing || utils.ease.circular; 811 | 812 | this.isInTransition = this.options.useTransition && time > 0; 813 | var transitionType = this.options.useTransition && easing.style; 814 | if ( !time || transitionType ) { 815 | if(transitionType) { 816 | this._transitionTimingFunction(easing.style); 817 | this._transitionTime(time); 818 | } 819 | this._translate(x, y); 820 | } else { 821 | this._animate(x, y, time, easing.fn); 822 | } 823 | }, 824 | 825 | scrollToElement: function (el, time, offsetX, offsetY, easing) { 826 | el = el.nodeType ? el : this.scroller.querySelector(el); 827 | 828 | if ( !el ) { 829 | return; 830 | } 831 | 832 | var pos = utils.offset(el); 833 | 834 | pos.left -= this.wrapperOffset.left; 835 | pos.top -= this.wrapperOffset.top; 836 | 837 | // if offsetX/Y are true we center the element to the screen 838 | if ( offsetX === true ) { 839 | offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2); 840 | } 841 | if ( offsetY === true ) { 842 | offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2); 843 | } 844 | 845 | pos.left -= offsetX || 0; 846 | pos.top -= offsetY || 0; 847 | 848 | pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left; 849 | pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top; 850 | 851 | time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time; 852 | 853 | this.scrollTo(pos.left, pos.top, time, easing); 854 | }, 855 | 856 | _transitionTime: function (time) { 857 | time = time || 0; 858 | 859 | var durationProp = utils.style.transitionDuration; 860 | this.scrollerStyle[durationProp] = time + 'ms'; 861 | 862 | if ( !time && utils.isBadAndroid ) { 863 | this.scrollerStyle[durationProp] = '0.0001ms'; 864 | // remove 0.0001ms 865 | var self = this; 866 | rAF(function() { 867 | if(self.scrollerStyle[durationProp] === '0.0001ms') { 868 | self.scrollerStyle[durationProp] = '0s'; 869 | } 870 | }); 871 | } 872 | 873 | 874 | if ( this.indicators ) { 875 | for ( var i = this.indicators.length; i--; ) { 876 | this.indicators[i].transitionTime(time); 877 | } 878 | } 879 | 880 | 881 | // INSERT POINT: _transitionTime 882 | 883 | }, 884 | 885 | _transitionTimingFunction: function (easing) { 886 | this.scrollerStyle[utils.style.transitionTimingFunction] = easing; 887 | 888 | 889 | if ( this.indicators ) { 890 | for ( var i = this.indicators.length; i--; ) { 891 | this.indicators[i].transitionTimingFunction(easing); 892 | } 893 | } 894 | 895 | 896 | // INSERT POINT: _transitionTimingFunction 897 | 898 | }, 899 | 900 | _translate: function (x, y) { 901 | if ( this.options.useTransform ) { 902 | 903 | /* REPLACE START: _translate */ 904 | 905 | this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; 906 | 907 | /* REPLACE END: _translate */ 908 | 909 | } else { 910 | x = Math.round(x); 911 | y = Math.round(y); 912 | this.scrollerStyle.left = x + 'px'; 913 | this.scrollerStyle.top = y + 'px'; 914 | } 915 | 916 | this.x = x; 917 | this.y = y; 918 | 919 | 920 | if ( this.indicators ) { 921 | for ( var i = this.indicators.length; i--; ) { 922 | this.indicators[i].updatePosition(); 923 | } 924 | } 925 | 926 | 927 | // INSERT POINT: _translate 928 | 929 | }, 930 | 931 | _initEvents: function (remove) { 932 | var eventType = remove ? utils.removeEvent : utils.addEvent, 933 | target = this.options.bindToWrapper ? this.wrapper : window; 934 | 935 | eventType(window, 'orientationchange', this); 936 | eventType(window, 'resize', this); 937 | 938 | if ( this.options.click ) { 939 | eventType(this.wrapper, 'click', this, true); 940 | } 941 | 942 | if ( !this.options.disableMouse ) { 943 | eventType(this.wrapper, 'mousedown', this); 944 | eventType(target, 'mousemove', this); 945 | eventType(target, 'mousecancel', this); 946 | eventType(target, 'mouseup', this); 947 | } 948 | 949 | if ( utils.hasPointer && !this.options.disablePointer ) { 950 | eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this); 951 | eventType(target, utils.prefixPointerEvent('pointermove'), this); 952 | eventType(target, utils.prefixPointerEvent('pointercancel'), this); 953 | eventType(target, utils.prefixPointerEvent('pointerup'), this); 954 | } 955 | 956 | if ( utils.hasTouch && !this.options.disableTouch ) { 957 | eventType(this.wrapper, 'touchstart', this); 958 | eventType(target, 'touchmove', this); 959 | eventType(target, 'touchcancel', this); 960 | eventType(target, 'touchend', this); 961 | } 962 | 963 | eventType(this.scroller, 'transitionend', this); 964 | eventType(this.scroller, 'webkitTransitionEnd', this); 965 | eventType(this.scroller, 'oTransitionEnd', this); 966 | eventType(this.scroller, 'MSTransitionEnd', this); 967 | }, 968 | 969 | getComputedPosition: function () { 970 | var matrix = window.getComputedStyle(this.scroller, null), 971 | x, y; 972 | 973 | if ( this.options.useTransform ) { 974 | matrix = matrix[utils.style.transform].split(')')[0].split(', '); 975 | x = +(matrix[12] || matrix[4]); 976 | y = +(matrix[13] || matrix[5]); 977 | } else { 978 | x = +matrix.left.replace(/[^-\d.]/g, ''); 979 | y = +matrix.top.replace(/[^-\d.]/g, ''); 980 | } 981 | 982 | return { x: x, y: y }; 983 | }, 984 | _initIndicators: function () { 985 | var interactive = this.options.interactiveScrollbars, 986 | customStyle = typeof this.options.scrollbars != 'string', 987 | indicators = [], 988 | indicator; 989 | 990 | var that = this; 991 | 992 | this.indicators = []; 993 | 994 | if ( this.options.scrollbars ) { 995 | // Vertical scrollbar 996 | if ( this.options.scrollY ) { 997 | indicator = { 998 | el: createDefaultScrollbar('v', interactive, this.options.scrollbars), 999 | interactive: interactive, 1000 | defaultScrollbars: true, 1001 | customStyle: customStyle, 1002 | resize: this.options.resizeScrollbars, 1003 | shrink: this.options.shrinkScrollbars, 1004 | fade: this.options.fadeScrollbars, 1005 | listenX: false 1006 | }; 1007 | 1008 | this.wrapper.appendChild(indicator.el); 1009 | indicators.push(indicator); 1010 | } 1011 | 1012 | // Horizontal scrollbar 1013 | if ( this.options.scrollX ) { 1014 | indicator = { 1015 | el: createDefaultScrollbar('h', interactive, this.options.scrollbars), 1016 | interactive: interactive, 1017 | defaultScrollbars: true, 1018 | customStyle: customStyle, 1019 | resize: this.options.resizeScrollbars, 1020 | shrink: this.options.shrinkScrollbars, 1021 | fade: this.options.fadeScrollbars, 1022 | listenY: false 1023 | }; 1024 | 1025 | this.wrapper.appendChild(indicator.el); 1026 | indicators.push(indicator); 1027 | } 1028 | } 1029 | 1030 | if ( this.options.indicators ) { 1031 | // TODO: check concat compatibility 1032 | indicators = indicators.concat(this.options.indicators); 1033 | } 1034 | 1035 | for ( var i = indicators.length; i--; ) { 1036 | this.indicators.push( new Indicator(this, indicators[i]) ); 1037 | } 1038 | 1039 | // TODO: check if we can use array.map (wide compatibility and performance issues) 1040 | function _indicatorsMap (fn) { 1041 | if (that.indicators) { 1042 | for ( var i = that.indicators.length; i--; ) { 1043 | fn.call(that.indicators[i]); 1044 | } 1045 | } 1046 | } 1047 | 1048 | if ( this.options.fadeScrollbars ) { 1049 | this.on('scrollEnd', function () { 1050 | _indicatorsMap(function () { 1051 | this.fade(); 1052 | }); 1053 | }); 1054 | 1055 | this.on('scrollCancel', function () { 1056 | _indicatorsMap(function () { 1057 | this.fade(); 1058 | }); 1059 | }); 1060 | 1061 | this.on('scrollStart', function () { 1062 | _indicatorsMap(function () { 1063 | this.fade(1); 1064 | }); 1065 | }); 1066 | 1067 | this.on('beforeScrollStart', function () { 1068 | _indicatorsMap(function () { 1069 | this.fade(1, true); 1070 | }); 1071 | }); 1072 | } 1073 | 1074 | 1075 | this.on('refresh', function () { 1076 | _indicatorsMap(function () { 1077 | this.refresh(); 1078 | }); 1079 | }); 1080 | 1081 | this.on('destroy', function () { 1082 | _indicatorsMap(function () { 1083 | this.destroy(); 1084 | }); 1085 | 1086 | delete this.indicators; 1087 | }); 1088 | }, 1089 | 1090 | _initWheel: function () { 1091 | utils.addEvent(this.wrapper, 'wheel', this); 1092 | utils.addEvent(this.wrapper, 'mousewheel', this); 1093 | utils.addEvent(this.wrapper, 'DOMMouseScroll', this); 1094 | 1095 | this.on('destroy', function () { 1096 | clearTimeout(this.wheelTimeout); 1097 | this.wheelTimeout = null; 1098 | utils.removeEvent(this.wrapper, 'wheel', this); 1099 | utils.removeEvent(this.wrapper, 'mousewheel', this); 1100 | utils.removeEvent(this.wrapper, 'DOMMouseScroll', this); 1101 | }); 1102 | }, 1103 | 1104 | _wheel: function (e) { 1105 | if ( !this.enabled ) { 1106 | return; 1107 | } 1108 | 1109 | e.preventDefault(); 1110 | 1111 | var wheelDeltaX, wheelDeltaY, 1112 | newX, newY, 1113 | that = this; 1114 | 1115 | if ( this.wheelTimeout === undefined ) { 1116 | that._execEvent('scrollStart'); 1117 | } 1118 | 1119 | // Execute the scrollEnd event after 400ms the wheel stopped scrolling 1120 | clearTimeout(this.wheelTimeout); 1121 | this.wheelTimeout = setTimeout(function () { 1122 | if(!that.options.snap) { 1123 | that._execEvent('scrollEnd'); 1124 | } 1125 | that.wheelTimeout = undefined; 1126 | }, 400); 1127 | 1128 | if ( 'deltaX' in e ) { 1129 | if (e.deltaMode === 1) { 1130 | wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed; 1131 | wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed; 1132 | } else { 1133 | wheelDeltaX = -e.deltaX; 1134 | wheelDeltaY = -e.deltaY; 1135 | } 1136 | } else if ( 'wheelDeltaX' in e ) { 1137 | wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed; 1138 | wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed; 1139 | } else if ( 'wheelDelta' in e ) { 1140 | wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed; 1141 | } else if ( 'detail' in e ) { 1142 | wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed; 1143 | } else { 1144 | return; 1145 | } 1146 | 1147 | wheelDeltaX *= this.options.invertWheelDirection; 1148 | wheelDeltaY *= this.options.invertWheelDirection; 1149 | 1150 | if ( !this.hasVerticalScroll ) { 1151 | wheelDeltaX = wheelDeltaY; 1152 | wheelDeltaY = 0; 1153 | } 1154 | 1155 | if ( this.options.snap ) { 1156 | newX = this.currentPage.pageX; 1157 | newY = this.currentPage.pageY; 1158 | 1159 | if ( wheelDeltaX > 0 ) { 1160 | newX--; 1161 | } else if ( wheelDeltaX < 0 ) { 1162 | newX++; 1163 | } 1164 | 1165 | if ( wheelDeltaY > 0 ) { 1166 | newY--; 1167 | } else if ( wheelDeltaY < 0 ) { 1168 | newY++; 1169 | } 1170 | 1171 | this.goToPage(newX, newY); 1172 | 1173 | return; 1174 | } 1175 | 1176 | newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0); 1177 | newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0); 1178 | 1179 | this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0; 1180 | this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0; 1181 | 1182 | if ( newX > 0 ) { 1183 | newX = 0; 1184 | } else if ( newX < this.maxScrollX ) { 1185 | newX = this.maxScrollX; 1186 | } 1187 | 1188 | if ( newY > 0 ) { 1189 | newY = 0; 1190 | } else if ( newY < this.maxScrollY ) { 1191 | newY = this.maxScrollY; 1192 | } 1193 | 1194 | this.scrollTo(newX, newY, 0); 1195 | 1196 | if ( this.options.probeType > 1 ) { 1197 | this._execEvent('scroll'); 1198 | } 1199 | 1200 | // INSERT POINT: _wheel 1201 | }, 1202 | 1203 | _initSnap: function () { 1204 | this.currentPage = {}; 1205 | 1206 | if ( typeof this.options.snap == 'string' ) { 1207 | this.options.snap = this.scroller.querySelectorAll(this.options.snap); 1208 | } 1209 | 1210 | this.on('refresh', function () { 1211 | var i = 0, l, 1212 | m = 0, n, 1213 | cx, cy, 1214 | x = 0, y, 1215 | stepX = this.options.snapStepX || this.wrapperWidth, 1216 | stepY = this.options.snapStepY || this.wrapperHeight, 1217 | el; 1218 | 1219 | this.pages = []; 1220 | 1221 | if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) { 1222 | return; 1223 | } 1224 | 1225 | if ( this.options.snap === true ) { 1226 | cx = Math.round( stepX / 2 ); 1227 | cy = Math.round( stepY / 2 ); 1228 | 1229 | while ( x > -this.scrollerWidth ) { 1230 | this.pages[i] = []; 1231 | l = 0; 1232 | y = 0; 1233 | 1234 | while ( y > -this.scrollerHeight ) { 1235 | this.pages[i][l] = { 1236 | x: Math.max(x, this.maxScrollX), 1237 | y: Math.max(y, this.maxScrollY), 1238 | width: stepX, 1239 | height: stepY, 1240 | cx: x - cx, 1241 | cy: y - cy 1242 | }; 1243 | 1244 | y -= stepY; 1245 | l++; 1246 | } 1247 | 1248 | x -= stepX; 1249 | i++; 1250 | } 1251 | } else { 1252 | el = this.options.snap; 1253 | l = el.length; 1254 | n = -1; 1255 | 1256 | for ( ; i < l; i++ ) { 1257 | if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) { 1258 | m = 0; 1259 | n++; 1260 | } 1261 | 1262 | if ( !this.pages[m] ) { 1263 | this.pages[m] = []; 1264 | } 1265 | 1266 | x = Math.max(-el[i].offsetLeft, this.maxScrollX); 1267 | y = Math.max(-el[i].offsetTop, this.maxScrollY); 1268 | cx = x - Math.round(el[i].offsetWidth / 2); 1269 | cy = y - Math.round(el[i].offsetHeight / 2); 1270 | 1271 | this.pages[m][n] = { 1272 | x: x, 1273 | y: y, 1274 | width: el[i].offsetWidth, 1275 | height: el[i].offsetHeight, 1276 | cx: cx, 1277 | cy: cy 1278 | }; 1279 | 1280 | if ( x > this.maxScrollX ) { 1281 | m++; 1282 | } 1283 | } 1284 | } 1285 | 1286 | this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0); 1287 | 1288 | // Update snap threshold if needed 1289 | if ( this.options.snapThreshold % 1 === 0 ) { 1290 | this.snapThresholdX = this.options.snapThreshold; 1291 | this.snapThresholdY = this.options.snapThreshold; 1292 | } else { 1293 | this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold); 1294 | this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold); 1295 | } 1296 | }); 1297 | 1298 | this.on('flick', function () { 1299 | var time = this.options.snapSpeed || Math.max( 1300 | Math.max( 1301 | Math.min(Math.abs(this.x - this.startX), 1000), 1302 | Math.min(Math.abs(this.y - this.startY), 1000) 1303 | ), 300); 1304 | 1305 | this.goToPage( 1306 | this.currentPage.pageX + this.directionX, 1307 | this.currentPage.pageY + this.directionY, 1308 | time 1309 | ); 1310 | }); 1311 | }, 1312 | 1313 | _nearestSnap: function (x, y) { 1314 | if ( !this.pages.length ) { 1315 | return { x: 0, y: 0, pageX: 0, pageY: 0 }; 1316 | } 1317 | 1318 | var i = 0, 1319 | l = this.pages.length, 1320 | m = 0; 1321 | 1322 | // Check if we exceeded the snap threshold 1323 | if ( Math.abs(x - this.absStartX) < this.snapThresholdX && 1324 | Math.abs(y - this.absStartY) < this.snapThresholdY ) { 1325 | return this.currentPage; 1326 | } 1327 | 1328 | if ( x > 0 ) { 1329 | x = 0; 1330 | } else if ( x < this.maxScrollX ) { 1331 | x = this.maxScrollX; 1332 | } 1333 | 1334 | if ( y > 0 ) { 1335 | y = 0; 1336 | } else if ( y < this.maxScrollY ) { 1337 | y = this.maxScrollY; 1338 | } 1339 | 1340 | for ( ; i < l; i++ ) { 1341 | if ( x >= this.pages[i][0].cx ) { 1342 | x = this.pages[i][0].x; 1343 | break; 1344 | } 1345 | } 1346 | 1347 | l = this.pages[i].length; 1348 | 1349 | for ( ; m < l; m++ ) { 1350 | if ( y >= this.pages[0][m].cy ) { 1351 | y = this.pages[0][m].y; 1352 | break; 1353 | } 1354 | } 1355 | 1356 | if ( i == this.currentPage.pageX ) { 1357 | i += this.directionX; 1358 | 1359 | if ( i < 0 ) { 1360 | i = 0; 1361 | } else if ( i >= this.pages.length ) { 1362 | i = this.pages.length - 1; 1363 | } 1364 | 1365 | x = this.pages[i][0].x; 1366 | } 1367 | 1368 | if ( m == this.currentPage.pageY ) { 1369 | m += this.directionY; 1370 | 1371 | if ( m < 0 ) { 1372 | m = 0; 1373 | } else if ( m >= this.pages[0].length ) { 1374 | m = this.pages[0].length - 1; 1375 | } 1376 | 1377 | y = this.pages[0][m].y; 1378 | } 1379 | 1380 | return { 1381 | x: x, 1382 | y: y, 1383 | pageX: i, 1384 | pageY: m 1385 | }; 1386 | }, 1387 | 1388 | goToPage: function (x, y, time, easing) { 1389 | easing = easing || this.options.bounceEasing; 1390 | 1391 | if ( x >= this.pages.length ) { 1392 | x = this.pages.length - 1; 1393 | } else if ( x < 0 ) { 1394 | x = 0; 1395 | } 1396 | 1397 | if ( y >= this.pages[x].length ) { 1398 | y = this.pages[x].length - 1; 1399 | } else if ( y < 0 ) { 1400 | y = 0; 1401 | } 1402 | 1403 | var posX = this.pages[x][y].x, 1404 | posY = this.pages[x][y].y; 1405 | 1406 | time = time === undefined ? this.options.snapSpeed || Math.max( 1407 | Math.max( 1408 | Math.min(Math.abs(posX - this.x), 1000), 1409 | Math.min(Math.abs(posY - this.y), 1000) 1410 | ), 300) : time; 1411 | 1412 | this.currentPage = { 1413 | x: posX, 1414 | y: posY, 1415 | pageX: x, 1416 | pageY: y 1417 | }; 1418 | 1419 | this.scrollTo(posX, posY, time, easing); 1420 | }, 1421 | 1422 | next: function (time, easing) { 1423 | var x = this.currentPage.pageX, 1424 | y = this.currentPage.pageY; 1425 | 1426 | x++; 1427 | 1428 | if ( x >= this.pages.length && this.hasVerticalScroll ) { 1429 | x = 0; 1430 | y++; 1431 | } 1432 | 1433 | this.goToPage(x, y, time, easing); 1434 | }, 1435 | 1436 | prev: function (time, easing) { 1437 | var x = this.currentPage.pageX, 1438 | y = this.currentPage.pageY; 1439 | 1440 | x--; 1441 | 1442 | if ( x < 0 && this.hasVerticalScroll ) { 1443 | x = 0; 1444 | y--; 1445 | } 1446 | 1447 | this.goToPage(x, y, time, easing); 1448 | }, 1449 | 1450 | _initKeys: function (e) { 1451 | // default key bindings 1452 | var keys = { 1453 | pageUp: 33, 1454 | pageDown: 34, 1455 | end: 35, 1456 | home: 36, 1457 | left: 37, 1458 | up: 38, 1459 | right: 39, 1460 | down: 40 1461 | }; 1462 | var i; 1463 | 1464 | // if you give me characters I give you keycode 1465 | if ( typeof this.options.keyBindings == 'object' ) { 1466 | for ( i in this.options.keyBindings ) { 1467 | if ( typeof this.options.keyBindings[i] == 'string' ) { 1468 | this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCodeAt(0); 1469 | } 1470 | } 1471 | } else { 1472 | this.options.keyBindings = {}; 1473 | } 1474 | 1475 | for ( i in keys ) { 1476 | this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i]; 1477 | } 1478 | 1479 | utils.addEvent(window, 'keydown', this); 1480 | 1481 | this.on('destroy', function () { 1482 | utils.removeEvent(window, 'keydown', this); 1483 | }); 1484 | }, 1485 | 1486 | _key: function (e) { 1487 | if ( !this.enabled ) { 1488 | return; 1489 | } 1490 | 1491 | var snap = this.options.snap, // we are using this alot, better to cache it 1492 | newX = snap ? this.currentPage.pageX : this.x, 1493 | newY = snap ? this.currentPage.pageY : this.y, 1494 | now = utils.getTime(), 1495 | prevTime = this.keyTime || 0, 1496 | acceleration = 0.250, 1497 | pos; 1498 | 1499 | if ( this.options.useTransition && this.isInTransition ) { 1500 | pos = this.getComputedPosition(); 1501 | 1502 | this._translate(Math.round(pos.x), Math.round(pos.y)); 1503 | this.isInTransition = false; 1504 | } 1505 | 1506 | this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0; 1507 | 1508 | switch ( e.keyCode ) { 1509 | case this.options.keyBindings.pageUp: 1510 | if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { 1511 | newX += snap ? 1 : this.wrapperWidth; 1512 | } else { 1513 | newY += snap ? 1 : this.wrapperHeight; 1514 | } 1515 | break; 1516 | case this.options.keyBindings.pageDown: 1517 | if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { 1518 | newX -= snap ? 1 : this.wrapperWidth; 1519 | } else { 1520 | newY -= snap ? 1 : this.wrapperHeight; 1521 | } 1522 | break; 1523 | case this.options.keyBindings.end: 1524 | newX = snap ? this.pages.length-1 : this.maxScrollX; 1525 | newY = snap ? this.pages[0].length-1 : this.maxScrollY; 1526 | break; 1527 | case this.options.keyBindings.home: 1528 | newX = 0; 1529 | newY = 0; 1530 | break; 1531 | case this.options.keyBindings.left: 1532 | newX += snap ? -1 : 5 + this.keyAcceleration>>0; 1533 | break; 1534 | case this.options.keyBindings.up: 1535 | newY += snap ? 1 : 5 + this.keyAcceleration>>0; 1536 | break; 1537 | case this.options.keyBindings.right: 1538 | newX -= snap ? -1 : 5 + this.keyAcceleration>>0; 1539 | break; 1540 | case this.options.keyBindings.down: 1541 | newY -= snap ? 1 : 5 + this.keyAcceleration>>0; 1542 | break; 1543 | default: 1544 | return; 1545 | } 1546 | 1547 | if ( snap ) { 1548 | this.goToPage(newX, newY); 1549 | return; 1550 | } 1551 | 1552 | if ( newX > 0 ) { 1553 | newX = 0; 1554 | this.keyAcceleration = 0; 1555 | } else if ( newX < this.maxScrollX ) { 1556 | newX = this.maxScrollX; 1557 | this.keyAcceleration = 0; 1558 | } 1559 | 1560 | if ( newY > 0 ) { 1561 | newY = 0; 1562 | this.keyAcceleration = 0; 1563 | } else if ( newY < this.maxScrollY ) { 1564 | newY = this.maxScrollY; 1565 | this.keyAcceleration = 0; 1566 | } 1567 | 1568 | this.scrollTo(newX, newY, 0); 1569 | 1570 | this.keyTime = now; 1571 | }, 1572 | 1573 | _animate: function (destX, destY, duration, easingFn) { 1574 | var that = this, 1575 | startX = this.x, 1576 | startY = this.y, 1577 | startTime = utils.getTime(), 1578 | destTime = startTime + duration; 1579 | 1580 | function step () { 1581 | var now = utils.getTime(), 1582 | newX, newY, 1583 | easing; 1584 | 1585 | if ( now >= destTime ) { 1586 | that.isAnimating = false; 1587 | that._translate(destX, destY); 1588 | 1589 | if ( !that.resetPosition(that.options.bounceTime) ) { 1590 | that._execEvent('scrollEnd'); 1591 | } 1592 | 1593 | return; 1594 | } 1595 | 1596 | now = ( now - startTime ) / duration; 1597 | easing = easingFn(now); 1598 | newX = ( destX - startX ) * easing + startX; 1599 | newY = ( destY - startY ) * easing + startY; 1600 | that._translate(newX, newY); 1601 | 1602 | if ( that.isAnimating ) { 1603 | rAF(step); 1604 | } 1605 | 1606 | if ( that.options.probeType == 3 ) { 1607 | that._execEvent('scroll'); 1608 | } 1609 | } 1610 | 1611 | this.isAnimating = true; 1612 | step(); 1613 | }, 1614 | 1615 | handleEvent: function (e) { 1616 | if (this.pullState === 'refresh') return 1617 | switch ( e.type ) { 1618 | case 'touchstart': 1619 | case 'pointerdown': 1620 | case 'MSPointerDown': 1621 | case 'mousedown': 1622 | this._start(e); 1623 | break; 1624 | case 'touchmove': 1625 | case 'pointermove': 1626 | case 'MSPointerMove': 1627 | case 'mousemove': 1628 | this._move(e); 1629 | break; 1630 | case 'touchend': 1631 | case 'pointerup': 1632 | case 'MSPointerUp': 1633 | case 'mouseup': 1634 | case 'touchcancel': 1635 | case 'pointercancel': 1636 | case 'MSPointerCancel': 1637 | case 'mousecancel': 1638 | this._end(e); 1639 | break; 1640 | case 'orientationchange': 1641 | case 'resize': 1642 | this._resize(); 1643 | break; 1644 | case 'transitionend': 1645 | case 'webkitTransitionEnd': 1646 | case 'oTransitionEnd': 1647 | case 'MSTransitionEnd': 1648 | this._transitionEnd(e); 1649 | break; 1650 | case 'wheel': 1651 | case 'DOMMouseScroll': 1652 | case 'mousewheel': 1653 | this._wheel(e); 1654 | break; 1655 | case 'keydown': 1656 | this._key(e); 1657 | break; 1658 | case 'click': 1659 | if ( this.enabled && !e._constructed ) { 1660 | e.preventDefault(); 1661 | e.stopPropagation(); 1662 | } 1663 | break; 1664 | } 1665 | } 1666 | }; 1667 | function createDefaultScrollbar (direction, interactive, type) { 1668 | var scrollbar = document.createElement('div'), 1669 | indicator = document.createElement('div'); 1670 | 1671 | if ( type === true ) { 1672 | scrollbar.style.cssText = 'position:absolute;z-index:9999'; 1673 | indicator.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px'; 1674 | } 1675 | 1676 | indicator.className = 'iScrollIndicator'; 1677 | 1678 | if ( direction == 'h' ) { 1679 | if ( type === true ) { 1680 | scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0'; 1681 | indicator.style.height = '100%'; 1682 | } 1683 | scrollbar.className = 'iScrollHorizontalScrollbar'; 1684 | } else { 1685 | if ( type === true ) { 1686 | scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px'; 1687 | indicator.style.width = '100%'; 1688 | } 1689 | scrollbar.className = 'iScrollVerticalScrollbar'; 1690 | } 1691 | 1692 | scrollbar.style.cssText += ';overflow:hidden'; 1693 | 1694 | if ( !interactive ) { 1695 | scrollbar.style.pointerEvents = 'none'; 1696 | } 1697 | 1698 | scrollbar.appendChild(indicator); 1699 | 1700 | return scrollbar; 1701 | } 1702 | 1703 | function Indicator (scroller, options) { 1704 | this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el; 1705 | this.wrapperStyle = this.wrapper.style; 1706 | this.indicator = this.wrapper.children[0]; 1707 | this.indicatorStyle = this.indicator.style; 1708 | this.scroller = scroller; 1709 | 1710 | this.options = { 1711 | listenX: true, 1712 | listenY: true, 1713 | interactive: false, 1714 | resize: true, 1715 | defaultScrollbars: false, 1716 | shrink: false, 1717 | fade: false, 1718 | speedRatioX: 0, 1719 | speedRatioY: 0 1720 | }; 1721 | 1722 | for ( var i in options ) { 1723 | this.options[i] = options[i]; 1724 | } 1725 | 1726 | this.sizeRatioX = 1; 1727 | this.sizeRatioY = 1; 1728 | this.maxPosX = 0; 1729 | this.maxPosY = 0; 1730 | 1731 | if ( this.options.interactive ) { 1732 | if ( !this.options.disableTouch ) { 1733 | utils.addEvent(this.indicator, 'touchstart', this); 1734 | utils.addEvent(window, 'touchend', this); 1735 | } 1736 | if ( !this.options.disablePointer ) { 1737 | utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); 1738 | utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this); 1739 | } 1740 | if ( !this.options.disableMouse ) { 1741 | utils.addEvent(this.indicator, 'mousedown', this); 1742 | utils.addEvent(window, 'mouseup', this); 1743 | } 1744 | } 1745 | 1746 | if ( this.options.fade ) { 1747 | this.wrapperStyle[utils.style.transform] = this.scroller.translateZ; 1748 | var durationProp = utils.style.transitionDuration; 1749 | this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms'; 1750 | // remove 0.0001ms 1751 | var self = this; 1752 | if(utils.isBadAndroid) { 1753 | rAF(function() { 1754 | if(self.wrapperStyle[durationProp] === '0.0001ms') { 1755 | self.wrapperStyle[durationProp] = '0s'; 1756 | } 1757 | }); 1758 | } 1759 | this.wrapperStyle.opacity = '0'; 1760 | } 1761 | } 1762 | 1763 | Indicator.prototype = { 1764 | handleEvent: function (e) { 1765 | if (this.scroller.pullState === 'refresh') return 1766 | switch ( e.type ) { 1767 | case 'touchstart': 1768 | case 'pointerdown': 1769 | case 'MSPointerDown': 1770 | case 'mousedown': 1771 | this._start(e); 1772 | break; 1773 | case 'touchmove': 1774 | case 'pointermove': 1775 | case 'MSPointerMove': 1776 | case 'mousemove': 1777 | this._move(e); 1778 | break; 1779 | case 'touchend': 1780 | case 'pointerup': 1781 | case 'MSPointerUp': 1782 | case 'mouseup': 1783 | case 'touchcancel': 1784 | case 'pointercancel': 1785 | case 'MSPointerCancel': 1786 | case 'mousecancel': 1787 | this._end(e); 1788 | break; 1789 | } 1790 | }, 1791 | 1792 | destroy: function () { 1793 | if ( this.options.fadeScrollbars ) { 1794 | clearTimeout(this.fadeTimeout); 1795 | this.fadeTimeout = null; 1796 | } 1797 | if ( this.options.interactive ) { 1798 | utils.removeEvent(this.indicator, 'touchstart', this); 1799 | utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); 1800 | utils.removeEvent(this.indicator, 'mousedown', this); 1801 | 1802 | utils.removeEvent(window, 'touchmove', this); 1803 | utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); 1804 | utils.removeEvent(window, 'mousemove', this); 1805 | 1806 | utils.removeEvent(window, 'touchend', this); 1807 | utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this); 1808 | utils.removeEvent(window, 'mouseup', this); 1809 | } 1810 | 1811 | if ( this.options.defaultScrollbars ) { 1812 | this.wrapper.parentNode.removeChild(this.wrapper); 1813 | } 1814 | }, 1815 | 1816 | _start: function (e) { 1817 | var point = e.touches ? e.touches[0] : e; 1818 | 1819 | e.preventDefault(); 1820 | e.stopPropagation(); 1821 | 1822 | this.transitionTime(); 1823 | 1824 | this.initiated = true; 1825 | this.moved = false; 1826 | this.lastPointX = point.pageX; 1827 | this.lastPointY = point.pageY; 1828 | 1829 | this.startTime = utils.getTime(); 1830 | 1831 | if ( !this.options.disableTouch ) { 1832 | utils.addEvent(window, 'touchmove', this); 1833 | } 1834 | if ( !this.options.disablePointer ) { 1835 | utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this); 1836 | } 1837 | if ( !this.options.disableMouse ) { 1838 | utils.addEvent(window, 'mousemove', this); 1839 | } 1840 | 1841 | this.scroller._execEvent('beforeScrollStart'); 1842 | }, 1843 | 1844 | _move: function (e) { 1845 | var point = e.touches ? e.touches[0] : e, 1846 | deltaX, deltaY, 1847 | newX, newY, 1848 | timestamp = utils.getTime(); 1849 | 1850 | if ( !this.moved ) { 1851 | this.scroller._execEvent('scrollStart'); 1852 | } 1853 | 1854 | this.moved = true; 1855 | 1856 | deltaX = point.pageX - this.lastPointX; 1857 | this.lastPointX = point.pageX; 1858 | 1859 | deltaY = point.pageY - this.lastPointY; 1860 | this.lastPointY = point.pageY; 1861 | 1862 | newX = this.x + deltaX; 1863 | newY = this.y + deltaY; 1864 | 1865 | this.scroller.directionX = deltaX > 0 ? 1 : deltaX < 0 ? -1 : 0; 1866 | this.scroller.directionY = deltaY > 0 ? 1 : deltaY < 0 ? -1 : 0; 1867 | this._pos(newX, newY); 1868 | 1869 | if ( this.scroller.options.probeType == 1 && timestamp - this.startTime > 300 ) { 1870 | this.startTime = timestamp; 1871 | this.scroller._execEvent('scroll'); 1872 | } else if ( this.scroller.options.probeType > 1 ) { 1873 | this.scroller._execEvent('scroll'); 1874 | } 1875 | 1876 | 1877 | // INSERT POINT: indicator._move 1878 | 1879 | e.preventDefault(); 1880 | e.stopPropagation(); 1881 | }, 1882 | 1883 | _end: function (e) { 1884 | if ( !this.initiated ) { 1885 | return; 1886 | } 1887 | 1888 | this.initiated = false; 1889 | 1890 | e.preventDefault(); 1891 | e.stopPropagation(); 1892 | 1893 | utils.removeEvent(window, 'touchmove', this); 1894 | utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); 1895 | utils.removeEvent(window, 'mousemove', this); 1896 | 1897 | if ( this.scroller.options.snap ) { 1898 | var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y); 1899 | 1900 | var time = this.options.snapSpeed || Math.max( 1901 | Math.max( 1902 | Math.min(Math.abs(this.scroller.x - snap.x), 1000), 1903 | Math.min(Math.abs(this.scroller.y - snap.y), 1000) 1904 | ), 300); 1905 | 1906 | if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) { 1907 | this.scroller.directionX = 0; 1908 | this.scroller.directionY = 0; 1909 | this.scroller.currentPage = snap; 1910 | this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing); 1911 | } 1912 | } 1913 | 1914 | if ( this.moved ) { 1915 | this.scroller._execEvent('scrollEnd'); 1916 | } 1917 | }, 1918 | 1919 | transitionTime: function (time) { 1920 | time = time || 0; 1921 | var durationProp = utils.style.transitionDuration; 1922 | this.indicatorStyle[durationProp] = time + 'ms'; 1923 | 1924 | if ( !time && utils.isBadAndroid ) { 1925 | this.indicatorStyle[durationProp] = '0.0001ms'; 1926 | // remove 0.0001ms 1927 | var self = this; 1928 | rAF(function() { 1929 | if(self.indicatorStyle[durationProp] === '0.0001ms') { 1930 | self.indicatorStyle[durationProp] = '0s'; 1931 | } 1932 | }); 1933 | } 1934 | }, 1935 | 1936 | transitionTimingFunction: function (easing) { 1937 | this.indicatorStyle[utils.style.transitionTimingFunction] = easing; 1938 | }, 1939 | 1940 | refresh: function () { 1941 | this.transitionTime(); 1942 | 1943 | if ( this.options.listenX && !this.options.listenY ) { 1944 | this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none'; 1945 | } else if ( this.options.listenY && !this.options.listenX ) { 1946 | this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none'; 1947 | } else { 1948 | this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none'; 1949 | } 1950 | 1951 | if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) { 1952 | utils.addClass(this.wrapper, 'iScrollBothScrollbars'); 1953 | utils.removeClass(this.wrapper, 'iScrollLoneScrollbar'); 1954 | 1955 | if ( this.options.defaultScrollbars && this.options.customStyle ) { 1956 | if ( this.options.listenX ) { 1957 | this.wrapper.style.right = '8px'; 1958 | } else { 1959 | this.wrapper.style.bottom = '8px'; 1960 | } 1961 | } 1962 | } else { 1963 | utils.removeClass(this.wrapper, 'iScrollBothScrollbars'); 1964 | utils.addClass(this.wrapper, 'iScrollLoneScrollbar'); 1965 | 1966 | if ( this.options.defaultScrollbars && this.options.customStyle ) { 1967 | if ( this.options.listenX ) { 1968 | this.wrapper.style.right = '2px'; 1969 | } else { 1970 | this.wrapper.style.bottom = '2px'; 1971 | } 1972 | } 1973 | } 1974 | 1975 | var r = this.wrapper.offsetHeight; // force refresh 1976 | 1977 | if ( this.options.listenX ) { 1978 | this.wrapperWidth = this.wrapper.clientWidth; 1979 | if ( this.options.resize ) { 1980 | this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8); 1981 | this.indicatorStyle.width = this.indicatorWidth + 'px'; 1982 | } else { 1983 | this.indicatorWidth = this.indicator.clientWidth; 1984 | } 1985 | 1986 | this.maxPosX = this.wrapperWidth - this.indicatorWidth; 1987 | 1988 | if ( this.options.shrink == 'clip' ) { 1989 | this.minBoundaryX = -this.indicatorWidth + 8; 1990 | this.maxBoundaryX = this.wrapperWidth - 8; 1991 | } else { 1992 | this.minBoundaryX = 0; 1993 | this.maxBoundaryX = this.maxPosX; 1994 | } 1995 | 1996 | this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX)); 1997 | } 1998 | 1999 | if ( this.options.listenY ) { 2000 | this.wrapperHeight = this.wrapper.clientHeight; 2001 | if ( this.options.resize ) { 2002 | this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8); 2003 | this.indicatorStyle.height = this.indicatorHeight + 'px'; 2004 | } else { 2005 | this.indicatorHeight = this.indicator.clientHeight; 2006 | } 2007 | 2008 | this.maxPosY = this.wrapperHeight - this.indicatorHeight; 2009 | 2010 | if ( this.options.shrink == 'clip' ) { 2011 | this.minBoundaryY = -this.indicatorHeight + 8; 2012 | this.maxBoundaryY = this.wrapperHeight - 8; 2013 | } else { 2014 | this.minBoundaryY = 0; 2015 | this.maxBoundaryY = this.maxPosY; 2016 | } 2017 | 2018 | this.maxPosY = this.wrapperHeight - this.indicatorHeight; 2019 | this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY)); 2020 | } 2021 | 2022 | this.updatePosition(); 2023 | }, 2024 | 2025 | updatePosition: function () { 2026 | var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0, 2027 | y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0; 2028 | 2029 | if ( !this.options.ignoreBoundaries ) { 2030 | if ( x < this.minBoundaryX ) { 2031 | if ( this.options.shrink == 'scale' ) { 2032 | this.width = Math.max(this.indicatorWidth + x, 8); 2033 | this.indicatorStyle.width = this.width + 'px'; 2034 | } 2035 | x = this.minBoundaryX; 2036 | } else if ( x > this.maxBoundaryX ) { 2037 | if ( this.options.shrink == 'scale' ) { 2038 | this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8); 2039 | this.indicatorStyle.width = this.width + 'px'; 2040 | x = this.maxPosX + this.indicatorWidth - this.width; 2041 | } else { 2042 | x = this.maxBoundaryX; 2043 | } 2044 | } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) { 2045 | this.width = this.indicatorWidth; 2046 | this.indicatorStyle.width = this.width + 'px'; 2047 | } 2048 | 2049 | if ( y < this.minBoundaryY ) { 2050 | if ( this.options.shrink == 'scale' ) { 2051 | this.height = Math.max(this.indicatorHeight + y * 3, 8); 2052 | this.indicatorStyle.height = this.height + 'px'; 2053 | } 2054 | y = this.minBoundaryY; 2055 | } else if ( y > this.maxBoundaryY ) { 2056 | if ( this.options.shrink == 'scale' ) { 2057 | this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8); 2058 | this.indicatorStyle.height = this.height + 'px'; 2059 | y = this.maxPosY + this.indicatorHeight - this.height; 2060 | } else { 2061 | y = this.maxBoundaryY; 2062 | } 2063 | } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) { 2064 | this.height = this.indicatorHeight; 2065 | this.indicatorStyle.height = this.height + 'px'; 2066 | } 2067 | } 2068 | 2069 | this.x = x; 2070 | this.y = y; 2071 | 2072 | if ( this.scroller.options.useTransform ) { 2073 | this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ; 2074 | } else { 2075 | this.indicatorStyle.left = x + 'px'; 2076 | this.indicatorStyle.top = y + 'px'; 2077 | } 2078 | }, 2079 | 2080 | _pos: function (x, y) { 2081 | if ( x < 0 ) { 2082 | x = 0; 2083 | } else if ( x > this.maxPosX ) { 2084 | x = this.maxPosX; 2085 | } 2086 | 2087 | if ( y < 0 ) { 2088 | y = 0; 2089 | } else if ( y > this.maxPosY ) { 2090 | y = this.maxPosY; 2091 | } 2092 | 2093 | x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x; 2094 | y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y; 2095 | 2096 | this.scroller.scrollTo(x, y); 2097 | }, 2098 | 2099 | fade: function (val, hold) { 2100 | if ( hold && !this.visible ) { 2101 | return; 2102 | } 2103 | 2104 | clearTimeout(this.fadeTimeout); 2105 | this.fadeTimeout = null; 2106 | 2107 | var time = val ? 250 : 500, 2108 | delay = val ? 0 : 300; 2109 | 2110 | val = val ? '1' : '0'; 2111 | 2112 | this.wrapperStyle[utils.style.transitionDuration] = time + 'ms'; 2113 | 2114 | this.fadeTimeout = setTimeout((function (val) { 2115 | this.wrapperStyle.opacity = val; 2116 | this.visible = +val; 2117 | }).bind(this, val), delay); 2118 | } 2119 | }; 2120 | 2121 | IScroll.utils = utils; 2122 | 2123 | if ( typeof module != 'undefined' && module.exports ) { 2124 | module.exports = IScroll; 2125 | } else if ( typeof define == 'function' && define.amd ) { 2126 | define( function () { return IScroll; } ); 2127 | } else { 2128 | window.IScroll = IScroll; 2129 | } 2130 | 2131 | })(window, document, Math); 2132 | --------------------------------------------------------------------------------