├── .gitignore ├── LICENSE ├── README.md ├── demo └── index.html ├── dist └── vue-swiper.js ├── package.json ├── src ├── vue-swiper.less └── vue-swiper.vue └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 威老 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 | [![npm](https://img.shields.io/npm/l/vue-swiper.svg?maxAge=2592000)](https://raw.githubusercontent.com/weilao/vue-swiper/master/LICENSE) 2 | [![npm](https://img.shields.io/npm/v/vue-swiper.svg?maxAge=2592000)](https://www.npmjs.com/package/vue-swiper) 3 | [![GitHub release](https://img.shields.io/github/release/weilao/vue-swiper.svg?maxAge=2592000)](https://github.com/weilao/vue-swiper/releases) 4 | [![GitHub issues](https://img.shields.io/github/issues/weilao/vue-swiper.svg?maxAge=2592000)](https://github.com/weilao/vue-swiper/issues) 5 | [![GitHub stars](https://img.shields.io/github/stars/weilao/vue-swiper.svg?style=social&label=Star&maxAge=2592000)](https://github.com/weilao/vue-swiper) 6 | 7 | [![NPM](https://nodei.co/npm/vue-swiper.png?downloads=true&downloadRank=true)](https://nodei.co/npm/vue-swiper/) 8 | 9 | # vue-swiper 10 | Swiper component. Easy to use. 11 | 12 | ## Examples 13 | [basic demo](http://weilao.github.io/vue-swiper/demo) 14 | 15 | ## Install 16 | ``` 17 | npm i vue-swiper -S 18 | ``` 19 | 20 | ## Usage 21 | 22 | ```js 23 | import Vue from 'vue' 24 | import Swiper from 'vue-swiper' 25 | 26 | new Vue({ 27 | el: 'body', 28 | components: {Swiper}, 29 | methods: { 30 | onSlideChangeStart (currentPage) { 31 | console.log('onSlideChangeStart', currentPage); 32 | }, 33 | onSlideChangeEnd (currentPage) { 34 | console.log('onSlideChangeEnd', currentPage); 35 | } 36 | } 37 | }); 38 | ``` 39 | 40 | ```html 41 | 50 |
Page 1
51 |
Page 2
52 |
Page 3
53 |
54 | ``` 55 | 56 | ## Api 57 | ### Properties 58 | | Name | Type | Default | Description | 59 | |----------------------|-----------|--------------|--------------------------------------------------------------------| 60 | | direction | `String` | `"vertical"` | Could be 'horizontal' or 'vertical' (for vertical slider). | 61 | | mousewheel-control | `Boolean` | `true` | Set to true to enable navigation through slides using mouse wheel. | 62 | | pagination-visible | `Boolean` | `false` | Toggle (hide/true) pagination container visibility when click on Slider's container | 63 | | pagination-clickable | `Boolean` | `false` | If true then clicking on pagination button will cause transition to appropriate slide. | 64 | | performace-mode | `Boolean` | `false` | Disable advance effect for better performance. | 65 | | loop | `Boolean` | `false` | Set to true to enable continuous loop mode | 66 | | ==================== | ========= | ============ | =================== | 67 | 68 | ### Methods 69 | | Method | Description | 70 | |-------------------|--------------------------| 71 | | next() | Go next page. | 72 | | prev() | Go previous page. | 73 | | setPage(`Number`) | Set current page number. | 74 | 75 | ### Events 76 | | Name | Parameters | Description | 77 | |--------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------| 78 | | slide-change-start | `pageNumber` | Fire in the beginning of animation to other slide (next or previous). | 79 | | slide-change-end | `pageNumber` | Will be fired after animation to other slide (next or previous). | 80 | | slide-revert-start | `pageNumber` | Fire in the beginning of animation to revert slide (no change). | 81 | | slide-revert-end | `pageNumber` | Will be fired after animation to revert slide (no change). | 82 | | slider-move | `offset` | Callback function, will be executed when user touch and move finger over Swiper and move it. Receives swiper instance and 'touchmove' event as an arguments. | 83 | | ================== | ================ | ============================ | 84 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue-swiper DEMO 6 | 8 | 108 | 109 | 110 |

vue-swiper demo

111 |

Vertical

112 | 119 |

o
120 |
Page {{n}}
121 |
122 |

Horizontal

123 | 126 |
{{slideText}}
127 |
128 |

Loop Mode / Infinite Loop

129 | 133 |
{{slideText}}
134 |
135 |

Append Child

136 |
137 | 138 |
139 |

Different children size

140 | 141 |

o
142 |
Page {{n}}
143 |
144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /dist/vue-swiper.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * vue-swiper v0.5.0 3 | * Swiper component. Easy to use. 4 | * https://github.com/weilao/vue-swiper 5 | * @author weilao 6 | */ 7 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.VueSwiper=e():t.VueSwiper=e()}(this,function(){return function(t){function e(n){if(i[n])return i[n].exports;var s=i[n]={exports:{},id:n,loaded:!1};return t[n].call(s.exports,s,s.exports,e),s.loaded=!0,s.exports}var i={};return e.m=t,e.c=i,e.p="/",e(0)}([function(t,e,i){var n,s;i(1),n=i(5),s=i(6),t.exports=n||{},t.exports.__esModule&&(t.exports=t.exports["default"]),s&&(("function"==typeof t.exports?t.exports.options||(t.exports.options={}):t.exports).template=s)},function(t,e,i){var n=i(2);"string"==typeof n&&(n=[[t.id,n,""]]);i(4)(n,{});n.locals&&(t.exports=n.locals)},function(t,e,i){e=t.exports=i(3)(),e.push([t.id,".swiper{position:relative;overflow:hidden}.swiper .swiper-wrap{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:100%;height:100%;-webkit-transition:all 0ms ease;transition:all 0ms ease}.swiper .swiper-wrap>div{overflow:hidden;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;width:100%;height:100%}.swiper.horizontal .swiper-wrap{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}.swiper.vertical .swiper-wrap{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.swiper .swiper-pagination{position:absolute}.swiper .swiper-pagination .swiper-pagination-bullet{width:8px;height:8px;border-radius:50%;background-color:#000;opacity:.2;-webkit-transition:all .5s ease;transition:all .5s ease}.swiper .swiper-pagination .swiper-pagination-bullet.active{background:#007aff;opacity:1}.swiper.vertical .swiper-pagination{right:10px;top:50%;-webkit-transform:translate3d(0,-50%,0);transform:translate3d(0,-50%,0)}.swiper.vertical .swiper-pagination .swiper-pagination-bullet{display:block;margin:6px 0}.swiper.horizontal .swiper-pagination{bottom:10px;width:100%;text-align:center}.swiper.horizontal .swiper-pagination .swiper-pagination-bullet{display:inline-block;margin:0 3px}",""])},function(t,e){t.exports=function(){var t=[];return t.toString=function(){for(var t=[],e=0;e=0&&m.splice(e,1)}function a(t){var e=document.createElement("style");return e.type="text/css",r(t,e),e}function l(t,e){var i,n,s;if(e.singleton){var r=v++;i=g||(g=a(e)),n=h.bind(null,i,r,!1),s=h.bind(null,i,r,!0)}else i=a(e),n=u.bind(null,i),s=function(){o(i)};return n(t),function(e){if(e){if(e.css===t.css&&e.media===t.media&&e.sourceMap===t.sourceMap)return;n(t=e)}else s()}}function h(t,e,i,n){var s=i?"":n.css;if(t.styleSheet)t.styleSheet.cssText=w(e,s);else{var r=document.createTextNode(s),o=t.childNodes;o[e]&&t.removeChild(o[e]),o.length?t.insertBefore(r,o[e]):t.appendChild(r)}}function u(t,e){var i=e.css,n=e.media,s=e.sourceMap;if(n&&t.setAttribute("media",n),s&&(i+="\n/*# sourceURL="+s.sources[0]+" */",i+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(s))))+" */"),t.styleSheet)t.styleSheet.cssText=i;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(i))}}var d={},c=function(t){var e;return function(){return"undefined"==typeof e&&(e=t.apply(this,arguments)),e}},p=c(function(){return/msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase())}),f=c(function(){return document.head||document.getElementsByTagName("head")[0]}),g=null,v=0,m=[];t.exports=function(t,e){e=e||{},"undefined"==typeof e.singleton&&(e.singleton=p()),"undefined"==typeof e.insertAt&&(e.insertAt="bottom");var i=s(t);return n(i,e),function(t){for(var r=[],o=0;o-1}},mousewheelControl:{type:Boolean,"default":!0},performanceMode:{type:Boolean,"default":!1},paginationVisible:{type:Boolean,"default":!1},paginationClickable:{type:Boolean,"default":!1},loop:{type:Boolean,"default":!1},speed:{type:Number,"default":500}},data:function(){return{currentPage:1,lastPage:1,translateX:0,translateY:0,startTranslate:0,delta:0,dragging:!1,startPos:null,transitioning:!1,slideEls:[],translateOffset:0,transitionDuration:0}},ready:function(){this._onTouchMove=this._onTouchMove.bind(this),this._onTouchEnd=this._onTouchEnd.bind(this),this.slideEls=[].map.call(this.$els.swiperWrap.children,function(t){return t}),this.loop?this.$nextTick(function(){this._createLoop(),this.setPage(this.currentPage,!0)}):this.setPage(this.currentPage)},methods:{next:function(){var t=this.currentPage;t1||this.loop?this.setPage(t-1):this._revert()},setPage:function(t,e){var i=this;if(this.lastPage=this.currentPage,0===t?this.currentPage=this.slideEls.length:t===this.slideEls.length+1?this.currentPage=1:this.currentPage=t,this.loop)0===this.delta&&this._setTranslate(i._getTranslateOfPage(this.lastPage)),setTimeout(function(){i._setTranslate(i._getTranslateOfPage(t)),e||i._onTransitionStart()},0);else{if(this._setTranslate(this._getTranslateOfPage(t)),e)return;this._onTransitionStart()}},isHorizontal:function(){return this.direction===n},isVertical:function(){return this.direction===i},_onTouchStart:function(t){this.startPos=this._getTouchPos(t),this.delta=0,this.startTranslate=this._getTranslateOfPage(this.currentPage),this.startTime=(new Date).getTime(),this.dragging=!0,this.transitionDuration=0,document.addEventListener("touchmove",this._onTouchMove,!1),document.addEventListener("touchend",this._onTouchEnd,!1),document.addEventListener("mousemove",this._onTouchMove,!1),document.addEventListener("mouseup",this._onTouchEnd,!1)},_onTouchMove:function(t){this.delta=this._getTouchPos(t)-this.startPos,this.performanceMode||(this._setTranslate(this.startTranslate+this.delta),this.$emit("slider-move",this._getTranslate())),(this.isVertical()||this.isHorizontal()&&Math.abs(this.delta)>0)&&t.preventDefault()},_onTouchEnd:function(t){this.dragging=!1,this.transitionDuration=this.speed;var e=(new Date).getTime()-this.startTime<1e3;this.delta<-100||e&&this.delta<-15?this.next():this.delta>100||e&&this.delta>15?this.prev():this._revert(),document.removeEventListener("touchmove",this._onTouchMove),document.removeEventListener("touchend",this._onTouchEnd),document.removeEventListener("mousemove",this._onTouchMove),document.removeEventListener("mouseup",this._onTouchEnd)},_onWheel:function(t){this.mousewheelControl&&(this.transitioning||(t.deltaY>0?this.next():this.prev()),this._isPageChanged()&&t.preventDefault())},_revert:function(){this.setPage(this.currentPage)},_getTouchPos:function(t){var e=this.isHorizontal()?"pageX":"pageY";return t.changedTouches?t.changedTouches[0][e]:t[e]},_onTransitionStart:function(){this.transitioning=!0,this.transitionDuration=this.speed,this._isPageChanged()?this.$emit("slide-change-start",this.currentPage):this.$emit("slide-revert-start",this.currentPage)},_onTransitionEnd:function(){this.transitioning=!1,this.transitionDuration=0,this.delta=0,this._isPageChanged()?this.$emit("slide-change-end",this.currentPage):this.$emit("slide-revert-end",this.currentPage)},_isPageChanged:function(){return this.lastPage!==this.currentPage},_setTranslate:function(t){var e=this.isHorizontal()?"translateX":"translateY";this[e]=t},_getTranslate:function(){var t=this.isHorizontal()?"translateX":"translateY";return this[t]},_getTranslateOfPage:function(t){if(0===t)return 0;var e=this.isHorizontal()?"clientWidth":"clientHeight";return-[].reduce.call(this.slideEls,function(i,n,s){return s>t-2?i:i+n[e]},0)+this.translateOffset},_createLoop:function(){var t=this.isHorizontal()?"clientWidth":"clientHeight",e=this.$els.swiperWrap,i=e.firstElementChild.cloneNode(!0),n=e.lastElementChild.cloneNode(!0);e.insertBefore(n,e.firstElementChild),e.appendChild(i),this.translateOffset=-n[t]}}}},function(t,e){t.exports="
"}])}); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-swiper", 3 | "version": "0.5.0", 4 | "description": "Swiper component. Easy to use.", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/weilao/vue-swiper.git" 8 | }, 9 | "author": "weilao", 10 | "license": "MIT", 11 | "bugs": { 12 | "url": "https://github.com/weilao/vue-swiper/issues" 13 | }, 14 | "homepage": "https://github.com/weilao/vue-swiper", 15 | "main": "dist/vue-swiper.js", 16 | "scripts": { 17 | "dev": "NODE_ENV=dev webpack-dev-server --inline --hot --host 0.0.0.0 --config webpack.config.js", 18 | "build": "webpack" 19 | }, 20 | "devDependencies": { 21 | "autoprefixer": "^6.3.6", 22 | "babel-core": "^6.8.0", 23 | "babel-loader": "^6.2.4", 24 | "babel-plugin-transform-runtime": "^6.8.0", 25 | "babel-preset-es2015": "^6.6.0", 26 | "babel-runtime": "^6.6.1", 27 | "css-loader": "^0.23.1", 28 | "less": "^2.7.0", 29 | "less-loader": "^2.2.3", 30 | "vue-hot-reload-api": "^1.3.2", 31 | "vue-html-loader": "^1.2.2", 32 | "vue-loader": "^8.3.1", 33 | "vue-style-loader": "^1.0.0", 34 | "webpack": "^1.13.0", 35 | "webpack-dev-server": "^1.14.1" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/vue-swiper.less: -------------------------------------------------------------------------------- 1 | .swiper { 2 | position: relative; 3 | overflow: hidden; 4 | 5 | .swiper-wrap { 6 | display: flex; 7 | width: 100%; 8 | height: 100%; 9 | transition: all 0ms ease; 10 | 11 | > div { 12 | overflow: hidden; 13 | flex-shrink: 0; 14 | width: 100%; 15 | height: 100%; 16 | } 17 | } 18 | 19 | &.horizontal .swiper-wrap { 20 | flex-direction: row; 21 | } 22 | 23 | &.vertical .swiper-wrap { 24 | flex-direction: column; 25 | } 26 | 27 | .swiper-pagination { 28 | position: absolute; 29 | 30 | .swiper-pagination-bullet { 31 | width: 8px; 32 | height: 8px; 33 | border-radius: 50%; 34 | background-color: #000000; 35 | opacity: .2; 36 | transition: all .5s ease; 37 | } 38 | 39 | .swiper-pagination-bullet.active { 40 | background: #007aff; 41 | opacity: 1; 42 | } 43 | } 44 | 45 | &.vertical .swiper-pagination { 46 | right: 10px; 47 | top: 50%; 48 | transform: translate3d(0, -50%, 0); 49 | 50 | .swiper-pagination-bullet { 51 | display: block; 52 | margin: 6px 0; 53 | } 54 | } 55 | 56 | &.horizontal .swiper-pagination { 57 | bottom: 10px; 58 | width: 100%; 59 | text-align: center; 60 | 61 | .swiper-pagination-bullet { 62 | display: inline-block; 63 | margin: 0 3px; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/vue-swiper.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 257 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var autoprefixer = require('autoprefixer'); 4 | var pkg = require('./package.json'); 5 | var banner = `${pkg.name} v${pkg.version}\n${pkg.description}\n${pkg.homepage}\n@author ${pkg.author}`; 6 | module.exports = { 7 | entry: { 8 | 'vue-swiper': path.join(__dirname, 'src/vue-swiper.vue') 9 | }, 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | publicPath: '/', 13 | library: 'VueSwiper', 14 | libraryTarget: 'umd', 15 | filename: "[name].js" 16 | }, 17 | module: { 18 | loaders: [ 19 | {test: /\.js$/, loader: 'babel', exclude: /node_modules/}, 20 | {test: /\.vue$/, loader: 'vue'}, 21 | {test: /\.less$/, loader: "css?sourceMap!postcss!less?sourceMap"} 22 | ] 23 | }, 24 | postcss: [autoprefixer({browsers: ['last 2 versions', 'Android 2.3']})], 25 | babel: { 26 | "presets": ["es2015"] 27 | }, 28 | plugins: [] 29 | }; 30 | 31 | if (process.env.NODE_ENV === 'dev') { 32 | module.exports.devtool = '#eval-source-map'; 33 | } else { 34 | module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin()); 35 | module.exports.plugins.push(new webpack.BannerPlugin(banner)); 36 | } 37 | --------------------------------------------------------------------------------