├── .babelrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── README.quick.md ├── README.quick.zh-CN.md ├── config ├── webpack.base.config.js ├── webpack.dev.config.js ├── webpack.page.config.js ├── webpack.pro.config.js └── webpack.test.config.js ├── coverage ├── lcov-report │ ├── base.css │ ├── components │ │ └── index.html │ ├── index.html │ ├── prettify.css │ ├── prettify.js │ ├── sort-arrow-sprite.png │ └── sorter.js └── lcov.info ├── dist └── main.js ├── index.html ├── index.js ├── karma.conf.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── src ├── GarenLoadmore.vue └── index.js ├── static ├── loadmoregif.gif ├── shanglajiazai.jpg ├── shifangshuaxin.jpg ├── wugengduoshuju.jpg ├── xialashuaxin.jpg └── zhengzaishuaxin.jpg └── test ├── LoadMore.spec.js ├── setup.js └── utils.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", 4 | { 5 | "target": { 6 | "browsers": [ "iOS >= 7","Android >= 4" 7 | ] 8 | } 9 | } 10 | ] 11 | ], 12 | "plugins": [ 13 | [ 14 | "transform-runtime", 15 | { 16 | "helpers": false, 17 | "polyfill": false, 18 | "regenerator": true, 19 | "moduleName": "babel-runtime" 20 | } 21 | ] 22 | ] 23 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .cache/ 3 | .vscode/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | - "9" 5 | 6 | addons: 7 | chrome: stable 8 | sudo: required 9 | before_script: 10 | - "sudo chown root /opt/google/chrome/chrome-sandbox" 11 | - "sudo chmod 4755 /opt/google/chrome/chrome-sandbox" 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 duyanpeng 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 | # garen-loadmore 2 | [![Build Status](https://travis-ci.com/duyanpeng/vue-quick-loadmore.svg?branch=master)](https://travis-ci.org/duyanpeng/vue-quick-loadmore) 3 | ![Read the Docs](https://img.shields.io/readthedocs/pip.svg) 4 | [![](https://data.jsdelivr.com/v1/package/npm/garen-loadmore/badge)](https://www.jsdelivr.com/package/npm/vue-quick-loadmore) 5 | 6 | vue移动端下拉刷新上拉无限滚动加载插件,支持更换loading图片,保存设置滚动距离等。 7 | 8 | 默认样式如下,可根据状态更换loading图片或提示文案。 9 | 10 | ![xiaoguozhanshi](./static/loadmoregif.gif) 11 | 12 | ## 文档 13 | 更多vue移动端组件,欢迎使用: [garen-ui](https://duyanpeng.github.io/garen/) 14 | 15 | 原vue-quick-loadmore文档:[vue-quick-loadmore中文文档](https://github.com/duyanpeng/vue-quick-loadmore/blob/master/README.quick.zh-CN.md) 16 | 17 | 18 | ## 安装 19 | --- 20 | `npm install garen-loadmore -S` 21 | 22 | ``` 23 | // 引入方式 24 | import Vue from 'vue'; 25 | import GarenLoadmore from 'garen-loadmore'; 26 | 27 | Vue.use(GarenLoadmore) 28 | ``` 29 | 30 | ```html 31 | 32 | 33 | 34 | 35 | 36 | 37 | 41 | ``` 42 | ## 示例 43 | --- 44 | 45 | ```vue 46 | 64 | 65 | 172 | 190 | ``` 191 | ## API 192 | 193 | ### 下拉刷新配置 194 | --- 195 | 参数|类型|说明|备注 196 | :--:|:--:|:--:|:--: 197 | :disableTop|Boolean|禁止下拉刷新|默认:false 198 | :distanceIndex|Number|手指滑动与页面滑动比例|默认:2 199 | :topLoadingDistance|Number|loading状态时页面距顶部距离|默认:50 200 | :topDistance|Number|下拉刷新触发值|默认:100 201 | :top-change-text|Object|下拉刷新提示文案|见示例代码 202 | @top-method|Function|下拉刷新触发方法| 203 | @top-status-change|Function|下拉刷新状态改变回调|五种状态具体见示例代码 204 | ref.onTopLoaded|Function|下拉刷新完成时调用函数,参数是完成状态等待时间ms|通过ref使用具体见示例代码 205 | --- 206 | ### 上拉加载配置: 207 | 参数|类型|说明|备注 208 | :--:|:--:|:--:|:--: 209 | :disableBttom|Boolean|禁止上拉加载|默认:false 210 | :bottomDistance|Number|上拉加载触发值|默认:10 211 | :bottom-change-text|Object|上拉加载提示文案|见示例代码 212 | @bottom-method|Function|上拉加载触发方法| 213 | @bottom-status-change|Function|上拉加载状态改变回调|四种状态具体见示例代码 214 | @bottom-error-click|Function|数据请求出错点击触发方法| 215 | :eventScroll|Function|scroll事件回调|用于监听scroll事件 216 | ref.onBottomLoaded(boolean = true)|Function|上拉加载完成时调用函数|通过ref使用具体见示例代码(注意:如果下拉加载之后是无更多数据状态,函数传参为false,此后不在触发上拉刷新方法,下拉刷新之后会自动开启上拉加载) 217 | ref.onBottomError()|Function|上拉加载出错时调用函数|通过ref使用具体见示例代码 218 | --- 219 | ### 其他配置: 220 | 参数|类型|说明|备注 221 | :--:|:--:|:--:|:--: 222 | ref.getScrollTop|Function|获得滚动距离|具体见示例代码 223 | ref.setScroolTop(y)|Function|设置滚动距离|具体见示例代码 224 | --- 225 | ### 替换下拉刷新下拉加载loading图方法: 226 | 227 | ```html 228 | 231 | 234 | 235 | ``` 236 | ```css 237 | /* 参考自定义样式css */ 238 | .garen-loadmore-header { 239 | margin-top: -50px; 240 | height: 50px; 241 | line-height: 50px; 242 | text-align: center; 243 | font-size: 14px; 244 | color: #666666; 245 | letter-spacing: -0.31px; 246 | } 247 | .garen-loadmore-footer { 248 | height: 50px; 249 | line-height: 50px; 250 | text-align: center; 251 | font-size: 13px; 252 | color: #666666; 253 | letter-spacing: -0.31px; 254 | } 255 | 256 | ``` 257 | 258 | ## 版本更新说明 259 | --- 260 | 版本号|说明| 261 | :--:|:--:| 262 | 1.0.0|正式版本 263 | 0.1.0|项目发布 264 | 265 | ## 联系我 266 | --- 267 | QQ群:257216865 268 | 邮箱:215028726@qq.com 269 | -------------------------------------------------------------------------------- /README.quick.md: -------------------------------------------------------------------------------- 1 | # vue-quick-loadmore 2 | [![Build Status](https://travis-ci.com/duyanpeng/vue-quick-loadmore.svg?branch=master)](https://travis-ci.org/duyanpeng/vue-quick-loadmore) 3 | ![Read the Docs](https://img.shields.io/readthedocs/pip.svg) 4 | 5 | A pull-down refresh and pull-up infinite scroll component for Vue.js,support to replace loading images, save and settings scrolling distance and so on 6 | 7 | [zh-CN中文文档](https://github.com/duyanpeng/vue-quick-loadmore/blob/master/README.zh-CN.md) 8 | 9 | The default style is as follows, you can change the loading picture or text according to the status. 10 | 11 | ![xiaoguozhanshi](./static/loadmoregif.gif) 12 | 13 | 14 | ## Install 15 | --- 16 | `npm install vue-quick-loadmore -S` 17 | 18 | ``` 19 | // how to use 20 | import Vue from 'vue'; 21 | import VueQuickLoadmore from 'vue-quick-loadmore'; 22 | 23 | Vue.use(VueQuickLoadmore) 24 | ``` 25 | 26 | ## Use 27 | --- 28 | ```html 29 | 42 | ``` 43 | ```javascript 44 | export default { 45 | name: "Message", 46 | data() { 47 | return { 48 | dataList: [1, 2, 3, 4, 5] 49 | }; 50 | }, 51 | // Implement the go to the details page to return to the list location function - with keep-alive 52 | beforeRouteLeave(to, from, next) { 53 | // if enter detail 54 | if (to.name === "MessageDetail") { 55 | // Get scrolling distance 56 | let scrollTop = this.$refs.vueLoad.getScrollTop(); 57 | // Setting the cache 58 | sessionStorage.setItem("messageScrollTop", scrollTop); 59 | } else { 60 | // remore the cache 61 | sessionStorage.removeItem("messageScrollTop"); 62 | } 63 | next(); 64 | }, 65 | activated() { 66 | let scrollTop = sessionStorage.getItem("messageScrollTop"); 67 | // where from ? 68 | if (scrollTop == null) { 69 | console.log("不需要缓存的页面"); 70 | } else { 71 | // need record -- scroll 72 | this.$refs.vueLoad.setScrollTop(scrollTop); 73 | } 74 | }, 75 | deactivated() { 76 | 77 | }, 78 | methods: { 79 | handleTop() { 80 | // pull-down refresh 81 | // mock data 82 | setTimeout(() => { 83 | this.dataList = [1, 2, 3, 4, 5]; 84 | // scroll to top 85 | this.$refs.vueLoad.onTopLoaded(); 86 | }, 1000); 87 | }, 88 | handleStatusChange(status) { 89 | // status change 90 | const TOPSTATUS = { 91 | wait: "wait", 92 | pulling: "pulling", 93 | limit: "limit", 94 | loading: "loading" 95 | }; 96 | console.log(status, "statuschange"); 97 | }, 98 | handleBottomStatusChange(status) { 99 | // status change 100 | const BOTTOMSTATUS = { 101 | wait: "wait", 102 | loading: "loading", 103 | nodata: "nodata" 104 | }; 105 | console.log(status, "bottomchange"); 106 | }, 107 | handleBottom() { 108 | // pull-up infinite 109 | // mock data 110 | setTimeout(() => { 111 | this.dataList.push(1, 2, 3); 112 | // have more data ? false: this.$refs.vueLoad.onBottomLoaded(false)) 113 | // scroll to bottom 114 | this.$refs.vueLoad.onBottomLoaded(); 115 | }, 1000); 116 | } 117 | }, 118 | mounted() { 119 | // console.log("mounted"); 120 | } 121 | }; 122 | ``` 123 | ```css 124 | *{ 125 | margin:0; 126 | padding:0; 127 | } 128 | html,body,#app{ 129 | height:100%; 130 | overflow: hidden; 131 | } 132 | .item{ 133 | height:200px; 134 | background: lightgray; 135 | border:2px solid green; 136 | overflow: hidden; 137 | } 138 | ``` 139 | 140 | ### Pull-down options 141 | --- 142 | params|type|description|note 143 | :--:|:--:|:--:|:--: 144 | v-bind:disableTop|Boolean|Disable pull-down refresh|default:false 145 | v-bind:distanceIndex|Number|Scrolling ratio|default:2 146 | v-bind:topLoadingDistance|Number|Loading distance|default:50 147 | v-bind:topDistance|Number|Pull-down refresh trigger value|default:100 148 | v-bind:topMethod|Function|Pull-down refresh trigger method| 149 | v-bind:topStatusChange|Function|Pull-down status change|look for example 150 | ref.onTopLoaded|Function|Pull-down complete|use ref api 151 | --- 152 | ### Pull-up options: 153 | params|type|description|note 154 | :--:|:--:|:--:|:--: 155 | v-bind:disableBttom|Boolean|Disable pull-up|default:false 156 | v-bind:bottomDistance|Number|Loading distance|default:10 157 | v-bind:bottomMethod|Function|Pull-up trigger method| 158 | v-bind:bottomStatusChange|Function|Pull-up status change|look for example 159 | v-bind:eventScroll|Function|Scroll event callback|Used to listen for scroll events 160 | ref.onBottomLoaded(boolean = true)|Function|Pull-up complete|use ref api 161 | --- 162 | ### Other options: 163 | params|type|description|note 164 | :--:|:--:|:--:|:--: 165 | ref.getScrollTop|Function|get scroll distance|look for example 166 | ref.setScroolTop(y)|Function|scroll to distance|look for example 167 | --- 168 | ### How to replace loading image: 169 | 170 | ```html 171 | 174 | 177 | 178 | ``` 179 | 180 | 181 | -------------------------------------------------------------------------------- /README.quick.zh-CN.md: -------------------------------------------------------------------------------- 1 | # vue-quick-loadmore 2 | [![Build Status](https://travis-ci.com/duyanpeng/vue-quick-loadmore.svg?branch=master)](https://travis-ci.org/duyanpeng/vue-quick-loadmore) 3 | ![Read the Docs](https://img.shields.io/readthedocs/pip.svg) 4 | [![](https://data.jsdelivr.com/v1/package/npm/vue-quick-loadmore/badge)](https://www.jsdelivr.com/package/npm/vue-quick-loadmore) 5 | 6 | vue移动端下拉刷新上拉无限滚动加载插件,支持更换loading图片,保存设置滚动距离等。 7 | 8 | 默认样式如下,可根据状态更换loading图片或提示文案。 9 | 10 | ![xiaoguozhanshi](./static/loadmoregif.gif) 11 | 12 | 13 | ## 安装 14 | --- 15 | `npm install vue-quick-loadmore -S` 16 | 17 | ``` 18 | // 引入方式 19 | import Vue from 'vue'; 20 | import VueQuickLoadmore from 'vue-quick-loadmore'; 21 | 22 | Vue.use(VueQuickLoadmore) 23 | ``` 24 | 25 | ## 使用 26 | --- 27 | ```html 28 | 42 | ``` 43 | ```javascript 44 | export default { 45 | name: "Message", 46 | data() { 47 | return { 48 | dataList: [1, 2, 3, 4, 5] 49 | }; 50 | }, 51 | // 实现进入详情页返回列表位置功能-搭配keep-alive 52 | beforeRouteLeave(to, from, next) { 53 | // 如果进入详情页 54 | if (to.name === "MessageDetail") { 55 | // 获得滚动距离 56 | let scrollTop = this.$refs.vueLoad.getScrollTop(); 57 | // 设置缓存 58 | sessionStorage.setItem("messageScrollTop", scrollTop); 59 | } else { 60 | // 如果去其他页移除缓存 61 | sessionStorage.removeItem("messageScrollTop"); 62 | } 63 | next(); 64 | }, 65 | activated() { 66 | // 激活路由 67 | let scrollTop = sessionStorage.getItem("messageScrollTop"); 68 | // 判断来源 69 | if (scrollTop == null) { 70 | console.log("不需要缓存的页面"); 71 | } else { 72 | // 需要缓存的页面,滚动 73 | this.$refs.vueLoad.setScrollTop(scrollTop); 74 | } 75 | }, 76 | deactivated() { 77 | 78 | }, 79 | methods: { 80 | handleTop() { 81 | // 下拉刷新 82 | // 定时器用来模拟下拉刷新接口延迟时间 83 | setTimeout(() => { 84 | // 模拟数据更新 85 | this.dataList = [1, 2, 3, 4, 5]; 86 | // 数据跟新完调用该方法使quick-loadmore滚到顶部 87 | this.$refs.vueLoad.onTopLoaded(); 88 | }, 1000); 89 | }, 90 | handleStatusChange(status) { 91 | // status监控下拉刷新状态--等待/下拉/到达阙值/刷新 92 | const TOPSTATUS = { 93 | wait: "wait", 94 | pulling: "pulling", 95 | limit: "limit", 96 | loading: "loading" 97 | }; 98 | console.log(status, "statuschange"); 99 | }, 100 | handleBottomStatusChange(status) { 101 | // status监控上拉加载状态--等待/加载/没有更多数据 102 | const BOTTOMSTATUS = { 103 | wait: "wait", 104 | loading: "loading", 105 | nodata: "nodata" 106 | }; 107 | console.log(status, "bottomchange"); 108 | }, 109 | handleBottom() { 110 | // 上拉加载 111 | // 定时器用来模拟上拉加载接口延迟时间 112 | setTimeout(() => { 113 | // 模拟数据更新 114 | this.dataList.push(1, 2, 3); 115 | // 数据跟新完调用该方法使数据加载中提示消失,(注意:如果没有更多数据参数传false: this.$refs.vueLoad.onBottomLoaded(false)) 116 | this.$refs.vueLoad.onBottomLoaded(); 117 | }, 1000); 118 | } 119 | }, 120 | mounted() { 121 | // console.log("mounted"); 122 | } 123 | }; 124 | ``` 125 | ```css 126 | *{ 127 | margin:0; 128 | padding:0; 129 | } 130 | html,body,#app{ 131 | height:100%; 132 | overflow: hidden; 133 | } 134 | .item{ 135 | height:200px; 136 | background: lightgray; 137 | border:2px solid green; 138 | overflow: hidden; 139 | } 140 | ``` 141 | ```html 142 | 143 | 144 | 145 | 146 | 147 | 148 | 152 | 153 | 154 | ``` 155 | 156 | ### 下拉刷新配置 157 | --- 158 | 参数|类型|说明|备注 159 | :--:|:--:|:--:|:--: 160 | v-bind:disableTop|Boolean|禁止下拉刷新|默认:false 161 | v-bind:distanceIndex|Number|手指滑动与页面滑动比例|默认:2 162 | v-bind:topLoadingDistance|Number|loading状态时页面距顶部距离|默认:50 163 | v-bind:topDistance|Number|下拉刷新触发值|默认:100 164 | v-bind:topMethod|Function|下拉刷新触发方法| 165 | v-bind:topStatusChange|Function|下拉刷新状态改变回调|四种状态具体见示例代码 166 | ref.onTopLoaded|Function|下拉刷新完成时调用函数|通过ref使用具体见示例代码 167 | --- 168 | ### 上拉加载配置: 169 | 参数|类型|说明|备注 170 | :--:|:--:|:--:|:--: 171 | v-bind:disableBttom|Boolean|禁止上拉加载|默认:false 172 | v-bind:bottomDistance|Number|上拉加载触发值|默认:10 173 | v-bind:bottomMethod|Function|上拉加载触发方法| 174 | v-bind:bottomStatusChange|Function|上拉加载状态改变回调|三种状态具体见示例代码 175 | v-bind:eventScroll|Function|scroll事件回调|用于监听scroll事件 176 | ref.onBottomLoaded(boolean = true)|Function|上拉加载完成时调用函数|通过ref使用具体见示例代码(注意:如果下拉加载之后是无更多数据状态,函数传参为false,此后不在触发上拉刷新方法,下拉刷新之后会自动开启上拉加载) 177 | --- 178 | ### 其他配置: 179 | 参数|类型|说明|备注 180 | :--:|:--:|:--:|:--: 181 | ref.getScrollTop|Function|获得滚动距离|具体见示例代码 182 | ref.setScroolTop(y)|Function|设置滚动距离|具体见示例代码 183 | --- 184 | ### 替换下拉刷新下拉加载loading图方法: 185 | 186 | ```html 187 | 190 | 193 | 194 | ``` 195 | ## 提示 196 | 更好用的loadmore组件,及更多vue移动端组件,欢迎使用: [garen-ui](https://duyanpeng.github.io/garen/) 197 | 198 | ## 版本更新说明 199 | --- 200 | 版本号|说明| 201 | :--:|:--:| 202 | 1.0.3|增加script标签直接引入方式使用 203 | 1.0.0|更换打包方式 204 | 0.0.6|修复下拉误点击bug 205 | 0.0.5|更新文档 206 | 0.0.4|解决命令行报错问题 207 | 0.0.3|用vue-cli时命令行会报警告,不影响正常使用,以后修复。 208 | 0.0.2|更新文档 209 | 0.0.1|项目初始化 210 | 211 | ## 联系我 212 | --- 213 | QQ群:257216865 214 | -------------------------------------------------------------------------------- /config/webpack.base.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 3 | module.exports = { 4 | output: { 5 | path: path.resolve(__dirname, '../dist'), 6 | filename: '[name].js' 7 | }, 8 | plugins: [ 9 | new VueLoaderPlugin() 10 | ], 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.js$/, 15 | exclude: /(node_modules|bower_components)/, 16 | use: { 17 | loader: 'babel-loader' 18 | } 19 | }, 20 | 21 | { 22 | test: /\.vue$/, 23 | use: [ 24 | { 25 | loader: 'vue-loader', 26 | options: {} 27 | } 28 | ] 29 | 30 | } 31 | ] 32 | 33 | }, 34 | resolve: { 35 | alias: { 36 | 'vue$': 'vue/dist/vue.common.js' 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /config/webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 4 | const WebpackBaseConfig = require('./webpack.base.config.js'); 5 | const WebpackMerge = require('webpack-merge') 6 | 7 | module.exports = WebpackMerge(WebpackBaseConfig,{ 8 | entry: './index.js', 9 | mode:'development', 10 | plugins:[ 11 | new HtmlWebpackPlugin({ 12 | template: './index.html' 13 | }), 14 | ], 15 | module:{ 16 | rules:[ 17 | { 18 | test: /\.css$/, use: [ 19 | { loader: 'style-loader' }, 20 | { 21 | loader: 'css-loader', 22 | }, 23 | { 24 | loader:'postcss-loader' 25 | } 26 | ] 27 | }, 28 | { 29 | test: /\.less$/, use: [ 30 | { loader: 'style-loader' }, 31 | { 32 | loader: 'css-loader', 33 | }, 34 | { 35 | loader:'postcss-loader' 36 | },{ 37 | loader:'less-loader' 38 | } 39 | ] 40 | } 41 | ] 42 | }, 43 | devServer: { 44 | overlay: true, 45 | disableHostCheck: true, 46 | host:'0.0.0.0', 47 | port: 9000 48 | } 49 | }) 50 | -------------------------------------------------------------------------------- /config/webpack.page.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 4 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 5 | const WebpackBaseConfig = require('./webpack.base.config.js'); 6 | const WebpackMerge = require('webpack-merge') 7 | const ExtractTextPlugin = require("extract-text-webpack-plugin"); 8 | module.exports = WebpackMerge(WebpackBaseConfig, { 9 | entry: './index.js', 10 | output: { 11 | path: path.resolve(__dirname, '../build'), 12 | filename: '[name].[chunkhash].js', 13 | }, 14 | mode: 'production', 15 | module:{ 16 | rules:[ 17 | { 18 | test: /\.css$/, 19 | use: ExtractTextPlugin.extract({ 20 | fallback: "style-loader", 21 | use: ["css-loader","postcss-loader"] 22 | }) 23 | // use: [ 24 | // { loader: 'style-loader' }, 25 | // { 26 | // loader: 'css-loader', 27 | // }, 28 | // { 29 | // loader:'postcss-loader' 30 | // } 31 | // ] 32 | }, 33 | { 34 | test: /\.less$/, 35 | use: ExtractTextPlugin.extract({ 36 | fallback: "style-loader", 37 | use: ["css-loader","postcss-loader","less-loader"] 38 | }) 39 | // use: [ 40 | // { loader: 'style-loader' }, 41 | // { 42 | // loader: 'css-loader', 43 | // }, 44 | // { 45 | // loader:'postcss-loader' 46 | // },{ 47 | // loader:'less-loader' 48 | // } 49 | // ] 50 | }, 51 | ] 52 | }, 53 | plugins: [ 54 | new CleanWebpackPlugin(['build']), 55 | new ExtractTextPlugin("styles.css"), 56 | new HtmlWebpackPlugin({ 57 | template: './index.html' 58 | }), 59 | 60 | ], 61 | optimization: { 62 | splitChunks: { 63 | // chunks:'all' 64 | cacheGroups: { 65 | commons: { 66 | test: /[\\/]node_modules[\\/]/, 67 | name: 'vendors', 68 | chunks: 'all' 69 | } 70 | } 71 | } 72 | } 73 | }) 74 | -------------------------------------------------------------------------------- /config/webpack.pro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 4 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 5 | const WebpackBaseConfig = require('./webpack.base.config.js'); 6 | const WebpackMerge = require('webpack-merge') 7 | 8 | module.exports = WebpackMerge(WebpackBaseConfig,{ 9 | entry:'./src/index.js', 10 | output:{ 11 | path: path.resolve(__dirname, '../dist'), 12 | filename: '[name].js', 13 | library:'GarenLoadmore', 14 | libraryTarget:'umd', 15 | libraryExport: 'default' 16 | }, 17 | module:{ 18 | rules:[ 19 | { 20 | test: /\.css$/, use: [ 21 | { loader: 'style-loader' }, 22 | { 23 | loader: 'css-loader', 24 | }, 25 | { 26 | loader:'postcss-loader' 27 | } 28 | ] 29 | }, 30 | { 31 | test: /\.less$/, use: [ 32 | { loader: 'style-loader' }, 33 | { 34 | loader: 'css-loader', 35 | }, 36 | { 37 | loader:'postcss-loader' 38 | },{ 39 | loader:'less-loader' 40 | } 41 | ] 42 | }, 43 | ] 44 | }, 45 | plugins:[ 46 | new CleanWebpackPlugin(['dist']) 47 | ], 48 | mode:'production', 49 | }) 50 | -------------------------------------------------------------------------------- /config/webpack.test.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 4 | const WebpackBaseConfig = require('./webpack.base.config.js'); 5 | const WebpackMerge = require('webpack-merge') 6 | const nodeExternals = require('webpack-node-externals'); 7 | 8 | module.exports = WebpackMerge(WebpackBaseConfig,{ 9 | entry: './index.js', 10 | mode:'production', 11 | output:{ 12 | devtoolModuleFilenameTemplate: '[absolute-resource-path]', 13 | devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]' 14 | }, 15 | plugins:[ 16 | new HtmlWebpackPlugin({ 17 | template: './index.html' 18 | }), 19 | ], 20 | module:{ 21 | rules:[ 22 | { 23 | test: /\.css$/, use: [ 24 | { loader: 'style-loader' }, 25 | { 26 | loader: 'css-loader', 27 | }, 28 | { 29 | loader:'postcss-loader' 30 | } 31 | ] 32 | }, 33 | { 34 | test: /\.less$/, use: [ 35 | { loader: 'style-loader' }, 36 | { 37 | loader: 'css-loader', 38 | }, 39 | { 40 | loader:'postcss-loader' 41 | },{ 42 | loader:'less-loader' 43 | } 44 | ] 45 | } 46 | ] 47 | }, 48 | devServer: { 49 | overlay: true, 50 | disableHostCheck: true, 51 | port: 9000 52 | }, 53 | devtool: 'inline-cheap-module-source-map', 54 | // target: 'node', 55 | // externals: [nodeExternals()] 56 | }) 57 | -------------------------------------------------------------------------------- /coverage/lcov-report/base.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | margin:0; padding: 0; 3 | height: 100%; 4 | } 5 | body { 6 | font-family: Helvetica Neue, Helvetica, Arial; 7 | font-size: 14px; 8 | color:#333; 9 | } 10 | .small { font-size: 12px; } 11 | *, *:after, *:before { 12 | -webkit-box-sizing:border-box; 13 | -moz-box-sizing:border-box; 14 | box-sizing:border-box; 15 | } 16 | h1 { font-size: 20px; margin: 0;} 17 | h2 { font-size: 14px; } 18 | pre { 19 | font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; 20 | margin: 0; 21 | padding: 0; 22 | -moz-tab-size: 2; 23 | -o-tab-size: 2; 24 | tab-size: 2; 25 | } 26 | a { color:#0074D9; text-decoration:none; } 27 | a:hover { text-decoration:underline; } 28 | .strong { font-weight: bold; } 29 | .space-top1 { padding: 10px 0 0 0; } 30 | .pad2y { padding: 20px 0; } 31 | .pad1y { padding: 10px 0; } 32 | .pad2x { padding: 0 20px; } 33 | .pad2 { padding: 20px; } 34 | .pad1 { padding: 10px; } 35 | .space-left2 { padding-left:55px; } 36 | .space-right2 { padding-right:20px; } 37 | .center { text-align:center; } 38 | .clearfix { display:block; } 39 | .clearfix:after { 40 | content:''; 41 | display:block; 42 | height:0; 43 | clear:both; 44 | visibility:hidden; 45 | } 46 | .fl { float: left; } 47 | @media only screen and (max-width:640px) { 48 | .col3 { width:100%; max-width:100%; } 49 | .hide-mobile { display:none!important; } 50 | } 51 | 52 | .quiet { 53 | color: #7f7f7f; 54 | color: rgba(0,0,0,0.5); 55 | } 56 | .quiet a { opacity: 0.7; } 57 | 58 | .fraction { 59 | font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; 60 | font-size: 10px; 61 | color: #555; 62 | background: #E8E8E8; 63 | padding: 4px 5px; 64 | border-radius: 3px; 65 | vertical-align: middle; 66 | } 67 | 68 | div.path a:link, div.path a:visited { color: #333; } 69 | table.coverage { 70 | border-collapse: collapse; 71 | margin: 10px 0 0 0; 72 | padding: 0; 73 | } 74 | 75 | table.coverage td { 76 | margin: 0; 77 | padding: 0; 78 | vertical-align: top; 79 | } 80 | table.coverage td.line-count { 81 | text-align: right; 82 | padding: 0 5px 0 20px; 83 | } 84 | table.coverage td.line-coverage { 85 | text-align: right; 86 | padding-right: 10px; 87 | min-width:20px; 88 | } 89 | 90 | table.coverage td span.cline-any { 91 | display: inline-block; 92 | padding: 0 5px; 93 | width: 100%; 94 | } 95 | .missing-if-branch { 96 | display: inline-block; 97 | margin-right: 5px; 98 | border-radius: 3px; 99 | position: relative; 100 | padding: 0 4px; 101 | background: #333; 102 | color: yellow; 103 | } 104 | 105 | .skip-if-branch { 106 | display: none; 107 | margin-right: 10px; 108 | position: relative; 109 | padding: 0 4px; 110 | background: #ccc; 111 | color: white; 112 | } 113 | .missing-if-branch .typ, .skip-if-branch .typ { 114 | color: inherit !important; 115 | } 116 | .coverage-summary { 117 | border-collapse: collapse; 118 | width: 100%; 119 | } 120 | .coverage-summary tr { border-bottom: 1px solid #bbb; } 121 | .keyline-all { border: 1px solid #ddd; } 122 | .coverage-summary td, .coverage-summary th { padding: 10px; } 123 | .coverage-summary tbody { border: 1px solid #bbb; } 124 | .coverage-summary td { border-right: 1px solid #bbb; } 125 | .coverage-summary td:last-child { border-right: none; } 126 | .coverage-summary th { 127 | text-align: left; 128 | font-weight: normal; 129 | white-space: nowrap; 130 | } 131 | .coverage-summary th.file { border-right: none !important; } 132 | .coverage-summary th.pct { } 133 | .coverage-summary th.pic, 134 | .coverage-summary th.abs, 135 | .coverage-summary td.pct, 136 | .coverage-summary td.abs { text-align: right; } 137 | .coverage-summary td.file { white-space: nowrap; } 138 | .coverage-summary td.pic { min-width: 120px !important; } 139 | .coverage-summary tfoot td { } 140 | 141 | .coverage-summary .sorter { 142 | height: 10px; 143 | width: 7px; 144 | display: inline-block; 145 | margin-left: 0.5em; 146 | background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; 147 | } 148 | .coverage-summary .sorted .sorter { 149 | background-position: 0 -20px; 150 | } 151 | .coverage-summary .sorted-desc .sorter { 152 | background-position: 0 -10px; 153 | } 154 | .status-line { height: 10px; } 155 | /* dark red */ 156 | .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } 157 | .low .chart { border:1px solid #C21F39 } 158 | /* medium red */ 159 | .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } 160 | /* light red */ 161 | .low, .cline-no { background:#FCE1E5 } 162 | /* light green */ 163 | .high, .cline-yes { background:rgb(230,245,208) } 164 | /* medium green */ 165 | .cstat-yes { background:rgb(161,215,106) } 166 | /* dark green */ 167 | .status-line.high, .high .cover-fill { background:rgb(77,146,33) } 168 | .high .chart { border:1px solid rgb(77,146,33) } 169 | /* dark yellow (gold) */ 170 | .medium .chart { border:1px solid #f9cd0b; } 171 | .status-line.medium, .medium .cover-fill { background: #f9cd0b; } 172 | /* light yellow */ 173 | .medium { background: #fff4c2; } 174 | /* light gray */ 175 | span.cline-neutral { background: #eaeaea; } 176 | 177 | .cbranch-no { background: yellow !important; color: #111; } 178 | 179 | .cstat-skip { background: #ddd; color: #111; } 180 | .fstat-skip { background: #ddd; color: #111 !important; } 181 | .cbranch-skip { background: #ddd !important; color: #111; } 182 | 183 | 184 | .cover-fill, .cover-empty { 185 | display:inline-block; 186 | height: 12px; 187 | } 188 | .chart { 189 | line-height: 0; 190 | } 191 | .cover-empty { 192 | background: white; 193 | } 194 | .cover-full { 195 | border-right: none !important; 196 | } 197 | pre.prettyprint { 198 | border: none !important; 199 | padding: 0 !important; 200 | margin: 0 !important; 201 | } 202 | .com { color: #999 !important; } 203 | .ignore-none { color: #999; font-weight: normal; } 204 | 205 | .wrapper { 206 | min-height: 100%; 207 | height: auto !important; 208 | height: 100%; 209 | margin: 0 auto -48px; 210 | } 211 | .footer, .push { 212 | height: 48px; 213 | } 214 | -------------------------------------------------------------------------------- /coverage/lcov-report/components/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for components/ 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files components/ 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 2/2 26 |
27 |
28 | 100% 29 | Branches 30 | 0/0 31 |
32 |
33 | 100% 34 | Functions 35 | 0/0 36 |
37 |
38 | 100% 39 | Lines 40 | 2/2 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
FileStatementsBranchesFunctionsLines
HelloWord.vue.js
100%2/2100%0/0100%0/0100%2/2
76 |
77 |
78 | 82 | 83 | 84 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /coverage/lcov-report/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for All files 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | / 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 0/0 26 |
27 |
28 | 100% 29 | Branches 30 | 0/0 31 |
32 |
33 | 100% 34 | Functions 35 | 0/0 36 |
37 |
38 | 100% 39 | Lines 40 | 0/0 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
FileStatementsBranchesFunctionsLines
63 |
64 |
65 | 69 | 70 | 71 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.js: -------------------------------------------------------------------------------- 1 | window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); 2 | -------------------------------------------------------------------------------- /coverage/lcov-report/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duyanpeng/vue-quick-loadmore/2c2f5c4221260749cd4774563d70cb50ac1d1ecc/coverage/lcov-report/sort-arrow-sprite.png -------------------------------------------------------------------------------- /coverage/lcov-report/sorter.js: -------------------------------------------------------------------------------- 1 | var addSorting = (function () { 2 | "use strict"; 3 | var cols, 4 | currentSort = { 5 | index: 0, 6 | desc: false 7 | }; 8 | 9 | // returns the summary table element 10 | function getTable() { return document.querySelector('.coverage-summary'); } 11 | // returns the thead element of the summary table 12 | function getTableHeader() { return getTable().querySelector('thead tr'); } 13 | // returns the tbody element of the summary table 14 | function getTableBody() { return getTable().querySelector('tbody'); } 15 | // returns the th element for nth column 16 | function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; } 17 | 18 | // loads all columns 19 | function loadColumns() { 20 | var colNodes = getTableHeader().querySelectorAll('th'), 21 | colNode, 22 | cols = [], 23 | col, 24 | i; 25 | 26 | for (i = 0; i < colNodes.length; i += 1) { 27 | colNode = colNodes[i]; 28 | col = { 29 | key: colNode.getAttribute('data-col'), 30 | sortable: !colNode.getAttribute('data-nosort'), 31 | type: colNode.getAttribute('data-type') || 'string' 32 | }; 33 | cols.push(col); 34 | if (col.sortable) { 35 | col.defaultDescSort = col.type === 'number'; 36 | colNode.innerHTML = colNode.innerHTML + ''; 37 | } 38 | } 39 | return cols; 40 | } 41 | // attaches a data attribute to every tr element with an object 42 | // of data values keyed by column name 43 | function loadRowData(tableRow) { 44 | var tableCols = tableRow.querySelectorAll('td'), 45 | colNode, 46 | col, 47 | data = {}, 48 | i, 49 | val; 50 | for (i = 0; i < tableCols.length; i += 1) { 51 | colNode = tableCols[i]; 52 | col = cols[i]; 53 | val = colNode.getAttribute('data-value'); 54 | if (col.type === 'number') { 55 | val = Number(val); 56 | } 57 | data[col.key] = val; 58 | } 59 | return data; 60 | } 61 | // loads all row data 62 | function loadData() { 63 | var rows = getTableBody().querySelectorAll('tr'), 64 | i; 65 | 66 | for (i = 0; i < rows.length; i += 1) { 67 | rows[i].data = loadRowData(rows[i]); 68 | } 69 | } 70 | // sorts the table using the data for the ith column 71 | function sortByIndex(index, desc) { 72 | var key = cols[index].key, 73 | sorter = function (a, b) { 74 | a = a.data[key]; 75 | b = b.data[key]; 76 | return a < b ? -1 : a > b ? 1 : 0; 77 | }, 78 | finalSorter = sorter, 79 | tableBody = document.querySelector('.coverage-summary tbody'), 80 | rowNodes = tableBody.querySelectorAll('tr'), 81 | rows = [], 82 | i; 83 | 84 | if (desc) { 85 | finalSorter = function (a, b) { 86 | return -1 * sorter(a, b); 87 | }; 88 | } 89 | 90 | for (i = 0; i < rowNodes.length; i += 1) { 91 | rows.push(rowNodes[i]); 92 | tableBody.removeChild(rowNodes[i]); 93 | } 94 | 95 | rows.sort(finalSorter); 96 | 97 | for (i = 0; i < rows.length; i += 1) { 98 | tableBody.appendChild(rows[i]); 99 | } 100 | } 101 | // removes sort indicators for current column being sorted 102 | function removeSortIndicators() { 103 | var col = getNthColumn(currentSort.index), 104 | cls = col.className; 105 | 106 | cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); 107 | col.className = cls; 108 | } 109 | // adds sort indicators for current column being sorted 110 | function addSortIndicators() { 111 | getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted'; 112 | } 113 | // adds event listeners for all sorter widgets 114 | function enableUI() { 115 | var i, 116 | el, 117 | ithSorter = function ithSorter(i) { 118 | var col = cols[i]; 119 | 120 | return function () { 121 | var desc = col.defaultDescSort; 122 | 123 | if (currentSort.index === i) { 124 | desc = !currentSort.desc; 125 | } 126 | sortByIndex(i, desc); 127 | removeSortIndicators(); 128 | currentSort.index = i; 129 | currentSort.desc = desc; 130 | addSortIndicators(); 131 | }; 132 | }; 133 | for (i =0 ; i < cols.length; i += 1) { 134 | if (cols[i].sortable) { 135 | // add the click event handler on the th so users 136 | // dont have to click on those tiny arrows 137 | el = getNthColumn(i).querySelector('.sorter').parentElement; 138 | if (el.addEventListener) { 139 | el.addEventListener('click', ithSorter(i)); 140 | } else { 141 | el.attachEvent('onclick', ithSorter(i)); 142 | } 143 | } 144 | } 145 | } 146 | // adds sorting functionality to the UI 147 | return function () { 148 | if (!getTable()) { 149 | return; 150 | } 151 | cols = loadColumns(); 152 | loadData(cols); 153 | addSortIndicators(); 154 | enableUI(); 155 | }; 156 | })(); 157 | 158 | window.addEventListener('load', addSorting); 159 | -------------------------------------------------------------------------------- /coverage/lcov.info: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duyanpeng/vue-quick-loadmore/2c2f5c4221260749cd4774563d70cb50ac1d1ecc/coverage/lcov.info -------------------------------------------------------------------------------- /dist/main.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.GarenLoadmore=e():t.GarenLoadmore=e()}(window,function(){return function(t){var e={};function n(o){if(e[o])return e[o].exports;var r=e[o]={i:o,l:!1,exports:{}};return t[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=t,n.c=e,n.d=function(t,e,o){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:o})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)n.d(o,r,function(e){return t[e]}.bind(null,r));return o},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=5)}([function(t,e,n){"use strict";n.r(e);var o=n(1),r=n.n(o);for(var i in o)"default"!==i&&function(t){n.d(e,t,function(){return o[t]})}(i);e.default=r.a},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o="wait",r="pulling",i="limit",s="loading",a="complete",c="wait",u="loading",l="nodata",f="error";e.default={name:"Loadmore",props:{disableTop:{type:Boolean,default:!1},distanceIndex:{type:Number,default:2},topLoadingDistance:{type:Number,default:50},topDistance:{type:Number,default:100},topChangeText:{type:Object,default:function(){return{}}},disableBottom:{type:Boolean,default:!1},bottomDistance:{type:Number,default:10},bottomChangeText:{type:Object,default:function(){return{}}},eventScroll:{type:Function}},data:function(){return{startPositionTop:null,startScreenY:0,endScreenY:0,topStatus:o,bottomOverflow:"auto",bottomStatus:c}},components:{},computed:{topText:function(){switch(this.topStatus){case r:return this.topChangeText.pulling||"下拉刷新";case i:return this.topChangeText.limit||"释放刷新";case s:return this.topChangeText.loading||"正在刷新...";case a:return this.topChangeText.complete||"";default:return""}},bottomText:function(){switch(this.bottomStatus){case u:return this.bottomChangeText.loading||"正在加载更多...";case l:return this.bottomChangeText.nodata||"暂无更多数据";case f:return this.bottomChangeText.error||"请求数据出错,请点击重试";default:return""}}},watch:{topStatus:function(t){this.$emit("top-status-change",t)},bottomStatus:function(t){this.$emit("bottom-status-change",t)}},mounted:function(){this.init()},methods:{handleScroll:function(){var t=this;(this.eventScroll&&this.eventScroll(),this.disableBottom)||this.bottomStatus===c&&this.$el.scrollHeight-this.$el.scrollTop-this.$el.clientHeight<=this.bottomDistance&&(this.bottomStatus=u,this.$nextTick(function(){try{t.$el.scrollTo(0,t.$el.scrollHeight)}catch(t){}}),this.$emit("bottom-method"))},getScrollTop:function(){return this.$el.scrollTop},setScrollTop:function(t){var e=this;this.$nextTick(function(){e.$el.scrollTop=parseFloat(t)})},init:function(){this.startPositionTop=this.$refs.content.getBoundingClientRect().top,this.disableTop||this.bindTouchEvents()},bindTouchEvents:function(){this.$refs.content.addEventListener("touchstart",this.handleTouchStart),this.$refs.content.addEventListener("touchmove",this.handleTouchMove),this.$refs.content.addEventListener("touchend",this.handleTouchEnd)},handleTouchStart:function(t){if(!(this.$refs.content.getBoundingClientRect().topthis.startPositionTop&&(this.topStatus=r),e>=this.topDistance&&(this.topStatus=i),e>0&&(t.preventDefault(),t.stopPropagation(),this.transformStyle(this.$refs.content,e))}},handleTouchEnd:function(t){this.$refs.content.getBoundingClientRect().top=this.topDistance?(this.transformStyle(this.$refs.content,this.topLoadingDistance,!0),this.topStatus=s,this.$emit("top-method"),this.disableBottom||(this.bottomStatus=c)):(this.topStatus=o,this.transformStyle(this.$refs.content,0),this.startScreenY=0)))},onTopLoaded:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;setTimeout(function(){t.transformStyle(t.$refs.content,0,!0),t.startScreenY=0},e),this.topStatus=a},onBottomLoaded:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];this.bottomStatus=t?c:l},onBottomError:function(){this.bottomStatus=f},onBottomErrorClick:function(){this.bottomStatus===f&&(this.bottomStatus=u,this.$emit("bottom-error-click"))},transformStyle:function(t,e,n){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:200;t.style["-webkit-transform"]="translate3d(0,"+e+"px,0)",t.style.transform="translate3d(0,"+e+"px,0)",t.style.transitionDuration="0ms",n&&(t.style.transitionDuration=o+"ms")}}}},function(t,e,n){var o=n(8);"string"==typeof o&&(o=[[t.i,o,""]]);var r={hmr:!0,transform:void 0,insertInto:void 0};n(10)(o,r);o.locals&&(t.exports=o.locals)},function(t,e,n){"use strict";var o=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"garen-loadmore",style:{overflow:t.bottomOverflow},on:{"&scroll":function(e){return t.handleScroll(e)}}},[n("div",{ref:"content",staticClass:"garen-loadmore-content"},[t._t("top",[n("div",{staticClass:"garen-loadmore-header"},[n("div",[t._v(t._s(t.topText))])])]),t._v(" "),t._t("default"),t._v(" "),t._t("bottom",[t.disableBottom?t._e():n("div",{staticClass:"garen-loadmore-footer",on:{click:t.onBottomErrorClick}},[n("div",[t._v(t._s(t.bottomText))])])])],2)])},r=[];o._withStripped=!0,n.d(e,"a",function(){return o}),n.d(e,"b",function(){return r})},function(t,e,n){"use strict";function o(t,e,n,o,r,i,s,a){var c,u="function"==typeof t?t.options:t;if(e&&(u.render=e,u.staticRenderFns=n,u._compiled=!0),o&&(u.functional=!0),i&&(u._scopeId="data-v-"+i),s?(c=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__),r&&r.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(s)},u._ssrRegister=c):r&&(c=a?function(){r.call(this,this.$root.$options.shadowRoot)}:r),c)if(u.functional){u._injectStyles=c;var l=u.render;u.render=function(t,e){return c.call(e),l(t,e)}}else{var f=u.beforeCreate;u.beforeCreate=f?[].concat(f,c):[c]}return{exports:t,options:u}}n.d(e,"a",function(){return o})},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o,r=n(6),i=(o=r)&&o.__esModule?o:{default:o};e.default={install:function(t){t.component("garen-loadmore",i.default)}}},function(t,e,n){"use strict";n.r(e);var o=n(3),r=n(0);for(var i in r)"default"!==i&&function(t){n.d(e,t,function(){return r[t]})}(i);n(7);var s=n(4),a=Object(s.a)(r.default,o.a,o.b,!1,null,"30a014b3",null);a.options.__file="src/GarenLoadmore.vue",e.default=a.exports},function(t,e,n){"use strict";var o=n(2);n.n(o).a},function(t,e,n){(t.exports=n(9)(!1)).push([t.i,"\n.garen-loadmore[data-v-30a014b3] {\r\n height: 100%;\r\n overflow: auto;\r\n -webkit-overflow-scrolling: touch;\n}\n.garen-loadmore-header[data-v-30a014b3] {\r\n margin-top: -50px;\r\n height: 50px;\r\n line-height: 50px;\r\n text-align: center;\r\n font-size: 14px;\r\n color: #666666;\r\n letter-spacing: -0.31px;\n}\n.garen-loadmore-footer[data-v-30a014b3] {\r\n height: 50px;\r\n line-height: 50px;\r\n text-align: center;\r\n font-size: 13px;\r\n color: #666666;\r\n letter-spacing: -0.31px;\n}\r\n",""])},function(t,e){t.exports=function(t){var e=[];return e.toString=function(){return this.map(function(e){var n=function(t,e){var n=t[1]||"",o=t[3];if(!o)return n;if(e&&"function"==typeof btoa){var r=(s=o,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(s))))+" */"),i=o.sources.map(function(t){return"/*# sourceURL="+o.sourceRoot+t+" */"});return[n].concat(i).concat([r]).join("\n")}var s;return[n].join("\n")}(e,t);return e[2]?"@media "+e[2]+"{"+n+"}":n}).join("")},e.i=function(t,n){"string"==typeof t&&(t=[[null,t,""]]);for(var o={},r=0;r=0&&l.splice(e,1)}function v(t){var e=document.createElement("style");if(void 0===t.attrs.type&&(t.attrs.type="text/css"),void 0===t.attrs.nonce){var o=function(){0;return n.nc}();o&&(t.attrs.nonce=o)}return b(e,t.attrs),h(t,e),e}function b(t,e){Object.keys(e).forEach(function(n){t.setAttribute(n,e[n])})}function g(t,e){var n,o,r,i;if(e.transform&&t.css){if(!(i=e.transform(t.css)))return function(){};t.css=i}if(e.singleton){var s=u++;n=c||(c=v(e)),o=x.bind(null,n,s,!1),r=x.bind(null,n,s,!0)}else t.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=function(t){var e=document.createElement("link");return void 0===t.attrs.type&&(t.attrs.type="text/css"),t.attrs.rel="stylesheet",b(e,t.attrs),h(t,e),e}(e),o=function(t,e,n){var o=n.css,r=n.sourceMap,i=void 0===e.convertToAbsoluteUrls&&r;(e.convertToAbsoluteUrls||i)&&(o=f(o));r&&(o+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(r))))+" */");var s=new Blob([o],{type:"text/css"}),a=t.href;t.href=URL.createObjectURL(s),a&&URL.revokeObjectURL(a)}.bind(null,n,e),r=function(){m(n),n.href&&URL.revokeObjectURL(n.href)}):(n=v(e),o=function(t,e){var n=e.css,o=e.media;o&&t.setAttribute("media",o);if(t.styleSheet)t.styleSheet.cssText=n;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(n))}}.bind(null,n),r=function(){m(n)});return o(t),function(e){if(e){if(e.css===t.css&&e.media===t.media&&e.sourceMap===t.sourceMap)return;o(t=e)}else r()}}t.exports=function(t,e){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(e=e||{}).attrs="object"==typeof e.attrs?e.attrs:{},e.singleton||"boolean"==typeof e.singleton||(e.singleton=s()),e.insertInto||(e.insertInto="head"),e.insertAt||(e.insertAt="bottom");var n=p(t,e);return d(n,e),function(t){for(var o=[],r=0;r 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 42 | 43 | 44 | 45 |
46 |
47 | 50 |
{{index}}
51 |
52 |
53 |
54 | 55 | 56 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import GarenLoadmore from './dist/main.js' 3 | 4 | Vue.use(GarenLoadmore) 5 | 6 | new Vue({ 7 | name: "Message", 8 | el:'#app', 9 | data() { 10 | return { 11 | topChangeText:{ 12 | pulling:"下拉刷新", 13 | limit:"释放刷新", 14 | loading:"正在刷新...", 15 | complete:" ", // 刷新完成暂不提示 16 | }, 17 | bottomChangeText:{ 18 | loading:"正在加载更多...", 19 | nodata:"暂无更多数据", 20 | error:"请求数据出错,请点击重试", 21 | }, 22 | dataList: [1, 2, 3, 4, 5] 23 | }; 24 | }, 25 | // 实现进入详情页返回列表位置功能-搭配keep-alive 26 | beforeRouteLeave(to, from, next) { 27 | // 如果进入详情页 28 | if (to.name === "MessageDetail") { 29 | // 获得滚动距离 30 | let scrollTop = this.$refs.vueLoad.getScrollTop(); 31 | // 设置缓存 32 | sessionStorage.setItem("messageScrollTop", scrollTop); 33 | } else { 34 | // 如果去其他页移除缓存 35 | sessionStorage.removeItem("messageScrollTop"); 36 | } 37 | next(); 38 | }, 39 | activated() { 40 | // 激活路由 41 | let scrollTop = sessionStorage.getItem("messageScrollTop"); 42 | // 判断来源 43 | if (scrollTop == null) { 44 | console.log("不需要缓存的页面"); 45 | } else { 46 | // 需要缓存的页面,滚动 47 | this.$refs.vueLoad.setScrollTop(scrollTop); 48 | } 49 | }, 50 | deactivated() { 51 | 52 | }, 53 | methods: { 54 | handleTop() { 55 | // 下拉刷新 56 | // 定时器用来模拟下拉刷新接口延迟时间 57 | setTimeout(() => { 58 | // 模拟数据更新 59 | this.dataList = [1, 2, 3, 4, 5]; 60 | // 数据跟新完调用该方法使quick-loadmore滚到顶部,可传参完成状态停止时间 61 | this.$refs.vueLoad.onTopLoaded(); 62 | }, 1000); 63 | }, 64 | handleStatusChange(status) { 65 | // status监控下拉刷新状态--等待/下拉/到达阙值/刷新 66 | const TOPSTATUS = { 67 | wait: "wait", 68 | pulling: "pulling", 69 | limit: "limit", 70 | loading: "loading" 71 | }; 72 | console.log(status, "statuschange"); 73 | }, 74 | handleBottomStatusChange(status) { 75 | // status监控上拉加载状态--等待/加载/没有更多数据 76 | const BOTTOMSTATUS = { 77 | wait: "wait", 78 | loading: "loading", 79 | nodata: "nodata" 80 | }; 81 | console.log(status, "bottomchange"); 82 | }, 83 | handleBottom() { 84 | // 上拉加载 85 | // 定时器用来模拟上拉加载接口延迟时间 86 | setTimeout(() => { 87 | // 模拟数据更新 88 | this.dataList.push(1, 2, 3); 89 | // 数据跟新完调用该方法使数据加载中提示消失,(注意:如果没有更多数据参数传false: this.$refs.vueLoad.onBottomLoaded(false)) 90 | this.$refs.vueLoad.onBottomLoaded(); 91 | }, 1000); 92 | }, 93 | handleBottomError(){ 94 | this.handleBottom() 95 | }, 96 | eventScroll(){ 97 | console.log('scroll') 98 | } 99 | }, 100 | mounted() { 101 | // console.log("mounted"); 102 | } 103 | }) -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | var webpackConfig = require('./config/webpack.test.config.js') 2 | 3 | module.exports = function (config) { 4 | config.set({ 5 | frameworks: ['mocha'], 6 | 7 | files: [ 8 | 'test/**/*.spec.js' 9 | ], 10 | 11 | preprocessors: { 12 | '**/*.spec.js': ['webpack', 'sourcemap'] 13 | }, 14 | 15 | webpack: webpackConfig, 16 | 17 | reporters: ['spec','coverage'], 18 | 19 | browsers: ['ChromeHeadless'], 20 | coverageReporter: { 21 | dir: './coverage', 22 | reporters: [ 23 | { type: 'lcov', subdir: '.' }, 24 | { type: 'text-summary' } 25 | ] 26 | } 27 | }) 28 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "garen-loadmore", 3 | "version": "1.0.0", 4 | "description": "基于vue的移动端下拉刷新上拉无限滚动加载支持自定义文案自定义gif图的插件", 5 | "main": "dist/main.js", 6 | "scripts": { 7 | "test:mocha": "mocha-webpack --webpack-config config/webpack.test.config.js --require test/setup.js test/**/*.spec.js", 8 | "test": "cross-env BABEL_ENV=test karma start --single-run", 9 | "dev": "npx webpack-dev-server --config config/webpack.dev.config.js --hot", 10 | "build": "npx webpack --config config/webpack.pro.config.js", 11 | "build:page": "npx webpack --config config/webpack.page.config.js" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/duyanpeng/vue-quick-loadmore.git" 16 | }, 17 | "keywords": [ 18 | "vue", 19 | "loadmore", 20 | "infinite", 21 | "scroll", 22 | "javascript" 23 | ], 24 | "author": "duyanpeng", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/duyanpeng/vue-quick-loadmore/issues" 28 | }, 29 | "homepage": "https://github.com/duyanpeng/vue-quick-loadmore#readme", 30 | "devDependencies": { 31 | "@vue/test-utils": "^1.0.0-beta.24", 32 | "autoprefixer": "^9.1.2", 33 | "babel-core": "^6.26.3", 34 | "babel-loader": "^7.1.5", 35 | "babel-plugin-istanbul": "^4.1.6", 36 | "babel-plugin-transform-runtime": "^6.23.0", 37 | "babel-preset-env": "^1.7.0", 38 | "chai": "^4.1.2", 39 | "clean-webpack-plugin": "^0.1.19", 40 | "cross-env": "^5.2.0", 41 | "css-loader": "^1.0.0", 42 | "expect": "^23.5.0", 43 | "extract-text-webpack-plugin": "^4.0.0-beta.0", 44 | "html-webpack-plugin": "^3.2.0", 45 | "jsdom": "^12.0.0", 46 | "jsdom-global": "^3.0.2", 47 | "karma": "^3.0.0", 48 | "karma-chai": "^0.1.0", 49 | "karma-chrome-launcher": "^2.2.0", 50 | "karma-coverage": "^1.1.2", 51 | "karma-mocha": "^1.3.0", 52 | "karma-sourcemap-loader": "^0.3.7", 53 | "karma-spec-reporter": "^0.0.32", 54 | "karma-webpack": "^3.0.0", 55 | "less": "^3.8.1", 56 | "less-loader": "^4.1.0", 57 | "mocha": "^5.2.0", 58 | "mocha-webpack": "^2.0.0-beta.0", 59 | "postcss": "^7.0.2", 60 | "postcss-loader": "^3.0.0", 61 | "sinon": "^7.2.7", 62 | "sinon-chai": "^3.2.0", 63 | "style-loader": "^0.22.1", 64 | "vue-loader": "^15.3.0", 65 | "webpack": "^4.16.5", 66 | "webpack-cli": "^3.1.0", 67 | "webpack-dev-server": "^3.1.5", 68 | "webpack-merge": "^4.1.4", 69 | "webpack-node-externals": "^1.7.2" 70 | }, 71 | "dependencies": { 72 | "babel-runtime": "^6.26.0", 73 | "vue": "^2.5.17", 74 | "vue-template-compiler": "^2.5.17" 75 | }, 76 | "browserslist": [ 77 | "iOS >= 7", 78 | "Android >= 4" 79 | ] 80 | } 81 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports={ 2 | plugins:[ 3 | require('autoprefixer') 4 | ] 5 | } -------------------------------------------------------------------------------- /src/GarenLoadmore.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 307 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 2 | import GarenLoadmore from './GarenLoadmore.vue'; 3 | 4 | export default { 5 | install(Vue){ 6 | Vue.component('garen-loadmore', GarenLoadmore) 7 | } 8 | } -------------------------------------------------------------------------------- /static/loadmoregif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duyanpeng/vue-quick-loadmore/2c2f5c4221260749cd4774563d70cb50ac1d1ecc/static/loadmoregif.gif -------------------------------------------------------------------------------- /static/shanglajiazai.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duyanpeng/vue-quick-loadmore/2c2f5c4221260749cd4774563d70cb50ac1d1ecc/static/shanglajiazai.jpg -------------------------------------------------------------------------------- /static/shifangshuaxin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duyanpeng/vue-quick-loadmore/2c2f5c4221260749cd4774563d70cb50ac1d1ecc/static/shifangshuaxin.jpg -------------------------------------------------------------------------------- /static/wugengduoshuju.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duyanpeng/vue-quick-loadmore/2c2f5c4221260749cd4774563d70cb50ac1d1ecc/static/wugengduoshuju.jpg -------------------------------------------------------------------------------- /static/xialashuaxin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duyanpeng/vue-quick-loadmore/2c2f5c4221260749cd4774563d70cb50ac1d1ecc/static/xialashuaxin.jpg -------------------------------------------------------------------------------- /static/zhengzaishuaxin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duyanpeng/vue-quick-loadmore/2c2f5c4221260749cd4774563d70cb50ac1d1ecc/static/zhengzaishuaxin.jpg -------------------------------------------------------------------------------- /test/LoadMore.spec.js: -------------------------------------------------------------------------------- 1 | import { shallowMount, mount } from '@vue/test-utils' 2 | import Loadmore from '../src/GarenLoadmore.vue' 3 | import chai, { expect } from 'chai' 4 | import { createEvent } from './utils' 5 | import sinon from 'sinon' 6 | import sinonChai from 'sinon-chai' 7 | 8 | chai.use(sinonChai) 9 | 10 | describe('Loadmore', () => { 11 | it('pulling状态改变pulling', (done) => { 12 | const wrapper = mount(Loadmore, { 13 | propsData: { 14 | 'top-change-text': { 15 | pulling: "测试下拉刷新", 16 | limit: "测试释放刷新", 17 | loading: "测试正在刷新...", 18 | complete: "测试完成", 19 | } 20 | } 21 | }) 22 | const vm = wrapper.vm 23 | const touchmove = createEvent('touchmove') 24 | touchmove.touches = [{ screenY: 20 }] 25 | const content = vm.$refs.content 26 | vm.startPositionTop = -40 27 | content.addEventListener('touchmove', function (e) { 28 | expect(vm.topStatus).to.equal('pulling') 29 | expect(vm.topText).to.equal('测试下拉刷新') 30 | setTimeout(() => { 31 | expect(wrapper.emitted()['top-status-change'][0][0]).to.be.equal('pulling') 32 | done() 33 | }, 0) 34 | }, false); 35 | content.dispatchEvent(touchmove) 36 | }) 37 | 38 | it('pulling状态改变limit', (done) => { 39 | const wrapper = mount(Loadmore, { 40 | propsData: { 41 | 'top-change-text': { 42 | pulling: "测试下拉刷新", 43 | limit: "测试释放刷新", 44 | loading: "测试正在刷新...", 45 | complete: "测试完成", 46 | } 47 | } 48 | }) 49 | const vm = wrapper.vm 50 | const touchmove = createEvent('touchmove') 51 | touchmove.touches = [{ screenY: 200 }] 52 | const content = vm.$refs.content 53 | content.addEventListener('touchmove', function (e) { 54 | expect(vm.topStatus).to.equal('limit') 55 | expect(vm.topText).to.equal('测试释放刷新') 56 | setTimeout(() => { 57 | expect(wrapper.emitted()['top-status-change'][0][0]).to.be.equal('limit') 58 | done() 59 | }, 0) 60 | }, false); 61 | content.dispatchEvent(touchmove) 62 | }) 63 | 64 | it('pulling状态改变loading', (done) => { 65 | const wrapper = mount(Loadmore, 66 | { 67 | propsData: { 68 | 'top-change-text': { 69 | pulling: "测试下拉刷新", 70 | limit: "测试释放刷新", 71 | loading: "测试正在刷新...", 72 | complete: "测试完成", 73 | } 74 | } 75 | }) 76 | const vm = wrapper.vm 77 | const touchend = createEvent('touchend') 78 | touchend.changedTouches = [{ screenY: 200 }] 79 | const content = vm.$refs.content 80 | content.addEventListener('touchend', function (e) { 81 | expect(vm.topStatus).to.equal('loading') 82 | expect(vm.topText).to.equal('测试正在刷新...') 83 | setTimeout(() => { 84 | expect(wrapper.emitted()['top-status-change'][0][0]).to.be.equal('loading') 85 | expect(wrapper.emitted()['top-method']).to.not.be.undefined 86 | done() 87 | }, 0) 88 | }, false); 89 | content.dispatchEvent(touchend) 90 | }) 91 | 92 | it('pulling状态改变complete', () => { 93 | const wrapper = mount(Loadmore, { 94 | propsData: { 95 | 'top-change-text': { 96 | pulling: "测试下拉刷新", 97 | limit: "测试释放刷新", 98 | loading: "测试正在刷新...", 99 | complete: "测试完成", 100 | } 101 | } 102 | }) 103 | const vm = wrapper.vm 104 | const content = vm.$refs.content 105 | vm.topStatus = 'loading' 106 | vm.onTopLoaded() 107 | expect(vm.topStatus).to.equal('complete') 108 | expect(vm.topText).to.equal('测试完成') 109 | }) 110 | 111 | it('loading状态改变loading', (done) => { 112 | const wrapper = mount(Loadmore, 113 | { 114 | propsData: { 115 | 'bottom-change-text': { 116 | loading: "测试正在加载更多...", 117 | nodata: "测试暂无更多数据", 118 | error: "测试请求数据出错,请点击重试", 119 | } 120 | } 121 | }) 122 | const vm = wrapper.vm 123 | const scroll = createEvent('scroll') 124 | vm.$el.addEventListener('scroll', function (e) { 125 | expect(vm.bottomStatus).to.equal('loading') 126 | expect(vm.bottomText).to.equal('测试正在加载更多...') 127 | setTimeout(() => { 128 | expect(wrapper.emitted()['bottom-status-change'][0][0]).to.be.equal('loading') 129 | expect(wrapper.emitted()['bottom-method']).to.not.be.undefined 130 | done() 131 | }, 0) 132 | }, false); 133 | vm.$el.dispatchEvent(scroll) 134 | }) 135 | 136 | it('loading状态改变complete', () => { 137 | const wrapper = mount(Loadmore, 138 | { 139 | propsData: { 140 | 'bottom-change-text': { 141 | loading: "测试正在加载更多...", 142 | nodata: "测试暂无更多数据", 143 | error: "测试请求数据出错,请点击重试", 144 | } 145 | } 146 | }) 147 | const vm = wrapper.vm 148 | vm.bottomStatus = 'loading' 149 | vm.onBottomLoaded() 150 | expect(vm.bottomStatus).to.equal('wait') 151 | }) 152 | 153 | it('loading状态改变nodata', () => { 154 | const wrapper = mount(Loadmore, 155 | { 156 | propsData: { 157 | 'bottom-change-text': { 158 | loading: "测试正在加载更多...", 159 | nodata: "测试暂无更多数据", 160 | error: "测试请求数据出错,请点击重试", 161 | } 162 | } 163 | }) 164 | const vm = wrapper.vm 165 | vm.bottomStatus = 'loading' 166 | vm.onBottomLoaded(false) 167 | expect(vm.bottomStatus).to.equal('nodata') 168 | }) 169 | 170 | it('loading状态改变error', (done) => { 171 | const wrapper = mount(Loadmore, 172 | { 173 | propsData: { 174 | 'bottom-change-text': { 175 | loading: "测试正在加载更多...", 176 | nodata: "测试暂无更多数据", 177 | error: "测试请求数据出错,请点击重试", 178 | } 179 | } 180 | }) 181 | const vm = wrapper.vm 182 | vm.bottomStatus = 'loading' 183 | vm.onBottomError() 184 | expect(vm.bottomStatus).to.equal('error') 185 | wrapper.find('.garen-loadmore-footer').trigger('click') 186 | setTimeout(() => { 187 | expect(wrapper.emitted()['bottom-error-click']).to.not.be.undefined 188 | done() 189 | }, 0) 190 | }) 191 | 192 | it('loading监听scroll', (done) => { 193 | const cb = sinon.spy() 194 | const wrapper = mount(Loadmore, 195 | { 196 | propsData: { 197 | 'event-scroll': cb 198 | } 199 | }) 200 | const vm = wrapper.vm 201 | const scroll = createEvent('scroll') 202 | vm.$el.addEventListener('scroll', function (e) { 203 | setTimeout(() => { 204 | expect(cb).to.have.been.called 205 | done() 206 | }, 0) 207 | }, false); 208 | vm.$el.dispatchEvent(scroll) 209 | }) 210 | 211 | it('loading获取滚动距离', () => { 212 | const wrapper = mount(Loadmore) 213 | const vm = wrapper.vm 214 | const scrollTop = vm.getScrollTop() 215 | expect(scrollTop).to.equal(0) 216 | }) 217 | 218 | it('loading设置滚动距离', (done) => { 219 | const wrapper = mount(Loadmore) 220 | const vm = wrapper.vm 221 | vm.setScrollTop(50) 222 | setTimeout(()=>{ 223 | // TODO: slots 224 | const scrollTop = vm.getScrollTop() 225 | // expect(scrollTop).to.equal(50) 226 | done() 227 | },0) 228 | }) 229 | }) 230 | -------------------------------------------------------------------------------- /test/setup.js: -------------------------------------------------------------------------------- 1 | require('jsdom-global')() 2 | 3 | global.expect = require('expect') -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | export function createEvent(name){ 2 | const event = new Event(name) 3 | return event 4 | } --------------------------------------------------------------------------------