├── example ├── card │ ├── card.json │ ├── card.wxml │ ├── card.wxss │ └── card.js ├── general │ ├── general.json │ ├── general.wxml │ ├── general.wxss │ └── general.js └── dashboard │ ├── dashboard.js │ ├── dashboard.json │ ├── dashboard.wxss │ └── dashboard.wxml ├── .babelrc ├── .gitignore ├── screenshots ├── Gif_20170401_013701.gif └── Gif_20170401_013729.gif ├── app.wxss ├── src ├── syncView.js ├── exception.js ├── animate.js ├── controller.js ├── default.js ├── handle.js ├── main.js └── methods.js ├── package.json ├── app.json ├── app.js ├── LICENSE ├── dist ├── weSwiper.wxss └── weSwiper.js └── README.md /example/card/card.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /example/general/general.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/dashboard/dashboard.js: -------------------------------------------------------------------------------- 1 | Page({}) 2 | -------------------------------------------------------------------------------- /example/dashboard/dashboard.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { "presets": ["es2015-rollup"] } 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | node_modules/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* -------------------------------------------------------------------------------- /screenshots/Gif_20170401_013701.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we-plugin/we-swiper/HEAD/screenshots/Gif_20170401_013701.gif -------------------------------------------------------------------------------- /screenshots/Gif_20170401_013729.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we-plugin/we-swiper/HEAD/screenshots/Gif_20170401_013729.gif -------------------------------------------------------------------------------- /app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | .container { 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | justify-content: space-between; 8 | padding: 200rpx 0; 9 | box-sizing: border-box; 10 | } 11 | -------------------------------------------------------------------------------- /src/syncView.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by sail on 2017/4/1. 3 | */ 4 | export default { 5 | /** 6 | * 同步设置到视图 7 | * @param DEFAULT:默认参数 8 | * @param param:构造参数 9 | */ 10 | syncView (viewName, prop) { 11 | this.pageContext.setData({ 12 | [`${viewName}`]: prop 13 | }) 14 | } 15 | } -------------------------------------------------------------------------------- /src/exception.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by sail on 2017/4/1. 3 | */ 4 | const ERROR = { 5 | 'paramType': '参数类型错误', 6 | 'bound': '参数越界' 7 | } 8 | 9 | export default { 10 | /** 11 | * 错误对照 12 | */ 13 | consoleException (type, place) { 14 | console.error(`%c${place}:${ERROR[type]}`, 'color: red') 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "we-swiper", 3 | "version": "0.1.0", 4 | "main": "dist/weSwiper.js", 5 | "scripts": { 6 | "build": "node build/build.js" 7 | }, 8 | "devDependencies": { 9 | "babel-preset-es2015-rollup": "^3.0.0", 10 | "rollup": "^0.41.6", 11 | "rollup-plugin-babel": "^2.7.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages":[ 3 | "example/dashboard/dashboard", 4 | "example/general/general", 5 | "example/card/card", 6 | "example/flip/flip" 7 | ], 8 | "window":{ 9 | "backgroundTextStyle":"light", 10 | "navigationBarBackgroundColor": "#fff", 11 | "navigationBarTitleText": "WeChat", 12 | "navigationBarTextStyle":"black" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /example/card/card.wxml: -------------------------------------------------------------------------------- 1 | 2 | 7 | slide 1 8 | slide 2 9 | slide 3 10 | 11 | 12 | -------------------------------------------------------------------------------- /example/general/general.wxml: -------------------------------------------------------------------------------- 1 | 2 | 7 | slide 1 8 | slide 2 9 | slide 3 10 | 11 | -------------------------------------------------------------------------------- /example/general/general.wxss: -------------------------------------------------------------------------------- 1 | @import "../../dist/weSwiper.wxss"; 2 | 3 | /************* 个人样式 *************/ 4 | .we-slide{ 5 | display: flex; 6 | align-items: center; 7 | justify-content: center; 8 | color: #fff; 9 | font-size: 2rem; 10 | } 11 | 12 | .we-slide:nth-child(1){ 13 | background-color: #4390EE 14 | } 15 | .we-slide:nth-child(2){ 16 | background-color: #CA4040 17 | } 18 | .we-slide:nth-child(3){ 19 | background-color: #FF8604 20 | } 21 | -------------------------------------------------------------------------------- /example/card/card.wxss: -------------------------------------------------------------------------------- 1 | @import "../../dist/weSwiper.wxss"; 2 | 3 | /************* 个人样式 *************/ 4 | .we-wrapper{ 5 | width: 100%; 6 | height: 100%; 7 | padding: 75rpx 0 100rpx 100rpx; 8 | box-sizing: border-box; 9 | } 10 | .we-slide{ 11 | display: flex; 12 | align-items: center; 13 | justify-content: center; 14 | width: 500rpx; 15 | margin: 25rpx; 16 | box-sizing: border-box; 17 | color: #fff; 18 | font-size: 2rem; 19 | } 20 | 21 | .we-slide:nth-child(1){ 22 | background-color: #4390EE 23 | } 24 | .we-slide:nth-child(2){ 25 | background-color: #CA4040 26 | } 27 | .we-slide:nth-child(3){ 28 | background-color: #FF8604 29 | } 30 | -------------------------------------------------------------------------------- /example/dashboard/dashboard.wxss: -------------------------------------------------------------------------------- 1 | Page{ 2 | background-color: #f8f8f8; 3 | } 4 | 5 | .lists{ 6 | margin: 25rpx 0; 7 | border-top: 1rpx solid #d7d7d7; 8 | border-bottom: 1rpx solid #d7d7d7; 9 | background-color: #fff; 10 | } 11 | 12 | .list-item{ 13 | position: relative; 14 | width: 100%; 15 | height: 100rpx; 16 | margin-left: 25rpx; 17 | line-height: 100rpx; 18 | font-size: 32rpx; 19 | border-bottom: 1rpx solid #d7d7d7; 20 | } 21 | 22 | .list-item:after{ 23 | position: absolute; 24 | top: 50%; 25 | right: 50rpx; 26 | content: '>'; 27 | transform: translateY(-50%); 28 | color: #666; 29 | } 30 | 31 | .list-item:last-child{ 32 | border: 0; 33 | } 34 | -------------------------------------------------------------------------------- /example/dashboard/dashboard.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | we-swiper 4 | 5 | 6 | 常规 7 | 卡片 8 | flip 9 | 2D翻转 10 | 11 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch: function () { 4 | //调用API从本地缓存中获取数据 5 | var logs = wx.getStorageSync('logs') || [] 6 | logs.unshift(Date.now()) 7 | wx.setStorageSync('logs', logs) 8 | }, 9 | getUserInfo:function(cb){ 10 | var that = this 11 | if(this.globalData.userInfo){ 12 | typeof cb == "function" && cb(this.globalData.userInfo) 13 | }else{ 14 | //调用登录接口 15 | wx.login({ 16 | success: function () { 17 | wx.getUserInfo({ 18 | success: function (res) { 19 | that.globalData.userInfo = res.userInfo 20 | typeof cb == "function" && cb(that.globalData.userInfo) 21 | } 22 | }) 23 | } 24 | }) 25 | } 26 | }, 27 | globalData:{ 28 | userInfo:null 29 | } 30 | }) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Sail 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 | -------------------------------------------------------------------------------- /src/animate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by sail on 2017/4/1. 3 | */ 4 | const REG = { 5 | SPEED: /^(0|[1-9][0-9]*|-[1-9][0-9]*)$/, 6 | TIMINGFUNCTION: /linear|ease|ease-in|ease-in-out|ease-out|step-start|step-end/ 7 | } 8 | 9 | export default { 10 | /** 11 | * 平移动画 12 | * @param translate:平移位置 13 | * @param speed:过渡时长 14 | * @param timingFunction:过渡类型 15 | */ 16 | slideAnimation (translate = 0, speed = 300, timingFunction = 'ease') { 17 | const { XORY, animationViewName, consoleException } = this 18 | try { 19 | /** 20 | * 异常处理 21 | */ 22 | if(!REG.SPEED.test(speed)) throw 'paramType' 23 | if(!REG.TIMINGFUNCTION.test(timingFunction)) throw 'paramType' 24 | /** 25 | * 创建一个动画实例 26 | */ 27 | const animation = wx.createAnimation({ 28 | transformOrigin: '50% 50%', 29 | duration: speed, 30 | timingFunction, 31 | delay: 0 32 | }) 33 | 34 | animation[`translate${XORY}`](translate).step() // 动画描述 35 | 36 | this.syncView(animationViewName, animation.export()) // 同步动画到视图 37 | 38 | } catch (err) { 39 | consoleException(err, 'slideAnimation[Function]') 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/controller.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by sail on 2017/4/1. 3 | */ 4 | 5 | export default { 6 | /** 7 | * 切换控制器 8 | * @param touchStartTime: 手指触碰slide时的时间戳 9 | * @param et: 手指离开slide时的时间戳 10 | * @param from: 手指触碰slide时的屏幕位置 11 | * @param to: 手指离开slide时的屏幕位置 12 | * @param wrapperDistance: slide滑动方向上的容器长度 13 | * @returns {*} 14 | */ 15 | action (touchStartTime, touchEndTime, from, to, wrapperDistance) { 16 | const { 17 | activeIndex, 18 | slideLength, 19 | onTransitionStart } = this 20 | const deltaTime = touchEndTime - touchStartTime // 手指触摸时长 21 | const distance = Math.abs(to - from) // 滑动距离 22 | 23 | const k = distance / deltaTime 24 | 25 | if (to > from) { 26 | typeof onTransitionStart === 'function' && onTransitionStart(this) // slide达到过渡条件时执行 27 | return (k > 0.3 || distance > wrapperDistance / 2) ? (activeIndex === 0 ? 'slideBack' : 'slidePrev') : 'slideBack' 28 | } 29 | 30 | if (to < from) { 31 | typeof onTransitionStart === 'function' && onTransitionStart(this) // slide达到过渡条件时执行 32 | return (k > 0.3 || distance > wrapperDistance / 2) ? (activeIndex === slideLength - 1 ? 'slideBack' : 'slideNext') : 'slideBack' 33 | } 34 | 35 | if (to = from) { 36 | return 'slideBack' 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /dist/weSwiper.wxss: -------------------------------------------------------------------------------- 1 | Page{ 2 | width: 100%; 3 | height: 100%; 4 | } 5 | 6 | .we-container{ 7 | width: 100%; 8 | height: 100%; 9 | } 10 | 11 | .we-container { 12 | margin-left: auto; 13 | margin-right: auto; 14 | position: relative; 15 | overflow: hidden; 16 | z-index: 1; 17 | } 18 | 19 | .we-wrapper{ 20 | position: relative; 21 | width: 100%; 22 | height: 100%; 23 | z-index: 1; 24 | display: -webkit-box; 25 | display: -moz-box; 26 | display: -ms-flexbox; 27 | display: -webkit-flex; 28 | display: flex; 29 | -webkit-transition-property: -webkit-transform; 30 | -moz-transition-property: -moz-transform; 31 | -o-transition-property: -o-transform; 32 | -ms-transition-property: -ms-transform; 33 | transition-property: transform; 34 | -webkit-box-sizing: content-box; 35 | -moz-box-sizing: content-box; 36 | box-sizing: content-box; 37 | } 38 | 39 | .we-container-vertical>.we-wrapper { 40 | -webkit-box-orient: vertical; 41 | -moz-box-orient: vertical; 42 | -ms-flex-direction: column; 43 | -webkit-flex-direction: column; 44 | flex-direction: column; 45 | } 46 | 47 | .we-slide { 48 | -webkit-flex-shrink: 0; 49 | -ms-flex: 0 0 auto; 50 | flex-shrink: 0; 51 | width: 100%; 52 | height: 100%; 53 | position: relative; 54 | } -------------------------------------------------------------------------------- /src/default.js: -------------------------------------------------------------------------------- 1 | const device = wx.getSystemInfoSync() // 获取设备信息 2 | 3 | export default { 4 | /** 5 | * 必填项 6 | */ 7 | slideLength: 0, // 由于目前无法直接获取slide页数,目前只能通过参数写入 8 | /** 9 | * 可选参数 10 | */ 11 | width: device.windowWidth, 12 | height: device.windowHeight, 13 | direction: 'horizontal', 14 | initialSlide: 0, 15 | speed: 300, 16 | effect: 'slide', // 过渡效果 17 | timingFunction: 'ease', // 过渡动画速度曲线 18 | autoplay: 0, // 自动播放间隔,设置为0时不自动播放 19 | animationViewName: 'animationData', // 对应视图wrapper中animation属性名 20 | /** 21 | * 事件回调 22 | * @type {[type]} 23 | */ 24 | onInit: null, // swiper初始化时执行 25 | onTouchStart: null, // 手指碰触slide时执行 26 | onTouchMove: null, // 手指碰触slide并且滑动时执行 27 | onTouchEnd: null, // 手指离开slide时执行 28 | onSlideChangeStart: null, // slide达到过渡条件时执行 29 | onSlideChangeEnd: null, // swiper从一个slide过渡到另一个slide结束时执行 30 | onTransitionStart: null, // 过渡时触发 31 | onTransitionEnd: null, // 过渡结束时执行 32 | onSlideMove: null, // 手指触碰swiper并且拖动slide时执行 33 | onSlideNextStart: null, // slide达到过渡条件 且规定了方向 向前(右、下)切换时执行 34 | onSlideNextEnd: null, // slide达到过渡条件 且规定了方向 向前(右、下)切换结束时执行 35 | onSlidePrevStart: null, // slide达到过渡条件 且规定了方向 向前(左、上)切换时执行 36 | onSlidePrevEnd: null // slide达到过渡条件 且规定了方向 向前(左、上)切换结束时执行 37 | } 38 | -------------------------------------------------------------------------------- /src/handle.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 3 | touchstart (e) { 4 | if (this.noSwiper) return 5 | const { onTouchStart, XORY, activeIndex, rectDistance } = this 6 | const touch = e.changedTouches[0] 7 | const distance = touch[`client${XORY}`] 8 | const translate = - activeIndex * rectDistance 9 | 10 | this[`touchStart${XORY}`] = distance 11 | this[`translate${XORY}`] = translate 12 | this.touchStartTime = new Date().getTime() 13 | 14 | typeof onTouchStart === 'function' && onTouchStart(this, e) // 当手指碰触到slide时执行 15 | 16 | this.slideAnimation(translate, 0) 17 | }, 18 | 19 | touchmove (e) { 20 | if (this.noSwiper) return 21 | const { onTouchMove, XORY, onSlideMove } = this 22 | const touch = e.changedTouches[0] 23 | const distance = touch[`client${XORY}`] 24 | const tmpMove = this[`translate${XORY}`] + distance - this[`touchStart${XORY}`] 25 | 26 | 27 | typeof onTouchMove === 'function' && onTouchMove(this, e) // 手指碰触slide并且滑动时执行 28 | 29 | this.slideAnimation(tmpMove, 0) 30 | 31 | typeof onSlideMove === 'function' && onSlideMove(this) 32 | }, 33 | 34 | touchend (e) { 35 | if (this.noSwiper) return 36 | const { onTouchEnd, XORY, speed, touchStartTime, rectDistance } = this 37 | const touch = e.changedTouches[0] 38 | const distance = touch[`client${XORY}`] 39 | const touchEndTime = new Date().getTime() 40 | 41 | const action = this.action(touchStartTime, touchEndTime, this[`touchStart${XORY}`], distance, rectDistance) 42 | 43 | typeof onTouchEnd === 'function' && onTouchEnd(this, e) // 手指离开slide时执行 44 | 45 | this[action](true, speed) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import DEFAULT from './default' 2 | import handle from './handle' 3 | import controller from './controller' 4 | import methods from './methods' 5 | import animate from './animate' 6 | import sync from './syncView' 7 | import exception from './exception' 8 | 9 | class weSwiper { 10 | 11 | constructor (param) { 12 | 13 | const pages = getCurrentPages() 14 | 15 | // 获取到当前page上下文 16 | this.pageContext = pages[pages.length - 1] 17 | // 把this依附在Page上下文的wecropper属性上,便于在page钩子函数中访问 18 | this.pageContext.weswiper = this 19 | 20 | const all = Object.assign(this, DEFAULT, param || {}) 21 | 22 | this.init(all) 23 | } 24 | 25 | /** 26 | * 初始化配置 27 | */ 28 | init (param) { 29 | const { 30 | speed, 31 | initialSlide, 32 | direction, 33 | autoplay, 34 | directionViewName 35 | } = param 36 | 37 | const directionClass = direction === 'horizontal' ? 'we-container-horizontal' : 'we-container-vertical' 38 | this.syncView(directionViewName, directionClass) 39 | this.rectDistance = direction === 'horizontal' ? this.width : this.height 40 | this.XORY = direction === 'horizontal' ? 'X' : 'Y' 41 | this.activeIndex = initialSlide // 将初始页码赋给activeIndex 42 | this.noSwiper = false // 阻止手势滑动 43 | this.previousIndex = initialSlide // 返回上一个活动块的索引,切换前的索引 44 | this.slideTo(initialSlide, 0) 45 | typeof autoplay === 'number' && autoplay > 0 && setInterval(() => { 46 | if (this.isEnd) { 47 | this.slideTo(0, speed) 48 | } else { 49 | this.slideTo(this.activeIndex + 1, speed) 50 | } 51 | }, autoplay) 52 | /** 53 | * 处理callback 54 | */ 55 | const { onInit } = this 56 | typeof onInit === 'function' && onInit(this) 57 | } 58 | } 59 | 60 | Object.assign(weSwiper.prototype, controller) 61 | Object.assign(weSwiper.prototype, handle) 62 | Object.assign(weSwiper.prototype, methods) 63 | Object.assign(weSwiper.prototype, animate) 64 | Object.assign(weSwiper.prototype, sync) 65 | Object.assign(weSwiper.prototype, exception) 66 | 67 | export default weSwiper 68 | -------------------------------------------------------------------------------- /example/general/general.js: -------------------------------------------------------------------------------- 1 | import weSwiper from '../../src/main' 2 | 3 | const option = { 4 | touchstart (e) { 5 | this.weswiper.touchstart(e) 6 | }, 7 | touchmove (e) { 8 | this.weswiper.touchmove(e) 9 | }, 10 | touchend (e) { 11 | this.weswiper.touchend(e) 12 | }, 13 | onLoad () { 14 | const device = wx.getSystemInfoSync() 15 | new weSwiper({ 16 | animationViewName: 'animationData', 17 | slideLength: 3, 18 | initialSlide: 0, 19 | /** 20 | * swiper初始化后执行 21 | * @param swiper 22 | */ 23 | onInit (weswiper) { 24 | 25 | }, 26 | /** 27 | * 手指碰触slide时执行 28 | * @param swiper 29 | * @param event 30 | */ 31 | onTouchStart (weswiper, event) { 32 | 33 | }, 34 | /** 35 | * 手指碰触slide并且滑动时执行 36 | * @param swiper 37 | * @param event 38 | */ 39 | onTouchMove (weswiper, event) { 40 | 41 | }, 42 | /** 43 | * 手指离开slide时执行 44 | * @param swiper 45 | * @param event 46 | */ 47 | onTouchEnd (weswiper, event) { 48 | 49 | }, 50 | /** 51 | * slide达到过渡条件时执行 52 | */ 53 | onSlideChangeStart (weswiper) { 54 | 55 | }, 56 | /** 57 | * swiper从一个slide过渡到另一个slide结束时执行 58 | */ 59 | onSlideChangeEnd (weswiper) { 60 | 61 | }, 62 | /** 63 | * 过渡时触发 64 | */ 65 | onTransitionStart (weswiper) { 66 | 67 | }, 68 | /** 69 | * 过渡结束时执行 70 | */ 71 | onTransitionEnd (weswiper) { 72 | 73 | }, 74 | /** 75 | * 手指触碰swiper并且拖动slide时执行 76 | */ 77 | onSlideMove (weswiper) { 78 | 79 | }, 80 | /** 81 | * slide达到过渡条件 且规定了方向 向前(右、下)切换时执行 82 | */ 83 | onSlideNextStart (weswiper) { 84 | 85 | }, 86 | /** 87 | * slide达到过渡条件 且规定了方向 向前(右、下)切换结束时执行 88 | */ 89 | onSlideNextEnd (weswiper) { 90 | 91 | }, 92 | /** 93 | * slide达到过渡条件 且规定了方向 向前(左、上)切换时执行 94 | */ 95 | onSlidePrevStart (swiper) { 96 | 97 | }, 98 | /** 99 | * slide达到过渡条件 且规定了方向 向前(左、上)切换结束时执行 100 | */ 101 | onSlidePrevEnd (weswiper) { 102 | 103 | } 104 | }) 105 | } 106 | } 107 | Page(option) 108 | -------------------------------------------------------------------------------- /example/card/card.js: -------------------------------------------------------------------------------- 1 | import weSwiper from '../../src/main' 2 | 3 | const option = { 4 | touchstart (e) { 5 | this.weswiper.touchstart(e) 6 | }, 7 | touchmove (e) { 8 | this.weswiper.touchmove(e) 9 | }, 10 | touchend (e) { 11 | this.weswiper.touchend(e) 12 | }, 13 | onLoad () { 14 | const device = wx.getSystemInfoSync() 15 | new weSwiper({ 16 | animationViewName: 'animationData', 17 | slideLength: 3, 18 | initialSlide: 0, 19 | width: 550 * device.windowWidth / 750, 20 | height: 500 * device.windowWidth / 750, 21 | /** 22 | * swiper初始化后执行 23 | * @param swiper 24 | */ 25 | onInit (weswiper) { 26 | 27 | }, 28 | /** 29 | * 手指碰触slide时执行 30 | * @param swiper 31 | * @param event 32 | */ 33 | onTouchStart (weswiper, event) { 34 | 35 | }, 36 | /** 37 | * 手指碰触slide并且滑动时执行 38 | * @param swiper 39 | * @param event 40 | */ 41 | onTouchMove (weswiper, event) { 42 | 43 | }, 44 | /** 45 | * 手指离开slide时执行 46 | * @param swiper 47 | * @param event 48 | */ 49 | onTouchEnd (weswiper, event) { 50 | 51 | }, 52 | /** 53 | * slide达到过渡条件时执行 54 | */ 55 | onSlideChangeStart (weswiper) { 56 | 57 | }, 58 | /** 59 | * swiper从一个slide过渡到另一个slide结束时执行 60 | */ 61 | onSlideChangeEnd (weswiper) { 62 | 63 | }, 64 | /** 65 | * 过渡时触发 66 | */ 67 | onTransitionStart (weswiper) { 68 | 69 | }, 70 | /** 71 | * 过渡结束时执行 72 | */ 73 | onTransitionEnd (weswiper) { 74 | 75 | }, 76 | /** 77 | * 手指触碰swiper并且拖动slide时执行 78 | */ 79 | onSlideMove (weswiper) { 80 | 81 | }, 82 | /** 83 | * slide达到过渡条件 且规定了方向 向前(右、下)切换时执行 84 | */ 85 | onSlideNextStart (weswiper) { 86 | 87 | }, 88 | /** 89 | * slide达到过渡条件 且规定了方向 向前(右、下)切换结束时执行 90 | */ 91 | onSlideNextEnd (weswiper) { 92 | 93 | }, 94 | /** 95 | * slide达到过渡条件 且规定了方向 向前(左、上)切换时执行 96 | */ 97 | onSlidePrevStart (swiper) { 98 | 99 | }, 100 | /** 101 | * slide达到过渡条件 且规定了方向 向前(左、上)切换结束时执行 102 | */ 103 | onSlidePrevEnd (weswiper) { 104 | 105 | } 106 | }) 107 | } 108 | } 109 | Page(option) 110 | -------------------------------------------------------------------------------- /src/methods.js: -------------------------------------------------------------------------------- 1 | export default { 2 | /** 3 | * 切换至下一个slide 4 | * @param runCallbacks: 可选,boolean,设置为false时不会触发onSlideChange回调函数 5 | * @param speed: 可选,num(单位ms),切换速度 6 | */ 7 | slideNext (runCallbacks = false, speed = 300) { 8 | const self = this 9 | const { 10 | onSlideNextStart, 11 | onSlideNextEnd 12 | } = self 13 | 14 | typeof onSlideNextStart === 'function' && onSlideNextStart(self) // slide达到过渡条件时执行 15 | 16 | self.slideTo(self.activeIndex + 1, speed, runCallbacks) 17 | 18 | typeof onSlideNextEnd === 'function' && setTimeout(() => { onSlideNextEnd(self) }, speed) // slide过渡结束后执行 19 | }, 20 | /** 21 | * 切换至上一个slide 22 | * @param runCallbacks: 可选,boolean,设置为false时不会触发onSlideChange回调函数 23 | * @param speed: 可选,num(单位ms),切换速度 24 | */ 25 | slidePrev (runCallbacks = false, speed = 300) { 26 | const self = this 27 | const { 28 | onSlidePrevStart, 29 | onSlidePrevEnd 30 | } = self 31 | 32 | typeof onSlidePrevStart === 'function' && onSlidePrevStart(self) // slide达到过渡条件时执行 33 | 34 | self.slideTo(self.activeIndex - 1, speed, runCallbacks) 35 | 36 | typeof onSlidePrevEnd === 'function' && setTimeout(() => { onSlidePrevEnd(self) }, speed) // slide过渡结束后执行 37 | }, 38 | /** 39 | * 回弹 40 | * @param runCallbacks: 可选,boolean,设置为false时不会触发onSlideChange回调函数 41 | * @param speed: 可选,num(单位ms),切换速度 42 | */ 43 | slideBack (runCallbacks = false, speed = 300) { 44 | const self = this 45 | const { 46 | XORY, 47 | activeIndex, 48 | rectDistance, 49 | onTransitionEnd 50 | } = self 51 | 52 | const translate = - activeIndex * rectDistance 53 | 54 | self.slideAnimation(translate, speed) 55 | 56 | typeof onTransitionEnd === 'function' && setTimeout(() => { onTransitionEnd(self) }, speed) // slide过渡结束后执行 57 | }, 58 | /** 59 | * 切换到指定slide 60 | * @param index:必选,num,指定将要切换到的slide的索引 61 | * @param speed:可选,num(单位ms),切换速度 62 | * @param runCallbacks:可选,boolean,设置为false时不会触发onSlideChange回调函数 63 | */ 64 | slideTo (index, speed = 300, runCallbacks = false) { 65 | const self = this 66 | const { 67 | slideLength, 68 | activeIndex, 69 | rectDistance, 70 | onSlideChangeStart, 71 | onSlideChangeEnd, 72 | onTransitionEnd, 73 | consoleException 74 | } = self 75 | 76 | try { 77 | if (typeof index !== 'number') throw 'paramType' // 参数类型错误 78 | if (index < 0 || index > slideLength - 1) throw 'bound' // 越界 79 | 80 | const translate = - index * rectDistance 81 | self.previousIndex = activeIndex 82 | self.activeIndex = index 83 | self.isBeginning = self.activeIndex === self.initialSlide 84 | self.isEnd = self.activeIndex === self.slideLength - 1 85 | 86 | runCallbacks && typeof onSlideChangeStart === 'function' && onSlideChangeStart(self) // slide达到过渡条件时执行 87 | 88 | self.slideAnimation(translate, speed) 89 | 90 | runCallbacks && typeof onSlideChangeEnd === 'function' && setTimeout(() => { onSlideChangeEnd(self) }, speed) // swiper从一个slide过渡到另一个slide结束后执行 91 | typeof onTransitionEnd === 'function' && setTimeout(() => { onTransitionEnd(self) }, speed) // slide过渡结束后执行 92 | } catch (err) { 93 | consoleException(err, 'slideTo[Function]') 94 | } 95 | 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # we-swiper 2 | 微信小程序触摸内容滑动解决方案,API设计细节及命名参考于[swiper.js](http://www.swiper.com.cn/). 3 | ### 为什么要开发这款插件 4 | #### 官方swiper组件: 5 | * 支持的事件回调很单一 6 | * ~~从文档上看只是能支持横向滑动~~(官方swiper组件实际是支持纵向滚动的,设置属性vertical="true"即可,但并未在官方文档提及,感谢[@pangz1](https://github.com/pangz1)指正) 7 | * 拓展性不强 8 | 9 | #### we-swiper插件: 10 | * 丰富的事件回调 11 | * 丰富的属性 12 | * 支持横、纵向滑动 13 | * 强拓展(可在原插件基础上二次开发) 14 | 15 | ## ScreenShots 16 | #### 横向滚动 17 | ![Alt text](https://github.com/we-plugin/we-swiper/blob/master/screenshots/Gif_20170401_013729.gif?raw=true) 18 | #### 纵向滚动 19 | ![Alt text](https://github.com/we-plugin/we-swiper/blob/master/screenshots/Gif_20170401_013701.gif?raw=true) 20 | 21 | ## 使用方式 22 | #### 克隆项目至你的目录 23 | ```bash 24 | cd my-project 25 | 26 | git clone https://github.com/dlhandsome/we-swiper.git 27 | ``` 28 | 29 | #### 在项目文件引入``` dist/weSwiper.js```进行开发 30 | 31 | ##### es6 module 32 | ``` javascript 33 | import weSwiper from 'dist/weSwiper' 34 | ``` 35 | ##### commonjs 36 | ```javascript 37 | var weSwiper = require('dist/weSwiper') 38 | ``` 39 | 40 | ## 示例 41 | #### example.wxml 42 | ``` html 43 | 44 | 49 | slide 1 50 | slide 2 51 | slide 3 52 | 53 | 54 | ``` 55 | #### example.js 56 | ``` javascript 57 | import weSwiper from '../dist/weSwiper' 58 | 59 | const option = { 60 | touchstart (e) { 61 | this.weswiper.touchstart(e) 62 | }, 63 | touchmove (e) { 64 | this.weswiper.touchmove(e) 65 | }, 66 | touchend (e) { 67 | this.weswiper.touchend(e) 68 | }, 69 | onLoad () { 70 | new weSwiper({ 71 | animationViewName: 'animationData', 72 | slideLength: 3, 73 | initialSlide: 0, 74 | /** 75 | * swiper初始化后执行 76 | * @param weswiper 77 | */ 78 | onInit (weswiper) { 79 | 80 | }, 81 | /** 82 | * 手指碰触slide时执行 83 | * @param weswiper 84 | * @param event 85 | */ 86 | onTouchStart (weswiper, event) { 87 | 88 | }, 89 | /** 90 | * 手指碰触slide并且滑动时执行 91 | * @param weswiper 92 | * @param event 93 | */ 94 | onTouchMove (weswiper, event) { 95 | 96 | }, 97 | /** 98 | * 手指离开slide时执行 99 | * @param weswiper 100 | * @param event 101 | */ 102 | onTouchEnd (weswiper, event) { 103 | 104 | }, 105 | /** 106 | * slide达到过渡条件时执行 107 | */ 108 | onSlideChangeStart (weswiper) { 109 | 110 | }, 111 | /** 112 | * weswiper从一个slide过渡到另一个slide结束时执行 113 | */ 114 | onSlideChangeEnd (weswiper) { 115 | 116 | }, 117 | /** 118 | * 过渡时触发 119 | */ 120 | onTransitionStart (weswiper) { 121 | 122 | }, 123 | /** 124 | * 过渡结束时执行 125 | */ 126 | onTransitionEnd (weswiper) { 127 | 128 | }, 129 | /** 130 | * 手指触碰weswiper并且拖动slide时执行 131 | */ 132 | onSlideMove (weswiper) { 133 | 134 | }, 135 | /** 136 | * slide达到过渡条件 且规定了方向 向前(右、下)切换时执行 137 | */ 138 | onSlideNextStart (weswiper) { 139 | 140 | }, 141 | /** 142 | * slide达到过渡条件 且规定了方向 向前(右、下)切换结束时执行 143 | */ 144 | onSlideNextEnd (weswiper) { 145 | 146 | }, 147 | /** 148 | * slide达到过渡条件 且规定了方向 向前(左、上)切换时执行 149 | */ 150 | onSlidePrevStart (swiper) { 151 | 152 | }, 153 | /** 154 | * slide达到过渡条件 且规定了方向 向前(左、上)切换结束时执行 155 | */ 156 | onSlidePrevEnd (weswiper) { 157 | 158 | } 159 | }) 160 | } 161 | } 162 | Page(option) 163 | 164 | ``` 165 | 166 | ## we-swiper初始化 167 | 168 | #### weSwiper在onLoad方法中实例化 169 | 170 | ```javascript 171 | onLoad () { 172 | new weSwiper({ 173 | slideLength: 3 // 必填,由于目前无法直接获取slide页数,目前只能通过参数写入 174 | }) 175 | } 176 | ``` 177 | 178 | #### 可通过this.weswiper在Page的钩子函数中访问实例 179 | 180 | ```javascript 181 | touchstart (e) { 182 | this.weswiper.touchstart(e) 183 | } 184 | ``` 185 | 186 | #### WXML结构配置 187 | 188 | ```html 189 | 190 | 195 | slide 1 196 | slide 2 197 | slide 3 198 | 199 | 200 | ``` 201 | 小提示:WXML中的字段不需要在Page的data中给出默认值,we-swiper内部有同步视图机制。 202 | 203 | ## 构造器参数 204 | 205 | ### 必填项 206 | 207 | 208 | #### slideLength 209 | 210 | - Type: `Number` 211 | - Default: `0` 212 | 213 | 表示slide的页数 214 | 215 | ### 可选项 216 | 217 | 218 | #### width 219 | 220 | - Type: `Number` 221 | - Default: `device.windowWidth` 222 | 223 | 设定slide的宽度(横向滑动时slide滑动间隔距离会根据其值计算) 224 | 225 | 226 | #### height 227 | 228 | - Type: `Number` 229 | - Default: `device.windowHeight` 230 | 231 | 设定slide的高度(纵向滑动时slide滑动间隔距离会根据其值计算) 232 | 233 | 234 | #### direction 235 | 236 | - Type: `String` 237 | - Default: `horizontal` 238 | - Option: 239 | - `horizontal`: slide水平方向滑动 240 | - `vertical`: slide垂直方向滑动 241 | 242 | 设定slide滑动方向 243 | 244 | 245 | #### initialSlide 246 | 247 | - Type: `Number` 248 | - Default: `0` 249 | 250 | 设定初始化时slide的索引 251 | 252 | 253 | #### speed 254 | 255 | - Type: `Number` 256 | - Default: `300` 257 | 258 | 设定slide过渡时长 259 | 260 | 261 | #### timingFunction 262 | 263 | - Type: `String` 264 | - Default: `ease` 265 | - Option: 266 | - `linear`: slide水平方向滑动 267 | - `ease`: slide垂直方向滑动 268 | - `ease-in`: slide垂直方向滑动 269 | - `ease-in-out`: slide垂直方向滑动 270 | - `ease-out`: slide垂直方向滑动 271 | - `step-start`: slide垂直方向滑动 272 | - `step-end`: slide垂直方向滑动 273 | 274 | 设定slide过渡动画速度曲线 275 | 276 | 277 | #### autoplay 278 | 279 | - Type: `Number` 280 | - Default: `0` 281 | 282 | 设定slide自动播放间隔时长,设置为0时不自动播放 283 | 284 | 285 | #### directionViewName 286 | 287 | - Type: `String` 288 | - Default: `directionClass` 289 | 290 | 对应视图中direction类名 291 | 292 | 293 | #### animationViewName 294 | 295 | - Type: `String` 296 | - Default: `animationData` 297 | 298 | 对应视图中animation属性名 299 | 300 | 301 | ## 属性 302 | 303 | 304 | #### weswiper.activeIndex 305 | 306 | 返回当前活动块(激活块)的索引 307 | 308 | 309 | #### weswiper.previousIndex 310 | 311 | 返回上一个活动块的索引 312 | 313 | 314 | #### weswiper.width 315 | 316 | 返回swiper容器的宽度 317 | 318 | 319 | #### weswiper.height 320 | 321 | 返回swiper容器的高度 322 | 323 | 324 | #### weswiper.isBeginning 325 | 326 | 如果swiper处于最初始位置,返回true 327 | 328 | 329 | #### weswiper.isEnd 330 | 331 | 如果swiper处于最末尾位置,返回true 332 | 333 | 334 | #### weswiper.speed 335 | 336 | 返回当前swiper的过渡时长 337 | 338 | 339 | ## 方法 340 | 341 | 342 | #### weswiper.slideNext(runCallbacks, speed) 343 | 344 | 滑动到后一个slide 345 | 346 | - Params: 347 | - `runCallbacks`: 可选,设为false不触发onSlideChange回调函数 348 | - `speed`: 可选,切换速度 349 | 350 | 351 | #### weswiper.slidePrev(runCallbacks, speed) 352 | 353 | 滑动到前一个slide。 354 | 355 | - Params: 356 | - `runCallbacks`: 可选,设为false不触发onSlideChange回调函数 357 | - `speed`: 可选,切换速度 358 | 359 | 360 | #### weswiper.slideTo(index, speed, runCallbacks) 361 | 362 | 切换到指定slide。 363 | 364 | - Params: 365 | - `index`: 必选,num,指定将要切换到的slide的索引 366 | - `speed`: 可选,切换速度 367 | - `runCallbacks`: 可选,设为false不触发onSlideChange回调函数 368 | 369 | 370 | ## 事件回调 371 | 372 | 373 | #### onInit (weswiper) 374 | 375 | 回调函数,初始化后执行。 376 | 可选weswiper实例作为参数。 377 | 378 | 379 | #### onTouchStart (weswiper, event) 380 | 381 | 回调函数,当碰触到slider时执行。可选weswiper和touchstart事件作为参数 382 | 383 | 384 | #### onTouchMove (weswiper, event) 385 | 386 | 回调函数,手指触碰weswiper并滑动(手指)时执行。此时slide不一定会发生移动,比如你手指的移动方向和weswiper的切换方向垂直时 387 | 388 | 389 | #### onTouchEnd (weswiper, event) 390 | 391 | 回调函数,当释放slider时执行。(释放即执行) 392 | 393 | 394 | #### onSlideChangeStart (weswiper) 395 | 396 | 回调函数,weswiper从当前slide开始过渡到另一个slide时执行。触摸情况下,如果释放slide时没有达到过渡条件而回弹时不会触发这个函数,此时可用onTransitionStart。 397 | 398 | 可接受weswiper实例作为参数,输出的activeIndex是过渡后的slide索引 399 | 400 | 401 | #### onSlideChangeEnd (weswiper) 402 | 403 | 回调函数,weswiper从一个slide过渡到另一个slide结束时执行。 404 | 405 | 可接受swiper实例作为参数。 406 | 407 | 408 | #### onTransitionStart (weswiper) 409 | 410 | 回调函数,过渡开始时触发,接受weswiper实例作为参数。 411 | 412 | 413 | #### onTransitionEnd (weswiper) 414 | 415 | 回调函数,过渡结束时触发,接收weswiper实例作为参数。 416 | 417 | 418 | #### onSlideMove (weswiper) 419 | 420 | 回调函数,手指触碰weswiper并拖动slide时执行。 421 | 422 | 423 | #### onSlideNextStart (weswiper) 424 | 425 | 回调函数,滑块释放时如果触发slider向前(右、下)切换则执行。类似于onSlideChangeStart,但规定了方向。 426 | 427 | 428 | #### onSlideNextEnd (weswiper) 429 | 430 | 回调函数,slider向前(右、下)切换结束时执行。类似于onSlideChangeEnd,但规定了方向。 431 | 432 | 433 | #### onSlidePrevStart (weswiper) 434 | 435 | 回调函数,滑块释放时如果触发slider向后(左、上)切换则执行。类似于onSlideChangeStart,但规定了方向。 436 | 437 | #### onSlidePrevEnd (weswiper) 438 | 439 | 回调函数,slider向后(左、上)切换结束时执行。类似于onSlideChangeEnd,但规定了方向。 440 | 441 | 442 | ## TODO 443 | 444 | - 增加切换效果:fade,flip等 445 | 446 | ## License 447 | The MIT License(http://opensource.org/licenses/MIT) 448 | 449 | 请自由地享受和参与开源 450 | 451 | ## 贡献 452 | 453 | 如果你有好的意见或建议,欢迎给我提issue或pull request。 454 | 455 | 456 | 457 | 458 | -------------------------------------------------------------------------------- /dist/weSwiper.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 3 | typeof define === 'function' && define.amd ? define(factory) : 4 | (global.weSwiper = factory()); 5 | }(this, (function () { 'use strict'; 6 | 7 | var device = wx.getSystemInfoSync(); // 获取设备信息 8 | 9 | var DEFAULT = { 10 | /** 11 | * 必填项 12 | */ 13 | slideLength: 0, // 由于目前无法直接获取slide页数,目前只能通过参数写入 14 | /** 15 | * 可选参数 16 | */ 17 | width: device.windowWidth, 18 | height: device.windowHeight, 19 | direction: 'horizontal', 20 | initialSlide: 0, 21 | speed: 300, 22 | effect: 'slide', // 过渡效果 23 | timingFunction: 'ease', // 过渡动画速度曲线 24 | autoplay: 0, // 自动播放间隔,设置为0时不自动播放 25 | animationViewName: 'animationData', // 对应视图wrapper中animation属性名 26 | /** 27 | * 事件回调 28 | * @type {[type]} 29 | */ 30 | onInit: null, // swiper初始化时执行 31 | onTouchStart: null, // 手指碰触slide时执行 32 | onTouchMove: null, // 手指碰触slide并且滑动时执行 33 | onTouchEnd: null, // 手指离开slide时执行 34 | onSlideChangeStart: null, // slide达到过渡条件时执行 35 | onSlideChangeEnd: null, // swiper从一个slide过渡到另一个slide结束时执行 36 | onTransitionStart: null, // 过渡时触发 37 | onTransitionEnd: null, // 过渡结束时执行 38 | onSlideMove: null, // 手指触碰swiper并且拖动slide时执行 39 | onSlideNextStart: null, // slide达到过渡条件 且规定了方向 向前(右、下)切换时执行 40 | onSlideNextEnd: null, // slide达到过渡条件 且规定了方向 向前(右、下)切换结束时执行 41 | onSlidePrevStart: null, // slide达到过渡条件 且规定了方向 向前(左、上)切换时执行 42 | onSlidePrevEnd: null // slide达到过渡条件 且规定了方向 向前(左、上)切换结束时执行 43 | }; 44 | 45 | var handle = { 46 | touchstart: function touchstart(e) { 47 | if (this.noSwiper) return; 48 | var onTouchStart = this.onTouchStart, 49 | XORY = this.XORY, 50 | activeIndex = this.activeIndex, 51 | rectDistance = this.rectDistance; 52 | 53 | var touch = e.changedTouches[0]; 54 | var distance = touch['client' + XORY]; 55 | var translate = -activeIndex * rectDistance; 56 | 57 | this['touchStart' + XORY] = distance; 58 | this['translate' + XORY] = translate; 59 | this.touchStartTime = new Date().getTime(); 60 | 61 | typeof onTouchStart === 'function' && onTouchStart(this, e); // 当手指碰触到slide时执行 62 | 63 | this.slideAnimation(translate, 0); 64 | }, 65 | touchmove: function touchmove(e) { 66 | if (this.noSwiper) return; 67 | var onTouchMove = this.onTouchMove, 68 | XORY = this.XORY, 69 | onSlideMove = this.onSlideMove; 70 | 71 | var touch = e.changedTouches[0]; 72 | var distance = touch['client' + XORY]; 73 | var tmpMove = this['translate' + XORY] + distance - this['touchStart' + XORY]; 74 | 75 | typeof onTouchMove === 'function' && onTouchMove(this, e); // 手指碰触slide并且滑动时执行 76 | 77 | this.slideAnimation(tmpMove, 0); 78 | 79 | typeof onSlideMove === 'function' && onSlideMove(this); 80 | }, 81 | touchend: function touchend(e) { 82 | if (this.noSwiper) return; 83 | var onTouchEnd = this.onTouchEnd, 84 | XORY = this.XORY, 85 | speed = this.speed, 86 | touchStartTime = this.touchStartTime, 87 | rectDistance = this.rectDistance; 88 | 89 | var touch = e.changedTouches[0]; 90 | var distance = touch['client' + XORY]; 91 | var touchEndTime = new Date().getTime(); 92 | 93 | var action = this.action(touchStartTime, touchEndTime, this['touchStart' + XORY], distance, rectDistance); 94 | 95 | typeof onTouchEnd === 'function' && onTouchEnd(this, e); // 手指离开slide时执行 96 | 97 | this[action](true, speed); 98 | } 99 | }; 100 | 101 | /** 102 | * Created by sail on 2017/4/1. 103 | */ 104 | 105 | var controller = { 106 | /** 107 | * 切换控制器 108 | * @param touchStartTime: 手指触碰slide时的时间戳 109 | * @param et: 手指离开slide时的时间戳 110 | * @param from: 手指触碰slide时的屏幕位置 111 | * @param to: 手指离开slide时的屏幕位置 112 | * @param wrapperDistance: slide滑动方向上的容器长度 113 | * @returns {*} 114 | */ 115 | action: function action(touchStartTime, touchEndTime, from, to, wrapperDistance) { 116 | var activeIndex = this.activeIndex, 117 | slideLength = this.slideLength, 118 | onTransitionStart = this.onTransitionStart; 119 | 120 | var deltaTime = touchEndTime - touchStartTime; // 手指触摸时长 121 | var distance = Math.abs(to - from); // 滑动距离 122 | 123 | var k = distance / deltaTime; 124 | 125 | if (to > from) { 126 | typeof onTransitionStart === 'function' && onTransitionStart(this); // slide达到过渡条件时执行 127 | return k > 0.3 || distance > wrapperDistance / 2 ? activeIndex === 0 ? 'slideBack' : 'slidePrev' : 'slideBack'; 128 | } 129 | 130 | if (to < from) { 131 | typeof onTransitionStart === 'function' && onTransitionStart(this); // slide达到过渡条件时执行 132 | return k > 0.3 || distance > wrapperDistance / 2 ? activeIndex === slideLength - 1 ? 'slideBack' : 'slideNext' : 'slideBack'; 133 | } 134 | 135 | if (to = from) { 136 | return 'slideBack'; 137 | } 138 | } 139 | }; 140 | 141 | var methods = { 142 | /** 143 | * 切换至下一个slide 144 | * @param runCallbacks: 可选,boolean,设置为false时不会触发onSlideChange回调函数 145 | * @param speed: 可选,num(单位ms),切换速度 146 | */ 147 | slideNext: function slideNext() { 148 | var runCallbacks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; 149 | var speed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300; 150 | 151 | var self = this; 152 | var onSlideNextStart = self.onSlideNextStart, 153 | onSlideNextEnd = self.onSlideNextEnd; 154 | 155 | 156 | typeof onSlideNextStart === 'function' && onSlideNextStart(self); // slide达到过渡条件时执行 157 | 158 | self.slideTo(self.activeIndex + 1, speed, runCallbacks); 159 | 160 | typeof onSlideNextEnd === 'function' && setTimeout(function () { 161 | onSlideNextEnd(self); 162 | }, speed); // slide过渡结束后执行 163 | }, 164 | 165 | /** 166 | * 切换至上一个slide 167 | * @param runCallbacks: 可选,boolean,设置为false时不会触发onSlideChange回调函数 168 | * @param speed: 可选,num(单位ms),切换速度 169 | */ 170 | slidePrev: function slidePrev() { 171 | var runCallbacks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; 172 | var speed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300; 173 | 174 | var self = this; 175 | var onSlidePrevStart = self.onSlidePrevStart, 176 | onSlidePrevEnd = self.onSlidePrevEnd; 177 | 178 | 179 | typeof onSlidePrevStart === 'function' && onSlidePrevStart(self); // slide达到过渡条件时执行 180 | 181 | self.slideTo(self.activeIndex - 1, speed, runCallbacks); 182 | 183 | typeof onSlidePrevEnd === 'function' && setTimeout(function () { 184 | onSlidePrevEnd(self); 185 | }, speed); // slide过渡结束后执行 186 | }, 187 | 188 | /** 189 | * 回弹 190 | * @param runCallbacks: 可选,boolean,设置为false时不会触发onSlideChange回调函数 191 | * @param speed: 可选,num(单位ms),切换速度 192 | */ 193 | slideBack: function slideBack() { 194 | var runCallbacks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; 195 | var speed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300; 196 | 197 | var self = this; 198 | var XORY = self.XORY, 199 | activeIndex = self.activeIndex, 200 | rectDistance = self.rectDistance, 201 | onTransitionEnd = self.onTransitionEnd; 202 | 203 | 204 | var translate = -activeIndex * rectDistance; 205 | 206 | self.slideAnimation(translate, speed); 207 | 208 | typeof onTransitionEnd === 'function' && setTimeout(function () { 209 | onTransitionEnd(self); 210 | }, speed); // slide过渡结束后执行 211 | }, 212 | 213 | /** 214 | * 切换到指定slide 215 | * @param index:必选,num,指定将要切换到的slide的索引 216 | * @param speed:可选,num(单位ms),切换速度 217 | * @param runCallbacks:可选,boolean,设置为false时不会触发onSlideChange回调函数 218 | */ 219 | slideTo: function slideTo(index) { 220 | var speed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300; 221 | var runCallbacks = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; 222 | 223 | var self = this; 224 | var noSwiper = self.noSwiper, 225 | slideLength = self.slideLength, 226 | activeIndex = self.activeIndex, 227 | rectDistance = self.rectDistance, 228 | onSlideChangeStart = self.onSlideChangeStart, 229 | onSlideChangeEnd = self.onSlideChangeEnd, 230 | onTransitionEnd = self.onTransitionEnd, 231 | consoleException = self.consoleException; 232 | 233 | 234 | try { 235 | if (typeof index !== 'number') throw 'paramType'; // 参数类型错误 236 | if (index < 0 || index > slideLength - 1) throw 'bound'; // 越界 237 | 238 | var translate = -index * rectDistance; 239 | self.previousIndex = activeIndex; 240 | self.activeIndex = index; 241 | self.isBeginning = self.activeIndex === self.initialSlide; 242 | self.isEnd = self.activeIndex === self.slideLength - 1; 243 | 244 | runCallbacks && typeof onSlideChangeStart === 'function' && onSlideChangeStart(self); // slide达到过渡条件时执行 245 | 246 | self.slideAnimation(translate, speed); 247 | 248 | runCallbacks && typeof onSlideChangeEnd === 'function' && setTimeout(function () { 249 | onSlideChangeEnd(self); 250 | }, speed); // swiper从一个slide过渡到另一个slide结束后执行 251 | typeof onTransitionEnd === 'function' && setTimeout(function () { 252 | onTransitionEnd(self); 253 | }, speed); // slide过渡结束后执行 254 | } catch (err) { 255 | consoleException(err, 'slideTo[Function]'); 256 | } 257 | } 258 | }; 259 | 260 | /** 261 | * Created by sail on 2017/4/1. 262 | */ 263 | var REG = { 264 | SPEED: /^(0|[1-9][0-9]*|-[1-9][0-9]*)$/, 265 | TIMINGFUNCTION: /linear|ease|ease-in|ease-in-out|ease-out|step-start|step-end/ 266 | }; 267 | 268 | var animate = { 269 | /** 270 | * 平移动画 271 | * @param translate:平移位置 272 | * @param speed:过渡时长 273 | * @param timingFunction:过渡类型 274 | */ 275 | slideAnimation: function slideAnimation() { 276 | var translate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; 277 | var speed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300; 278 | var timingFunction = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'ease'; 279 | var XORY = this.XORY, 280 | animationViewName = this.animationViewName, 281 | consoleException = this.consoleException; 282 | 283 | try { 284 | /** 285 | * 异常处理 286 | */ 287 | if (!REG.SPEED.test(speed)) throw 'paramType'; 288 | if (!REG.TIMINGFUNCTION.test(timingFunction)) throw 'paramType'; 289 | /** 290 | * 创建一个动画实例 291 | */ 292 | var animation = wx.createAnimation({ 293 | transformOrigin: '50% 50%', 294 | duration: speed, 295 | timingFunction: timingFunction, 296 | delay: 0 297 | }); 298 | 299 | animation['translate' + XORY](translate).step(); // 动画描述 300 | 301 | this.syncView(animationViewName, animation.export()); // 同步动画到视图 302 | } catch (err) { 303 | consoleException(err, 'slideAnimation[Function]'); 304 | } 305 | } 306 | }; 307 | 308 | var classCallCheck = function (instance, Constructor) { 309 | if (!(instance instanceof Constructor)) { 310 | throw new TypeError("Cannot call a class as a function"); 311 | } 312 | }; 313 | 314 | var createClass = function () { 315 | function defineProperties(target, props) { 316 | for (var i = 0; i < props.length; i++) { 317 | var descriptor = props[i]; 318 | descriptor.enumerable = descriptor.enumerable || false; 319 | descriptor.configurable = true; 320 | if ("value" in descriptor) descriptor.writable = true; 321 | Object.defineProperty(target, descriptor.key, descriptor); 322 | } 323 | } 324 | 325 | return function (Constructor, protoProps, staticProps) { 326 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 327 | if (staticProps) defineProperties(Constructor, staticProps); 328 | return Constructor; 329 | }; 330 | }(); 331 | 332 | 333 | 334 | 335 | 336 | var defineProperty = function (obj, key, value) { 337 | if (key in obj) { 338 | Object.defineProperty(obj, key, { 339 | value: value, 340 | enumerable: true, 341 | configurable: true, 342 | writable: true 343 | }); 344 | } else { 345 | obj[key] = value; 346 | } 347 | 348 | return obj; 349 | }; 350 | 351 | /** 352 | * Created by sail on 2017/4/1. 353 | */ 354 | var sync = { 355 | /** 356 | * 同步设置到视图 357 | * @param DEFAULT:默认参数 358 | * @param param:构造参数 359 | */ 360 | syncView: function syncView(viewName, prop) { 361 | this.pageContext.setData(defineProperty({}, "" + viewName, prop)); 362 | } 363 | }; 364 | 365 | /** 366 | * Created by sail on 2017/4/1. 367 | */ 368 | var ERROR = { 369 | 'paramType': '参数类型错误', 370 | 'bound': '参数越界' 371 | }; 372 | 373 | var exception = { 374 | /** 375 | * 错误对照 376 | */ 377 | consoleException: function consoleException(type, place) { 378 | console.error('%c' + place + ':' + ERROR[type], 'color: red'); 379 | } 380 | }; 381 | 382 | var weSwiper = function () { 383 | function weSwiper(param) { 384 | classCallCheck(this, weSwiper); 385 | 386 | 387 | var pages = getCurrentPages(); 388 | 389 | // 获取到当前page上下文 390 | this.pageContext = pages[pages.length - 1]; 391 | // 把this依附在Page上下文的wecropper属性上,便于在page钩子函数中访问 392 | this.pageContext.weswiper = this; 393 | 394 | var all = Object.assign(this, DEFAULT, param || {}); 395 | 396 | this.init(all); 397 | } 398 | 399 | /** 400 | * 初始化配置 401 | */ 402 | 403 | 404 | createClass(weSwiper, [{ 405 | key: 'init', 406 | value: function init(param) { 407 | var _this = this; 408 | 409 | var speed = param.speed, 410 | initialSlide = param.initialSlide, 411 | direction = param.direction, 412 | autoplay = param.autoplay, 413 | directionViewName = param.directionViewName; 414 | 415 | 416 | var directionClass = direction === 'horizontal' ? 'we-container-horizontal' : 'we-container-vertical'; 417 | this.syncView(directionViewName, directionClass); 418 | this.rectDistance = direction === 'horizontal' ? this.width : this.height; 419 | this.XORY = direction === 'horizontal' ? 'X' : 'Y'; 420 | this.activeIndex = initialSlide; // 将初始页码赋给activeIndex 421 | this.noSwiper = false; // 阻止手势滑动 422 | this.previousIndex = initialSlide; // 返回上一个活动块的索引,切换前的索引 423 | this.slideTo(initialSlide, 0); 424 | typeof autoplay === 'number' && autoplay > 0 && setInterval(function () { 425 | if (_this.isEnd) { 426 | _this.slideTo(0, speed); 427 | } else { 428 | _this.slideTo(_this.activeIndex + 1, speed); 429 | } 430 | }, autoplay); 431 | /** 432 | * 处理callback 433 | */ 434 | var onInit = this.onInit; 435 | 436 | typeof onInit === 'function' && onInit(this); 437 | } 438 | }]); 439 | return weSwiper; 440 | }(); 441 | 442 | Object.assign(weSwiper.prototype, controller); 443 | Object.assign(weSwiper.prototype, handle); 444 | Object.assign(weSwiper.prototype, methods); 445 | Object.assign(weSwiper.prototype, animate); 446 | Object.assign(weSwiper.prototype, sync); 447 | Object.assign(weSwiper.prototype, exception); 448 | 449 | return weSwiper; 450 | 451 | }))); 452 | --------------------------------------------------------------------------------