├── _config.yml ├── foxslider.gif ├── src ├── assets │ ├── slider1.jpg │ ├── slider2.jpg │ └── slider3.jpg ├── js │ ├── index.js │ └── base.js ├── css │ └── index.css └── index.html ├── LICENSE └── README.md /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /foxslider.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forrestyuan/FoxSliderJS/HEAD/foxslider.gif -------------------------------------------------------------------------------- /src/assets/slider1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forrestyuan/FoxSliderJS/HEAD/src/assets/slider1.jpg -------------------------------------------------------------------------------- /src/assets/slider2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forrestyuan/FoxSliderJS/HEAD/src/assets/slider2.jpg -------------------------------------------------------------------------------- /src/assets/slider3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forrestyuan/FoxSliderJS/HEAD/src/assets/slider3.jpg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 ForrrestYuan 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/js/index.js: -------------------------------------------------------------------------------- 1 | window.onload = function(){ 2 | //样式1 3 | var tp = new TouchPlugin({ 4 | sliderContainer:'.slider-identifier.slider-container', 5 | slider:'.slider-identifier .slider', 6 | slidePin:'.slider-identifier .slider-pin', 7 | sliderBar:'.slider-identifier .slide-bar', 8 | pinClassName:'on', 9 | pin:'.slider-identifier .pin', 10 | callback:function(e, dir, distance){} 11 | }); 12 | //样式2 13 | var tp = new TouchPlugin({ 14 | sliderContainer:'.slider-identifier2.slider-container', 15 | slider:'.slider-identifier2 .slider', 16 | slidePin:'.slider-identifier2 .slider-pin', 17 | sliderBar:'.slider-identifier2 .slide-bar', 18 | pinClassName:'on', 19 | pin:'.slider-identifier2 .pin', 20 | leftRightToggleBtn:{left:'.slider-identifier2 .leftArrowIcon',right:'.slider-identifier2 .rightArrowIcon'}, 21 | callback:function(e, dir, distance){} 22 | }); 23 | // 样式3 24 | var tp = new TouchPlugin({ 25 | sliderContainer:'.slider-identifier3.slider-container', 26 | slider:'.slider-identifier3 .slider', 27 | slidePin:'.slider-identifier3 .slider-pin', 28 | sliderBar:'.slider-identifier3 .slide-bar', 29 | pinClassName:'on', 30 | pin:'.slider-identifier3 .pin', 31 | leftRightToggleBtn:{left:'.slider-identifier3 .leftArrowIcon',right:'.slider-identifier3 .rightArrowIcon'}, 32 | callback:function(e, dir, distance){} 33 | }); 34 | } -------------------------------------------------------------------------------- /src/css/index.css: -------------------------------------------------------------------------------- 1 | html,body,div,img{margin: 0;padding: 0;} 2 | /*Icon */ 3 | .leftArrowIcon,.rightArrowIcon{display:inline-block;position: relative;width: 30px;height: 30px;cursor: pointer;padding:5px;} 4 | .leftArrowIcon::before,.leftArrowIcon::after,.rightArrowIcon::before,.rightArrowIcon::after{position: absolute;content: "";width: 20px;height: 3px;top:17px;left:8px;background-color: #fff; -webkit-transform-origin: left;-ms-transform-origin: left;transform-origin: left;} 5 | .rightArrowIcon::before,.rightArrowIcon::after { -webkit-transform-origin: right;-ms-transform-origin: right;transform-origin: right;} 6 | .leftArrowIcon::before,.rightArrowIcon::before{-webkit-transform: rotate(-45deg) translate(0,1px);-ms-transform: rotate(-45deg) translate(0,1px);transform: rotate(-45deg) translate(0,1px);} 7 | .leftArrowIcon::after,.rightArrowIcon::after{-webkit-transform: rotate(45deg) translate(0,1px);-ms-transform: rotate(45deg) translate(0,1px);transform: rotate(45deg) translate(0,1px);} 8 | 9 | 10 | 11 | .slider-container {position: relative;width: auto;height: auto;white-space: nowrap;overflow: hidden;} 12 | .slider {display: inline-block;width: 100%;height: 100%;} 13 | .slider * {user-select: none;} 14 | .slider img {width: 100%;} 15 | 16 | .slider:nth-child(n + 2) {margin-left: -5px;} 17 | .slide-bar {height: 100%;user-select: none;} 18 | .slider-pin {position: absolute;width: 100vw;left: 0;bottom: 15px;text-align: center;z-index: 100;} 19 | .slider-pin,.slider-pin * {user-select: none;} 20 | .slider-pin span {display: inline-block;margin: 0 5px;width: 10px;height: 10px;border-radius: 100%;cursor: pointer;color: transparent;background-color: white;} 21 | .slider-pin span.on {background-color: dodgerblue;} 22 | /* .slider-pin[data-type="img"] {} */ 23 | .slider-pin[data-type="img"] span{margin:0 10px 0 0;width:100px;height:50px;border-radius: 0;} 24 | .slider-pin[data-type="img"] span img{width:100px;height:50px;} 25 | .slider-pin[data-type="img"] span.on {border:solid 2px dodgerblue;} 26 | 27 | .left-right-btn .leftArrowIcon,.left-right-btn .rightArrowIcon{position: absolute;width:30px;height:30px;top:0;bottom:0;margin:auto;z-index: 2000;} 28 | .left-right-btn .leftArrowIcon{left:0;} 29 | .left-right-btn .rightArrowIcon{right:0;} 30 | .left-right-btn .leftArrowIcon:hover,.left-right-btn .rightArrowIcon:hover{background-color: gray;} 31 | 32 | @media only screen and (max-width:1240px){ 33 | .slider-pin[data-type="img"] span{margin:0 10px 0 0;width:50px;height:30px;border-radius: 0;} 34 | .slider-pin[data-type="img"] span img{width:50px;height:30px;} 35 | } 36 | @media only screen and (max-width:600px){ 37 | .leftArrowIcon,.rightArrowIcon{width: 20px;height: 20px;} 38 | .left-right-btn .leftArrowIcon,.left-right-btn .rightArrowIcon{width:15px;height:15px;} 39 | .left-right-btn .leftArrowIcon:hover,.left-right-btn .rightArrowIcon:hover{background-color:transparent;} 40 | .leftArrowIcon::before,.leftArrowIcon::after,.rightArrowIcon::before,.rightArrowIcon::after{width: 15px;height: 2px;top:10px;left:5px;} 41 | 42 | .slider-pin{bottom: 10px;} 43 | .slider-pin span,.slider-pin[data-type="img"] span{margin: 0 5px;width:5px;height:5px;border-radius: 100%;} 44 | .slider-pin[data-type="img"] span img{display: none;} 45 | .slider-pin[data-type="img"] span.on {border:none} 46 | } -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 滚动插件 8 | 9 | 16 | 17 | 18 |
19 |

Fox-slider 轮播图

20 |

21 |
22 |
23 |

样式一:

24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | 34 | 35 | 36 | 37 | 38 |
39 |
40 | 41 |

样式二:

42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 |
59 |
60 | 61 | 62 |
63 |
64 | 65 | 66 |

样式三:

67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | 77 | 78 | 79 | 80 | 81 |
82 |
83 | 84 |
85 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # 原生 JS 撸一个轮播图(支持拖拽切屏) 3 | 4 | >## FoxSlider.js 称不上库的库 [在线page]( https://forrestyuan.github.io/FoxSliderJS/) 5 | 6 | > last update time: 2019-08-15 7 | > - 修复轮播图边界时滚动不流畅 8 | > - 新增 **2个**轮播图样式[点我去看效果]( https://forrestyuan.github.io/FoxSliderJS/src/index.html) 9 | > - IE9的一些兼容性修复 10 | 11 | ## 1、简述 12 | 13 | 用惯了各种各样的组件,并没有真正意义上的封装一个可以拖拽切屏的轮播图,经过一番编写,发现写这样一个轮播图要想写的好,还真的是挺有难度,不同设备的不同事件完备性?事件触发时机的把控?如何更好的去封装?自适应窗口后的事件重置?等等...,看看swiper这个库的源码,就知道小事情也可以不简单。 14 | 现在写的这个基本的需求是可以满足的,可以通过拖拽切换也可以点击切换。 15 | >(想你来一起完(wan)善(shua)!!Fork & Star ^_^一下你就会很美 16 | 17 | >**原生撸码一时爽,一直原生一直爽** 18 | 19 | ### 1.1、特性 20 | 21 | - 面向手机、平板,PC等终端。 22 | 23 | ### 1.2、缺点 24 | - 功能亟需扩充 25 | - 用户配置功能有待扩充 26 | - 轮播图样式不够丰富 27 | - 性能待测 28 | 29 | ## 2、调用实例 30 | >html 结构代码 31 | 32 | ``` 33 | 34 | 35 | 36 | 37 |

样式一:

38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | 48 | 49 | 50 | 51 | 52 |
53 |
54 | ``` 55 | 56 | >js 代码 57 | 58 | ```js 59 | //样式1 60 | var tp = new TouchPlugin({ 61 | sliderContainer:'.slider-identifier.slider-container', 62 | slider:'.slider-identifier .slider', 63 | slidePin:'.slider-identifier .slider-pin', 64 | sliderBar:'.slider-identifier .slide-bar', 65 | pinClassName:'on', 66 | pin:'.slider-identifier .pin', 67 | callback:function(e, dir, distance){} 68 | }); 69 | ``` 70 | >运行效果 71 | 72 | ![运行效果图](https://github.com/forrestyuan/FoxSlider.js/blob/master/foxslider.gif?raw=true) 73 | 74 | ## 3、`base.js`内主要方法 75 | 76 | 77 | 78 | >### init() 79 | 初始化函数 80 | 81 | **Kind**: global function 82 | *** 83 | 84 | 85 | 86 | ### refreshParam(totalMoveLen, spinIndex) 87 | 刷新参数 88 | 89 | **Kind**: global function 90 | 91 | | Param | Type | Description | 92 | | --- | --- | --- | 93 | | totalMoveLen | number | 滚动位移 | 94 | | spinIndex | number | 轮播指标高亮下标 | 95 | 96 | *** 97 | 98 | 99 | ## setTranslate(domNode, conf, moveLen) 100 | 设置指定对象移动样式 (transform) 101 | 102 | **Kind**: global function 103 | 104 | | Param | Type | Description | 105 | | --- | --- | --- | 106 | | domNode | Object | 应用移动样式的对象 | 107 | | conf | Object | 配置对象(animateStyle: ease-in-out|linear|ease-in|ease; animateTime:); | 108 | | moveLen | number | 轮播图移动距离(切屏通过控制位移) | 109 | *** 110 | 111 | 112 | 113 | ### resize() 114 | 改变屏幕尺寸重置参数 115 | 116 | **Kind**: global function 117 | *** 118 | 119 | 120 | 121 | ### autoRun(time, initStep) 122 | 自动轮播 123 | 124 | **Kind**: global function 125 | 126 | | Param | Type | Description | 127 | | --- | --- | --- | 128 | | time | number | 轮播时间 | 129 | | initStep | number | spin下标 和下一屏 | 130 | *** 131 | 132 | 133 | 134 | ### judgeDir(curX, preX) 135 | 判断鼠标或触摸移动的方向 136 | 137 | **Kind**: global function 138 | 139 | | Param | Type | Description | 140 | | --- | --- | --- | 141 | | curX | number | 鼠标点击或开始触摸屏幕时的坐标X | 142 | | preX | numer | 鼠标移动或触摸移动时的坐标X | 143 | *** 144 | 145 | 146 | 147 | ### testTouchEvent() 148 | 检测当前设备支持的事件(鼠标点击移动和手触摸移动) 149 | 150 | **Kind**: global function 151 | *** 152 | 153 | 154 | 155 | ### mouseX(event) 156 | 获取鼠标横坐标位置 157 | 158 | **Kind**: global function 159 | 160 | 161 | | Param | Type | Description | 162 | | --- | --- | --- | 163 | | event | Event | 事件对象 | 164 | 165 | *** 166 | 167 | 168 | ### cancelBind(domNode) 169 | 取消绑定触摸或鼠标点击移动事件 170 | 171 | **Kind**: global function 172 | 173 | | Param | Type | Description | 174 | | --- | --- | --- | 175 | | domNode | Object | 需要被取消绑定事件节点对象 | 176 | *** 177 | 178 | 179 | 180 | ### reBindTouchEvent(domNode, callback, isUnbind) 181 | 重新绑定触摸事件 182 | 183 | **Kind**: global function 184 | 185 | | Param | Type | Description | 186 | | --- | --- | --- | 187 | | domNode | Object | 需要被绑定事件节点对象 | 188 | | callback | function | 回调方法 | 189 | | isUnbind | boolean | 是否取消绑定 | 190 | *** 191 | 192 | 193 | 194 | ### removeClsName(nodeList, clsName) 195 | 移除节点的样式类名 196 | 197 | **Kind**: global function 198 | 199 | | Param | Type | Description | 200 | | --- | --- | --- | 201 | | nodeList | Array | 被移除样式的节点数组 | 202 | | clsName | string | 移除的样式类名称 | 203 | *** 204 | 205 | 206 | 207 | ### setClsName(node, clsName) 208 | 添加样式 209 | 210 | **Kind**: global function 211 | 212 | | Param | Type | Description | 213 | | --- | --- | --- | 214 | | node | Object | 添加类名的节点 | 215 | | clsName | string | 样式类名 | 216 | *** 217 | 218 | 219 | 220 | ### bindSpinClick() 221 | 点击轮播spin 切换屏 222 | 223 | **Kind**: global function 224 | *** 225 | 226 | 227 | ### bindLeftRightBtnClick() 228 | 点击左右按钮切换屏 229 | 230 | **Kind**: global function 231 | *** 232 | 233 | 234 | ## checkTargetByCls(domNode, clsName) 235 | 通过检测dom节点是否包含某个样式名来判断是否属于目标target 236 | 237 | **Kind**: global function 238 | 239 | | Param | Type | 240 | | --- | --- | 241 | | domNode | Object | 242 | | clsName | string | 243 | *** 244 | 245 | 246 | ### bindTouchEvent(domNode, callback, isUnbind) 247 | **Kind**: global function 248 | 249 | | Param | Type | Description | 250 | | --- | --- | --- | 251 | | domNode | Object | 绑定事件的代理对象 | 252 | | callback | function | 回调方法 | 253 | | isUnbind | boolean | 是否取消绑定 | 254 | *** 255 | -------------------------------------------------------------------------------- /src/js/base.js: -------------------------------------------------------------------------------- 1 | var getEle = (function (obj) { 2 | return function (selector, isSingle) { 3 | return isSingle ? obj.querySelector(selector) : obj.querySelectorAll(selector); 4 | } 5 | })(window.document); 6 | 7 | /** 8 | * @param {Object} obj 参数配置,参数的值为 样式名 即可。以下的argument配置在obj对象中 9 | * @argument sliderContainer 轮播图最顶层父容器 10 | * @argument sliderBar 轮播图Item的父容器 11 | * @argument slider 轮播图Item 12 | * @argument sliderPin 轮播图小圆点的容器 13 | * @argument pin 轮播图高亮小圆点 14 | * @argument pinClassName 高亮小圆点时的样式,可自定义样式名 15 | * @argument leftRightToggleBtn {left:'.left', rigth:'right'} 16 | * 17 | */ 18 | function TouchPlugin(obj) { 19 | /** 20 | * @desc 初始化函数 21 | */ 22 | this.init = function () { 23 | //配置信息 24 | this.sliderContainer = getEle(obj.sliderContainer); 25 | this.slider = getEle(obj.slider); 26 | this.sliderPin = getEle(obj.sliderPin); 27 | this.pinClassName = obj.pinClassName || "on"; 28 | this.sliderBar = getEle(obj.sliderBar); 29 | this.pin = getEle(obj.pin); 30 | this.leftToggleBtn = ("leftRightToggleBtn" in obj) ? getEle(obj.leftRightToggleBtn.left):null; 31 | this.rightToggleBtn = ("leftRightToggleBtn" in obj) ? getEle(obj.leftRightToggleBtn.right):null; 32 | this.autoScrollInterval = null; 33 | this.hasMove = false; 34 | //取消图片拖拽默认事件 35 | for (var i = 0; i < this.slider.length; i++) { 36 | this.slider[i].querySelector('img').setAttribute('ondragstart', 'return false'); 37 | } 38 | //改变屏幕尺寸会刷新的配置参数 39 | this.refreshParam(); 40 | //事件绑定 41 | this.testTouchEvent(); 42 | this.bindTouchEvent(this.sliderContainer[0], obj.callback, false); 43 | this.resize(); 44 | this.bindSpinClick(); 45 | ;!!(this.leftToggleBtn && this.rightToggleBtn) ? this.bindLeftRightBtnClick() : false; 46 | this.autoRun(); 47 | } 48 | 49 | /** 50 | * @desc 设置指定对象移动样式 (transform) 51 | * @param {Object} domNode 应用移动样式的对象 52 | * @param {Object} conf 配置对象(animateStyle: ease-in-out|linear|ease-in|ease; animateTime:); 53 | * @param {number} moveLen 轮播图移动距离(切屏通过控制位移) 54 | */ 55 | this.setTranslate = function (domNode, conf, moveLen) { 56 | conf = conf || {}; 57 | var animateTime = conf.animateTime || '.3s'; 58 | var animateStyle = conf.animateStyle || 'ease-in-out'; 59 | moveLen = moveLen || 0; 60 | domNode.style.cssText = 'transition:all '+animateStyle +' '+ animateTime+';transform:translateX(' + moveLen + 'px);-ms-transform:translateX(' + moveLen + 'px);-moz-transform:translateX(' + moveLen + 'px);-webkit-transform:translateX(' + moveLen + 'px);-o-transform:translateX(' + moveLen + 'px)'; 61 | } 62 | /** 63 | * @desc 刷新参数 64 | * @param {number} totalMoveLen 滚动位移 65 | * @param {number} spinIndex 轮播指标高亮下标 66 | */ 67 | this.refreshParam = function (totalMoveLen, spinIndex) { 68 | this.preX = 0; //鼠标点击或开始触摸屏幕时的坐标X 69 | this.curX = 0; //鼠标移动或触摸移动时的坐标X 70 | this.totalMoveLen = totalMoveLen || 0; // 记录上一次移动的坐标X总值 71 | this.hasmoveLen = 0; //当前触摸或鼠标移动事件的已经移动的坐标X值 72 | this.isNeedRebindTag = false; //滑动过程中是否达到需要重新绑定事件的界限 73 | this.dir = 0; //鼠标或触摸移动的方向 大于0 向右, 小于0 向左 等于0 无左右移动 74 | this.sliderW = Math.floor(this.slider[0].offsetWidth); //轮播容器内的每一屏的宽度 75 | this.removeClsName(this.pin, 'on'); 76 | this.setClsName(this.pin[spinIndex || 0], 'on'); 77 | this.setTranslate(this.sliderBar[0],{}, this.totalMoveLen); 78 | } 79 | 80 | 81 | /** 82 | * @desc 改变屏幕尺寸重置参数 83 | */ 84 | this.resize = function () { 85 | var that = this; 86 | if (window.addEventListener) { 87 | window.addEventListener('resize', function (ev) { 88 | console.log("resize chrome"); 89 | that.refreshParam(); 90 | that.bindTouchEvent(that.sliderContainer, obj.callback, false); 91 | that.autoRun(); 92 | }, false) 93 | } else { 94 | window.attachEvent('resize', function (ev) { 95 | console.log("resize IE"); 96 | that.refreshParam(); 97 | that.bindTouchEvent(that.sliderContainer, obj.callback, false); 98 | that.autoRun(); 99 | }) 100 | } 101 | } 102 | 103 | 104 | /** 105 | * @desc 自动轮播 106 | * @param {number} time 轮播时间 107 | * @param {number} initStep spin下标 和下一屏 108 | */ 109 | this.autoRun = function (time, initStep) { 110 | var that = this; 111 | var stepLen = that.sliderW; 112 | var step = initStep || 0; 113 | clearInterval(that.autoScrollInterval); 114 | that.autoScrollInterval = setInterval(function () { 115 | that.refreshParam(-stepLen * step, step); 116 | step++; 117 | if (step >= that.slider.length) { 118 | step = 0; 119 | } 120 | 121 | }, time || 3000); 122 | } 123 | 124 | /** 125 | * @desc 判断鼠标或触摸移动的方向 126 | * @param {number} curX 鼠标点击或开始触摸屏幕时的坐标X 127 | * @param {number} preX 鼠标移动或触摸移动时的坐标X 128 | */ 129 | this.judgeDir = function (curX, preX) { 130 | return curX - preX > 0 ? 1 : curX - preX < 0 ? -1 : 0; 131 | }; 132 | 133 | /** 134 | * @desc 检测当前设备支持的事件(鼠标点击移动和手触摸移动) 135 | */ 136 | this.testTouchEvent = function () { 137 | if ("ontouchstart" in window) { 138 | this.eventStart = "ontouchstart"; 139 | this.eventEnd = "ontouchend"; 140 | this.eventMove = "ontouchmove"; 141 | } else { 142 | this.eventStart = "onmousedown"; 143 | this.eventEnd = "onmouseup"; 144 | this.eventMove = "onmousemove"; 145 | } 146 | console.log("初始化完成") 147 | }; 148 | 149 | /** 150 | * @desc 获取鼠标横坐标位置 151 | * @param {Event} event 事件对象 152 | */ 153 | this.mouseX = function (event) { 154 | event = event || window.event; 155 | var x = event.clientX || event.pageX || event.touches[0].clientX || event.touches[0].pageX; 156 | return x; 157 | }; 158 | 159 | 160 | /** 161 | * @desc 取消绑定触摸或鼠标点击移动事件 162 | * @param {Object} domNode 需要被取消绑定事件节点对象 163 | */ 164 | this.cancelBind = function (domNode) { 165 | domNode[this.eventStart] = null; 166 | domNode[this.eventEnd] = null; 167 | domNode[this.eventMove] = null; 168 | } 169 | 170 | /** 171 | * @desc 重新绑定触摸事件 172 | * @param {Object} domNode 需要被绑定事件节点对象 173 | * @param {function} callback 回调方法 174 | * @param {boolean} isUnbind 是否取消绑定 175 | */ 176 | this.reBindTouchEvent = function (domNode, callback, isUnbind) { 177 | var that = this; 178 | setTimeout(function () { 179 | that.bindTouchEvent(domNode, callback, isUnbind); 180 | }, 1000) 181 | } 182 | 183 | /** 184 | * @desc 移除节点的样式类名 185 | * @param {Array} nodeList 被移除样式的节点数组 186 | * @param {string} clsName 移除的样式类名称 187 | */ 188 | this.removeClsName = function (nodeList, clsName) { 189 | for (var i = 0; i < nodeList.length; i++) { 190 | if("classList" in nodeList[i]){ 191 | nodeList[i].classList.remove(clsName); 192 | }else{ 193 | var clsList = nodeList[i].getAttribute("class").split(/\s+/); 194 | var tmpArr = []; 195 | for(var j = 0; j < clsList.length; j++){ 196 | clsList[j]!==clsName ? tmpArr.push(clsList[j]) : false; 197 | } 198 | nodeList[i].setAttribute("class",tmpArr.join(" ")); 199 | tmpArr = null; 200 | } 201 | } 202 | }; 203 | 204 | /** 205 | * @desc 添加样式 206 | * @param {Object} node 添加类名的节点 207 | * @param {string} clsName 样式类名 208 | */ 209 | this.setClsName = function (node, clsName) { 210 | if("classList" in node){ 211 | node.classList.add(clsName); 212 | }else{ 213 | node.setAttribute("class",node.getAttribute("class") +" "+clsName); 214 | } 215 | 216 | } 217 | 218 | /** 219 | * @desc 点击轮播spin 切换屏 220 | */ 221 | this.bindSpinClick = function () { 222 | var that = this; 223 | for (var i = 0; i < that.pin.length; i++) { 224 | (function (sub) { 225 | that.pin[sub].onclick = function (ev) { 226 | ev.stopPropagation(); 227 | that.refreshParam(-sub * that.sliderW, sub); 228 | that.autoRun(3000,sub); 229 | } 230 | })(i); 231 | } 232 | } 233 | /** 234 | * @desc 点击左右箭头 切换屏 235 | */ 236 | this.bindLeftRightBtnClick = function () { 237 | console.log("init leftrightbtn click") 238 | var that = this; 239 | console.log((that.leftToggleBtn||that.leftToggleBtn[0])); 240 | ;(that.leftToggleBtn[0]||that.leftToggleBtn).onclick = function (ev) { 241 | ev.stopPropagation(); 242 | that.totalMoveLen += that.totalMoveLen + that.sliderW > 0 ? -that.sliderW* (that.slider.length - 1) : that.sliderW; 243 | console.log(that.totalMoveLen) 244 | var sub =Math.floor(Math.abs(that.totalMoveLen / that.sliderW)); 245 | that.refreshParam(that.totalMoveLen, sub); 246 | that.autoRun(3000,sub); 247 | } 248 | ;(that.rightToggleBtn[0]||that.rightToggleBtn).onclick = function (ev) { 249 | ev.stopPropagation(); 250 | that.totalMoveLen -= that.totalMoveLen - that.sliderW < -that.sliderW * (that.slider.length - 1) ? that.totalMoveLen : that.sliderW; 251 | console.log(that.totalMoveLen) 252 | var sub =Math.floor(Math.abs(that.totalMoveLen / that.sliderW)); 253 | that.refreshParam(that.totalMoveLen, sub); 254 | that.autoRun(3000,sub); 255 | } 256 | } 257 | 258 | /** 259 | * @desc 通过检测dom节点是否包含某个样式名来判断是否属于目标target 260 | * @param {Object} domNode 261 | * @param {string} clsName 262 | */ 263 | this.checkTargetByCls = function(domNode, clsName){ 264 | 265 | if("clssList" in domNode){ 266 | return domNode.classList.contains(clsName); 267 | }else{ 268 | if(!domNode.getAttribute("class")){ 269 | return false; 270 | } 271 | var clsList = domNode.getAttribute("class").split(/\s+/); 272 | for(var i = 0; i < clsList.length; i++){ 273 | if(clsList[i] == clsName){ 274 | return true; 275 | } 276 | } 277 | } 278 | return false; 279 | } 280 | 281 | /** 282 | * 283 | * @param {Object} domNode 绑定事件的代理对象 284 | * @param {function} callback 回调方法 285 | * @param {boolean} isUnbind 是否取消绑定 286 | */ 287 | this.bindTouchEvent = function(domNode, callback, isUnbind) { 288 | var that = this; 289 | if (!domNode) return; 290 | if (isUnbind) { 291 | that.cancelBind(domNode); 292 | return; 293 | } 294 | domNode[that.eventStart] = function(ev) { 295 | ev = ev || window.ev; 296 | clearInterval(that.autoScrollInterval); 297 | that.preX = that.mouseX(ev); 298 | domNode[that.eventMove] = typeof callback == "function" ? function(ev) { 299 | console.log('has move') 300 | that.hasMove = true; // 鼠标或触摸有滑动位移 301 | that.removeClsName(that.pin, "on"); 302 | that.curX = that.mouseX(ev); 303 | that.dir = that.judgeDir(that.curX, that.preX); 304 | that.hasmoveLen = that.totalMoveLen + (that.curX - that.preX) * 2.2; 305 | callback( ev, that.dir, Math.round(that.hasmoveLen / that.sliderW) ); 306 | //轮播边界判定 小于第一屏 307 | if (that.hasmoveLen / that.sliderW > 0.2) { 308 | console.log("小于第一屏") 309 | that.hasmoveLen = -(that.slider.length - 1) * that.sliderW; 310 | that.isNeedRebindTag = true; 311 | } 312 | //轮播边界判定 大于最后一屏 313 | if ( that.hasmoveLen / that.sliderW < -(that.slider.length - 0.8) ) { 314 | console.log("大于最后一屏") 315 | that.hasmoveLen = 0; 316 | that.isNeedRebindTag = true; 317 | } 318 | that.setTranslate(that.sliderBar[0],{animateTime:that.isNeedRebindTag ? '0.4s' : '.0s'},that.hasmoveLen); 319 | var pinNode = that.pin[ Math.round(Math.abs(that.hasmoveLen / that.sliderW))]; 320 | that.setClsName(pinNode, "on"); 321 | //检测当移动事件对象是否发生在合法对象上。 322 | if (ev.target.tagName !== 'IMG') { 323 | domNode[that.eventEnd](); 324 | return; 325 | } 326 | //当达到要重新绑定事件时的条件触发(轮播屏达到边界) 327 | if (that.isNeedRebindTag) { 328 | that.cancelBind(domNode); 329 | that.totalMoveLen = that.dir > 0 ? -(that.slider.length - 1) * that.sliderW : 0; 330 | that.isNeedRebindTag = false; 331 | that.reBindTouchEvent(domNode, callback, isUnbind); 332 | } 333 | } : null; 334 | }; 335 | domNode[that.eventEnd] = function(ev) { 336 | ev = ev || window.event; 337 | domNode[that.eventMove] = null; 338 | if(that.checkTargetByCls(ev.target, 'pin')){ 339 | return; 340 | } 341 | var num = 0; 342 | if(!that.hasMove){ 343 | num = Math.round(that.totalMoveLen / that.sliderW) 344 | }else{ 345 | num = Math.round((that.hasmoveLen / that.sliderW)); 346 | num = num > 0 ? -that.slider.length + 1 : num; 347 | num = num < -(that.slider.length - 1) ? 0 : num; 348 | } 349 | that.hasMove = false; 350 | that.setTranslate(that.sliderBar[0],{},(num*that.sliderW)); 351 | that.totalMoveLen = num * that.sliderW; 352 | that.autoRun( 3000, Math.round(Math.abs(that.hasmoveLen / that.sliderW)) ); 353 | }; 354 | }; 355 | 356 | this.init(); 357 | } --------------------------------------------------------------------------------