├── .babelrc ├── .gitignore ├── .postcssrc.js ├── LICENSE ├── README.md ├── build ├── client.js ├── compile.js ├── server.js ├── webpack.compile.js └── webpack.dev.js ├── demo.gif ├── index.html ├── package.json ├── src ├── App.vue ├── main.js └── vue-better-slider │ ├── common │ └── js │ │ └── dom.js │ ├── components │ ├── slider-item.vue │ └── slider.vue │ └── index.js ├── static └── package.json └── vue-better-slider ├── index.js └── package.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["env",{ 3 | "modules": false 4 | }], "stage-0"] 5 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log* 4 | /vue-better-slider -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "plugins": { 3 | "autoprefixer": { 4 | browsers:["> 1%", "last 20 versions", "not ie <= 8"] 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 songhao 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-better-slider 2 | 3 | ## 这是什么(What is it) 4 | 为vue提供的一个轮播图组件 5 | 6 | ## 代码演示如何使用 7 | 8 | npm install vue-better-slider --save 9 | 10 | ### 1.main.js引入样式文件 11 | ```js 12 | import 'vue-better-slider/style.css' 13 | 14 | ``` 15 | ### 2.导入并注册组件,注册组件 16 | ```js 17 | import {IcSlider,IcSliderItem} from 'vue-better-slider' 18 | components: { 19 | IcSlider, 20 | IcSliderItem 21 | } 22 | ``` 23 | ### 3.template模板 24 | ```html 25 | 26 | 27 | 28 | 29 | 30 | ``` 31 | 32 | ```js 33 | export default { 34 | data() { 35 | return { 36 | images: [ 37 | { 38 | linkUrl: 'http://y.qq.com/w/album.html?albummid=0044K2vN1sT5mE', 39 | picUrl: 'http://y.gtimg.cn/music/photo_new/T003R720x288M000001YCZlY3aBifi.jpg', 40 | id: 11351 41 | }, 42 | { 43 | linkUrl: 'https://y.qq.com/m/digitalbum/gold/index.html?_video=true&id=2197820&g_f=shoujijiaodian', 44 | picUrl: 'http://y.gtimg.cn/music/photo_new/T003R720x288M000004ckGfg3zaho0.jpg', 45 | id: 11372 46 | }, 47 | { 48 | linkUrl: 'http://y.qq.com/w/album.html?albummid=001tftZs2RX1Qz', 49 | picUrl: 'http://y.gtimg.cn/music/photo_new/T003R720x288M00000236sfA406cmk.jpg', 50 | id: 11378 51 | }, 52 | { 53 | linkUrl: 'https://y.qq.com/msa/218/0_4085.html', 54 | picUrl: 'http://y.gtimg.cn/music/photo_new/T003R720x288M000001s0BXx3Zxcwb.jpg', 55 | id: 11375 56 | }, 57 | { 58 | linkUrl: 'https://y.qq.com/m/digitalbum/gold/index.html?_video=true&id=2195876&g_f=shoujijiaodian', 59 | picUrl: 'http://y.gtimg.cn/music/photo_new/T003R720x288M000002cwng4353HKz.jpg', 60 | id: 11287 61 | } 62 | ] 63 | } 64 | } 65 | } 66 | ``` 67 | ## 组件演示demo 68 | 69 | ```js 70 | git clone https://github.com/songhaoreact/vue-better-slider.git 71 | cd vue-better-slier 72 | npm install 73 | npm run dev 74 | ``` 75 | 76 | ## 效果图 77 | 78 | ![image](http://oij04cgoe.bkt.clouddn.com/demo.gif) 79 | 80 | ## 说明 81 | 82 | 实现功能有:轮播 自动播放 dots 循环播放,适合手机端,图片高度自适应 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /build/client.js: -------------------------------------------------------------------------------- 1 | // 主要就是为了实现页面刷新的时候错误提示依旧在 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /build/compile.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const webpackConfig = require('./webpack.compile'); 3 | const rm = require('rimraf'); 4 | const cp = require('shelljs').cp; 5 | const path = require('path'); 6 | const chalk = require('chalk'); 7 | const fs = require('fs'); 8 | const semver = require('semver'); 9 | const src = path.resolve(process.cwd(), 'static'); 10 | const packageJson = src + '/package.json'; 11 | const name = require(packageJson).name; 12 | 13 | const target = path.resolve(process.cwd(), name); 14 | 15 | rm(path.resolve(process.cwd() , name), err => { 16 | if (err) { 17 | console.log(err) 18 | } else { 19 | webpack(webpackConfig, function(err, stats) { 20 | process.stdout.write(stats.toString({ 21 | colors: true, 22 | modules: false, 23 | children: false, 24 | chunks: false, 25 | chunkModules: false 26 | }) + '\n\n'); 27 | // 修改版本号 28 | modifyVersion(); 29 | 30 | // 不在打包之后的目录里面放置 README.md 文件 31 | cp('-R', src + '/*', target); 32 | // cp('-R', './README.md'); 33 | 34 | console.log(); 35 | console.log(chalk.green.bold('> Compile Successed')); 36 | console.log(); 37 | }) 38 | } 39 | }); 40 | 41 | 42 | function modifyVersion() { 43 | fs.readFile(packageJson, function(err, data){ 44 | 45 | // 获取版本号 46 | let obj = JSON.parse(data.toString()); 47 | let version = obj.version; 48 | 49 | let major = semver.major(version); 50 | let minor = semver.minor(version); 51 | let patch = semver.patch(version); 52 | 53 | // 如果 patch = 10 54 | if (patch == 10) { 55 | // 再判断一下 minior 的值 是不是 10 56 | if (minor == 10) { 57 | major = major + 1; 58 | minor = 0; 59 | patch = 0; 60 | } else { 61 | minor = minor + 1; 62 | patch = 0; 63 | } 64 | } else { 65 | patch = patch + 1; 66 | } 67 | // 重新修改 版本号 68 | obj.version = major + '.' + minor + '.' + patch; 69 | fs.writeFile(packageJson, JSON.stringify(obj, null, 4)) 70 | }) 71 | } -------------------------------------------------------------------------------- /build/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const webpack = require('webpack'); 3 | 4 | const webpackDevMiddleware = require('webpack-dev-middleware'); 5 | const webpackHotMiddleware = require('webpack-hot-middleware'); 6 | 7 | const webpackConfig = require('./webpack.dev'); 8 | const compiler = webpack(webpackConfig); 9 | 10 | const opn = require('opn'); 11 | 12 | const chalk = require('chalk'); 13 | 14 | const app = express(); 15 | 16 | // 这个玩意可以直接给个随机数 17 | 18 | // 80 端口是 http 协议的专用端口, 专用端口! 19 | const port = parseInt(Math.random() * 10000) + 5000; 20 | // const port = '80'; 21 | // 设置 webpackDevMiddleware 22 | const devMiddleware = webpackDevMiddleware(compiler, { 23 | publicPath: '/', 24 | // 这个字段为 true 会删掉每次 hot reload 的时候输出到 cmd 里面的打包信息 25 | quiet: true 26 | }); 27 | 28 | const hotMiddleware = webpackHotMiddleware(compiler, { 29 | log: () => {} 30 | }) 31 | 32 | /* 33 | 当 vue-router 开启 histroy 的时候, 就需要这个插件 34 | : 这个玩意的顺序必须要在这里, 不能在 devMiddleware, hotMiddleware 后面 35 | // handle fallback for HTML5 history API 36 | */ 37 | 38 | app.use(require('connect-history-api-fallback')()) 39 | 40 | app.use(devMiddleware); 41 | 42 | // hot-reload 43 | app.use(hotMiddleware); 44 | 45 | // 挂载到虚拟路径上面 46 | app.use('/static', express.static('./static')); 47 | 48 | // 监听路径 49 | app.listen(port, function(){ 50 | console.log(chalk.green.bold('> Listening on port: http://localhost:' + port +'/')); 51 | console.log(); 52 | }); 53 | 54 | // 打包成功之后会触发这个玩意 55 | devMiddleware.waitUntilValid(function(err){ 56 | // 打开浏览器 57 | opn('http://localhost:' + port) 58 | }); 59 | -------------------------------------------------------------------------------- /build/webpack.compile.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | // 不需要打包的文件 6 | const externals = { 7 | 'vue': 'vue', 8 | 'lodash/merge': 'lodash/merge' 9 | } 10 | 11 | const packageJson = path.resolve(process.cwd(), 'static') + '/package.json'; 12 | const name = require(packageJson).name; 13 | 14 | const config = { 15 | node: { 16 | Buffer: false 17 | }, 18 | entry: { 19 | app: './src/' + name + '/' + 'index.js' 20 | }, 21 | output: { 22 | path: path.resolve(process.cwd(), name), 23 | filename: 'index.js', 24 | publicPath: '/', 25 | libraryTarget: "commonjs2" 26 | }, 27 | resolve: { 28 | extensions: ['.js', '.json', '.vue'] 29 | }, 30 | externals: externals, 31 | module: { 32 | rules: [{ 33 | test: /\.css$/, 34 | use: ExtractTextPlugin.extract({ 35 | use: 'css-loader?minimize!postcss-loader' 36 | }) 37 | }, { 38 | test: /\.styl$/, 39 | use: ExtractTextPlugin.extract({ 40 | use: 'css-loader?minimize!postcss-loader!stylus-loader' 41 | }) 42 | }, { 43 | test: /\.js$/, 44 | loader: 'babel-loader', 45 | include: [path.resolve(process.cwd(), 'src')], 46 | }, { 47 | test: /\.vue$/, 48 | loader: 'vue-loader', 49 | options: { 50 | loaders: { 51 | css: ExtractTextPlugin.extract({ 52 | use: 'css-loader?minimize', 53 | }), 54 | 55 | less: ExtractTextPlugin.extract({ 56 | use: 'css-loader?minimize!postcss-loader!less-loader', 57 | }) 58 | // css:'css-loader?minimize', 59 | 60 | // less: 'css-loader?minimize!postcss-loader!less-loader' 61 | 62 | 63 | } 64 | } 65 | }, { 66 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 67 | loader: 'url-loader', 68 | query: { 69 | limit: 1000 * 5, 70 | name: '[name].[hash:7].[ext]' 71 | } 72 | }, { 73 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 74 | loader: 'url-loader', 75 | query: { 76 | limit: 1000 * 5, 77 | name: '[name].[hash:7].[ext]' 78 | } 79 | }] 80 | }, 81 | plugins: [ 82 | new webpack.optimize.UglifyJsPlugin({ 83 | compress: { 84 | warnings: false 85 | }, 86 | sourceMap: true 87 | }), 88 | 89 | 90 | new ExtractTextPlugin('style.css'), 91 | new webpack.LoaderOptionsPlugin({ 92 | minimize: true 93 | }) 94 | ] 95 | }; 96 | module.exports = config; -------------------------------------------------------------------------------- /build/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | // 在命令行里面的错误提示友好一点 6 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin'); 7 | 8 | const config = { 9 | entry: { 10 | // webpack-hot-middleware/client 是必须要加上的, 不然的话不会热更新 11 | // ./build/client.js 也是必须要加, 不然刷新之后错误提示就会失效 12 | app: [ './build/client.js','./src/main.js','webpack-hot-middleware/client'] 13 | }, 14 | // 开发环境需要开启 devtool, 这样方便调试, 因为可以直接通过错误到达具体的文件 15 | devtool: '#cheap-module-eval-source-map', 16 | output: { 17 | path: path.resolve(process.cwd(), 'dist'), 18 | filename: '[name].[hash:7].js', 19 | }, 20 | resolve: { 21 | extensions: ['.js', '.json', '.vue'], 22 | alias: { 23 | 'vue$': 'vue/dist/vue.esm.js', 24 | } 25 | }, 26 | module: { 27 | rules: [ 28 | { 29 | test: /\.styl$/, 30 | use: ['style-loader', 'css-loader', 'postcss-loader', 'stylus-loader'] 31 | }, 32 | { 33 | test: /\.css$/, 34 | // 这个后面不能加上 postcss-loader 35 | // 加上之后报错: 所有的 css 文件都找不到 36 | use: ['style-loader', 'css-loader'] 37 | }, 38 | 39 | { 40 | test: /\.js$/, 41 | loader: 'babel-loader', 42 | query: { 43 | compact: false 44 | }, 45 | include: [path.resolve(process.cwd(), 'src')], 46 | }, 47 | 48 | { 49 | test: /\.vue$/, 50 | loader: 'vue-loader', 51 | 52 | }, { 53 | 54 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 55 | loader: 'url-loader', 56 | query: { 57 | limit: 1000 * 10, 58 | 59 | name: './static/[name].[hash:7].[ext]' 60 | } 61 | 62 | }, { 63 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 64 | loader: 'url-loader', 65 | query: { 66 | limit: 1000 * 10, 67 | name: './static/[name].[hash:7].[ext]' 68 | } 69 | 70 | } 71 | ] 72 | }, 73 | plugins: [ 74 | new FriendlyErrorsPlugin(), 75 | new webpack.HotModuleReplacementPlugin(), 76 | new HtmlWebpackPlugin({ 77 | template: './index.html' 78 | }), 79 | // 定义全局变量 80 | new webpack.DefinePlugin({ 81 | // 直接使用 env 对象 82 | 'process.env': '"development"' 83 | }) 84 | ] 85 | }; 86 | 87 | module.exports = config; -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openfe-openfe/vue-better-slider/29bd6d659ff369820eb2ea912427188d6ac47911/demo.gif -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-better-slider", 3 | "version": "1.0.3", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "node build/server.js", 8 | "compile": "node build/compile.js && npm publish ./vue-better-slider" 9 | }, 10 | "author": "songhao", 11 | "license": "MIT", 12 | "dependencies": { 13 | "babel-core": "^6.24.0", 14 | "babel-loader": "^6.4.1", 15 | "babel-plugin-transform-runtime": "^6.23.0", 16 | "babel-preset-env": "^1.3.3", 17 | "babel-preset-es2015": "^6.24.0", 18 | "babel-preset-stage-0": "^6.22.0", 19 | "better-scroll": "^1.3.0", 20 | "clean-webpack-plugin": "^0.1.16", 21 | "connect-history-api-fallback": "^1.3.0", 22 | "css-loader": "^0.27.3", 23 | "eventsource-polyfill": "^0.9.6", 24 | "express": "^4.15.2", 25 | "extract-text-webpack-plugin": "^2.1.0", 26 | "file-loader": "^0.10.1", 27 | "friendly-errors-webpack-plugin": "^1.6.1", 28 | "html-webpack-plugin": "^2.28.0", 29 | "lodash": "^4.17.4", 30 | "opn": "^4.0.2", 31 | "postcss-loader": "^1.3.3", 32 | "rimraf": "^2.6.1", 33 | "semver": "^5.3.0", 34 | "shelljs": "^0.7.7", 35 | "style-loader": "^0.16.1", 36 | "stylus": "^0.54.5", 37 | "stylus-loader": "^2.1.1", 38 | "uglify-js": "^2.8.0", 39 | "uglifyjs-webpack-plugin": "^0.3.1", 40 | "url-loader": "^0.5.8", 41 | "vue": "^2.2.6", 42 | "vue-loader": "^11.3.3", 43 | "vue-router": "^2.3.0", 44 | "vue-template-compiler": "^2.2.6", 45 | "webpack": "^2.3.2", 46 | "webpack-dev-middleware": "^1.10.1", 47 | "webpack-hot-middleware": "^2.17.1" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 52 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | 4 | new Vue({ 5 | el: '#app', 6 | render: h => h(App) 7 | }); -------------------------------------------------------------------------------- /src/vue-better-slider/common/js/dom.js: -------------------------------------------------------------------------------- 1 | export function hasClass(el, className) { 2 | let reg = new RegExp('(^|\\s)' + className + '(\\s|$)') 3 | return reg.test(el.className) 4 | } 5 | 6 | export function addClass(el, className) { 7 | if (hasClass(el, className)) { 8 | return 9 | } 10 | 11 | let newClass = el.className.split(' ') 12 | newClass.push(className) 13 | el.className = newClass.join(' ') 14 | } 15 | 16 | export function getData(el, name, val) { 17 | const prefix = 'data-' 18 | if (val) { 19 | return el.setAttribute(prefix + name, val) 20 | } 21 | return el.getAttribute(prefix + name) 22 | } 23 | 24 | let elementStyle = document.createElement('div').style 25 | 26 | let vendor = (() => { 27 | let transformNames = { 28 | webkit: 'webkitTransform', 29 | Moz: 'MozTransform', 30 | O: 'OTransform', 31 | ms: 'msTransform', 32 | standard: 'transform' 33 | } 34 | 35 | for (let key in transformNames) { 36 | if (elementStyle[transformNames[key]] !== undefined) { 37 | return key 38 | } 39 | } 40 | 41 | return false 42 | })() 43 | 44 | export function prefixStyle(style) { 45 | if (vendor === false) { 46 | return false 47 | } 48 | 49 | if (vendor === 'standard') { 50 | return style 51 | } 52 | 53 | return vendor + style.charAt(0).toUpperCase() + style.substr(1) 54 | } 55 | -------------------------------------------------------------------------------- /src/vue-better-slider/components/slider-item.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /src/vue-better-slider/components/slider.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 171 | 172 | -------------------------------------------------------------------------------- /src/vue-better-slider/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import IcSlider from './components/slider' 3 | import IcSliderItem from './components/slider-item' 4 | export { 5 | IcSlider, 6 | IcSliderItem 7 | } -------------------------------------------------------------------------------- /static/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-better-slider", 3 | "version": "1.1.1", 4 | "main": "index.js", 5 | "scripts": {}, 6 | "author": "songhao", 7 | "license": "MIT", 8 | "devDependencies": { 9 | "babel-preset-env": "^1.3.3", 10 | "babel-preset-stage-0": "^6.24.1", 11 | "vue": "^2.2.6" 12 | } 13 | } -------------------------------------------------------------------------------- /vue-better-slider/index.js: -------------------------------------------------------------------------------- 1 | module.exports=function(t){function i(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,i),o.l=!0,o.exports}var e={};return i.m=t,i.c=e,i.i=function(t){return t},i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:n})},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,i){return Object.prototype.hasOwnProperty.call(t,i)},i.p="/",i(i.s=6)}([function(t,i){t.exports=function(t,i,e,n){var o,s=t=t||{},r=typeof t.default;"object"!==r&&"function"!==r||(o=t,s=t.default);var c="function"==typeof s?s.options:s;if(i&&(c.render=i.render,c.staticRenderFns=i.staticRenderFns),e&&(c._scopeId=e),n){var u=Object.create(c.computed||null);Object.keys(n).forEach(function(t){var i=n[t];u[t]=function(){return i}}),c.computed=u}return{esModule:o,exports:s,options:c}}},function(t,i,e){var n=e(0)(e(4),e(8),null,null);t.exports=n.exports},function(t,i,e){e(7);var n=e(0)(e(5),e(9),null,null);t.exports=n.exports},function(t,i){t.exports=require("vue")},function(t,i,e){"use strict";Object.defineProperty(i,"__esModule",{value:!0}),i.default={name:"ic-slider-item",data:function(){return{offset:0}},computed:{style:function(){return{width:this.$parent.width+"px",transform:"translate3d("+this.offset+"px, 0, 0)"}}},beforeCreate:function(){this.$parent.swipes.push(this)},destroyed:function(){this.$parent.swipes.splice(this.$parent.swipes.indexOf(this),1)}}},function(t,i,e){"use strict";Object.defineProperty(i,"__esModule",{value:!0}),i.default={name:"ic-slider",props:{autoplay:Number,showIndicators:{type:Boolean,default:!0},duration:{type:Number,default:500}},data:function(){return{width:0,offset:0,startX:0,startY:0,active:0,deltaX:0,swipes:[],direction:"",currentDuration:0}},mounted:function(){var t=this;this.initialize(),window.addEventListener("resize",function(){t.initialize()})},destroyed:function(){clearTimeout(this.timer)},watch:{swipes:function(){this.initialize()}},computed:{count:function(){return this.swipes.length},trackStyle:function(){return{paddingLeft:this.width+"px",width:(this.count+2)*this.width+"px",transitionDuration:this.currentDuration+"ms",transform:"translate3d("+this.offset+"px, 0, 0)"}},activeIndicator:function(){return(this.active+this.count)%this.count}},methods:{initialize:function(){clearTimeout(this.timer),this.width=this.$el.getBoundingClientRect().width,this.active=0,this.currentDuration=0,this.offset=this.count>1?-this.width:0,this.swipes.forEach(function(t){t.offset=0}),this.autoPlay()},onTouchStart:function(t){clearTimeout(this.timer),this.deltaX=0,this.direction="",this.currentDuration=0,this.startX=t.touches[0].clientX,this.startY=t.touches[0].clientY,this.active<=-1&&this.move(this.count),this.active>=this.count&&this.move(-this.count)},onTouchMove:function(t){this.direction=this.direction||this.getDirection(t.touches[0]),"horizontal"===this.direction&&(t.preventDefault(),this.deltaX=t.touches[0].clientX-this.startX,this.move(0,this.range(this.deltaX,[-this.width,this.width])))},onTouchEnd:function(){this.deltaX&&(this.move(Math.abs(this.deltaX)>50?this.deltaX>0?-1:1:0),this.currentDuration=this.duration),this.autoPlay()},move:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,e=this.active,n=this.count,o=this.swipes,s=this.deltaX,r=this.width;t?(-1===e&&(o[n-1].offset=0),o[0].offset=e===n-1&&t>0?n*r:0,this.active+=t):0===e?o[n-1].offset=s>0?-n*r:0:e===n-1&&(o[0].offset=s<0?n*r:0),this.offset=i-(this.active+1)*this.width},autoPlay:function(){var t=this,i=this.autoplay;i&&this.count>1&&(clearTimeout(this.timer),this.timer=setTimeout(function(){t.currentDuration=0,t.active>=t.count&&t.move(-t.count),setTimeout(function(){t.currentDuration=t.duration,t.move(1),t.autoPlay()},30)},i))},getDirection:function(t){var i=Math.abs(t.clientX-this.startX),e=Math.abs(t.clientY-this.startY);return i>e?"horizontal":i1?e("div",{staticClass:"ic-slider__track",style:t.trackStyle,on:{touchstart:t.onTouchStart,touchmove:t.onTouchMove,touchend:t.onTouchEnd,touchcancel:t.onTouchEnd,transitionend:function(i){return t.$emit("change",t.activeIndicator)}}},[t._t("default")],2):e("div",{staticClass:"ic-slider__track"},[t._t("default")],2),t._v(" "),t.showIndicators&&t.count>1?e("div",{staticClass:"ic-slider__indicators"},t._l(t.count,function(i){return e("i",{class:{"ic-slider__indicator--active":i-1===t.activeIndicator}})}),0):t._e()])},staticRenderFns:[]}}]); -------------------------------------------------------------------------------- /vue-better-slider/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-better-slider", 3 | "version": "1.1.0", 4 | "main": "index.js", 5 | "scripts": {}, 6 | "author": "songhao", 7 | "license": "MIT", 8 | "devDependencies": { 9 | "babel-preset-env": "^1.3.3", 10 | "babel-preset-stage-0": "^6.24.1", 11 | "vue": "^2.2.6" 12 | } 13 | } --------------------------------------------------------------------------------