sliderVerify.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /**
  2. * 滑块验证
  3. * @author good_idea
  4. * @date 2019年1月11日 上午10:48:41
  5. */
  6. layui.define(["jquery", "layer", "form"], function (exports) {
  7. "use strict";
  8. var $ = layui.jquery,
  9. form = layui.form,
  10. layer = layui.layer,
  11. device = layui.device(),
  12. sliderVerify = {
  13. read: (function () {
  14. var css =
  15. ".slider-item{height:38px;line-height:38px;background-color:#d0d0d0;position:relative;border: 1px solid white;}.slider-bg{position:absolute;width:40px;height:100%;z-index:100}.slider-btn{width:40px;height:96%;position:absolute;border:1px solid #ccc;cursor:move;text-align:center;background-color:#fff;user-select:none;color:#666;z-index:120}.slider-btn-success{font-size:26px}.slider-text{position:absolute;text-align:center;width:100%;height:100%;user-select:none;font-size:14px;color:#fff;z-index:120}.slider-error{animation:glow 800ms ease-out infinite alternate;}@keyframes glow{0%{border-color:#e6e6e6}100%{border-color:#ff5722}}",
  16. style = document.createElement("style");
  17. style.innerHTML = css;
  18. style.type = "text/css";
  19. ($("head link:last")[0] && $("head link:last").after(style)) ||
  20. $("head").append(style);
  21. })()
  22. },
  23. dom = function (d) {
  24. return d[0];
  25. },
  26. thisSliderVerify = function () {
  27. var that = this;
  28. return {
  29. isOk: function () {
  30. return that.isOk.call(that);
  31. },
  32. reset: function () {
  33. return that.reset.call(that);
  34. },
  35. version: '1.7'
  36. };
  37. },
  38. MOD_NAME = "sliderVerify",
  39. MOD_BTN = "slider-btn",
  40. MOD_BG = "slider-bg",
  41. MOD_TEXT = "slider-text",
  42. MOD_NEXT = "layui-icon-next",
  43. MOD_OK = "layui-icon-ok-circle",
  44. MOD_BTN_SUCCESS = "slider-btn-success",
  45. MOD_DEFAULT_BG = "layui-bg-green",
  46. MOD_ERROR_BORDER = "slider-error",
  47. MOD_CONFIG_TEXT = "请拖动滑块验证",
  48. MOD_CONFIG_SUCCESS = "验证通过",
  49. Class = function (option) {
  50. var that = this;
  51. that.config = $.extend({}, that.config, option);
  52. that.render();
  53. };
  54. //默认配置
  55. Class.prototype.config = {
  56. elem: "",
  57. onOk: null,
  58. isOk: false,
  59. isAutoVerify: true,
  60. bg: MOD_DEFAULT_BG, //默认滑块颜色
  61. text: MOD_CONFIG_TEXT
  62. };
  63. Class.prototype.render = function () {
  64. var that = this,
  65. option = that.config,
  66. elem = $(option.elem);
  67. if (!elem[0]) return;
  68. if (option.domid) option.domid.remove();
  69. option.domid = that.createIdNum();
  70. var sliderDom = $(
  71. [
  72. '<div id="' +
  73. option.domid +
  74. '"' +
  75. (option.isAutoVerify ? 'lay-verify="sliderVerify"' : "") +
  76. 'class="slider-item">',
  77. '<div class="' + MOD_BG + " " + option.bg + '"></div>',
  78. '<div class="' + MOD_TEXT + '">' + option.text + "</div>",
  79. '<div class="' + MOD_BTN + ' layui-icon layui-icon-next"></div>'
  80. ].join("")
  81. );
  82. elem.hide().after(sliderDom);
  83. option.domid = $("#" + option.domid);
  84. that.events();
  85. //自动验证
  86. if (option.isAutoVerify) {
  87. form.verify({
  88. sliderVerify: function (value, dom) {
  89. if (!value) {
  90. dom.classList.add(MOD_ERROR_BORDER);
  91. return option.text;
  92. }
  93. }
  94. });
  95. }
  96. };
  97. Class.prototype.isMobile = function () {
  98. return (
  99. device.os == "ios" ||
  100. device.os == "android" ||
  101. device.android ||
  102. device.ios
  103. ) || (device.weixin && typeof device.weixin === Boolean);
  104. };
  105. Class.prototype.createIdNum = function () {
  106. return (
  107. MOD_NAME +
  108. (+new Date()).toString() +
  109. Math.random()
  110. .toString()
  111. .substr(2, 7)
  112. );
  113. };
  114. //验证是否验证成功
  115. Class.prototype.isOk = function () {
  116. return this.config.isOk;
  117. };
  118. Class.prototype.error = function (msg) {
  119. return layer.msg(msg, {
  120. icon: 5
  121. });
  122. };
  123. Class.prototype.distance = function () {
  124. var container = this.config.container;
  125. return container.box.offsetWidth - container.btn.offsetWidth; //滑动成功的宽度(距离)
  126. };
  127. //重置组件
  128. Class.prototype.reset = function () {
  129. this.config.isOk = false;
  130. return this.render();
  131. };
  132. //重置
  133. Class.prototype.resize = function (distance) {
  134. var that = this,
  135. container = that.config.container;
  136. var distance = distance || that.distance();
  137. container.btn.style.left = distance + "px";
  138. container.bg.style.width = distance + "px";
  139. };
  140. //取消动画
  141. Class.prototype.cancelTransition = function () {
  142. var container = this.config.container;
  143. this.config.domid[0].classList.remove(MOD_ERROR_BORDER);
  144. container.btn.style.transition = "";
  145. container.bg.style.transition = "";
  146. };
  147. //按下
  148. Class.prototype.down = function (e) {
  149. var that = this,
  150. option = that.config,
  151. container = option.container,
  152. e = e || window.event,
  153. //按下的坐标
  154. downX = e.clientX || e.touches[0].clientX;
  155. //每次将过渡去掉
  156. that.cancelTransition();
  157. var move = function (e) {
  158. that.move(downX, e);
  159. };
  160. that.events.move = move;
  161. //mobile移动
  162. if (that.isMobile()) {
  163. document.addEventListener("touchmove", that.events.move);
  164. } else {
  165. //pc移动
  166. document.onmousemove = move;
  167. }
  168. //处理部分浏览器滑动时左右翻页
  169. if(navigator.userAgent.indexOf("UCBrowser") > -1){
  170. e.preventDefault()
  171. }
  172. };
  173. //移动
  174. Class.prototype.move = function (down, e) {
  175. var that = this,
  176. option = that.config,
  177. container = option.container;
  178. var e = e || window.event;
  179. //鼠标移动后的水平位置
  180. var moveX = e.clientX || e.touches[0].clientX;
  181. //鼠标水平位置的偏移量(鼠标移动时的位置 - 鼠标按下时的位置)
  182. var offsetX = moveX - down;
  183. //判断一下:鼠标水平移动的距离 与 滑动成功的距离 之间的关系
  184. if (offsetX > container.distance) {
  185. offsetX = container.distance; //如果滑过了终点,就将它停留在终点位置
  186. } else if (offsetX < 0) {
  187. offsetX = 0; //滑到了起点的左侧,将它重置为起点位置
  188. }
  189. container.btn.style.left = offsetX + "px";
  190. container.bg.style.width = offsetX + "px";
  191. //鼠标的水平移动距离 = 滑动成功的宽度
  192. if (offsetX == container.distance) {
  193. //1.滑动成功后的样式
  194. container.text.innerHTML = MOD_CONFIG_SUCCESS;
  195. var com = window.getComputedStyle
  196. ? window.getComputedStyle(container.bg, null)
  197. : container.bg.currentStyle;
  198. container.btn.style.border = "1px solid " + com.backgroundColor;
  199. container.btn.style.color = com.backgroundColor;
  200. container.btn.classList.remove(MOD_NEXT);
  201. container.btn.classList.add(MOD_OK, MOD_BTN_SUCCESS);
  202. option.isOk = true;
  203. container.box.value = true;
  204. //成功后,清除掉鼠标按下事件和移动事件(因为移动时并不会涉及到鼠标松开事件)
  205. //干掉mobile事件
  206. if (that.isMobile()) {
  207. container.btn.removeEventListener(
  208. "touchstart",
  209. that.events.down,
  210. false
  211. );
  212. document.removeEventListener(
  213. "touchmove",
  214. that.events.move,
  215. false
  216. );
  217. } else {
  218. container.btn.onmousedown = null;
  219. document.onmousemove = null;
  220. }
  221. //最后调用回调
  222. option.onOk && typeof option.onOk == "function" && option.onOk();
  223. return;
  224. }
  225. var seup = function (e) {
  226. that.stop(e);
  227. };
  228. that.events.seup = seup;
  229. if (that.isMobile()) {
  230. document.addEventListener("touchend", seup);
  231. } else {
  232. document.onmouseup = seup;
  233. }
  234. };
  235. //放开
  236. Class.prototype.stop = function (e) {
  237. var that = this,
  238. option = that.config,
  239. container = option.container;
  240. //鼠标松开,如果滑到了终点,则验证通过
  241. if (that.isOk()) {
  242. return;
  243. } else {
  244. container.btn.style.left = 0;
  245. container.bg.style.width = 0;
  246. container.btn.style.transition = "left 1s";
  247. container.bg.style.transition = "width 1s";
  248. }
  249. //鼠标松开了,不需要拖动就清除鼠标移动和松开事件。
  250. document.onmousemove = null;
  251. document.onmouseup = null;
  252. if (that.isMobile()) {
  253. document.removeEventListener("touchmove", that.events.move, false);
  254. document.removeEventListener("touchend", that.events.seup, false);
  255. }
  256. };
  257. //事件
  258. Class.prototype.events = function () {
  259. var that = this,
  260. option = that.config;
  261. if (!option.domid) return that.error("创建滑块验证失败");
  262. var btn = option.domid.find("." + MOD_BTN),
  263. bg = option.domid.find("." + MOD_BG),
  264. text = option.domid.find("." + MOD_TEXT),
  265. container = {
  266. box: dom(option.domid),
  267. btn: dom(btn),
  268. bg: dom(bg),
  269. text: dom(text)
  270. };
  271. option.container = container;
  272. container.distance = that.distance();
  273. var down = function (e) {
  274. that.down(e);
  275. };
  276. that.events.down = down;
  277. if (that.isMobile()) {
  278. container.btn.addEventListener("touchstart", that.events.down);
  279. } else {
  280. container.btn.onmousedown = down;
  281. }
  282. var $dom = $(window);
  283. $dom.on("resize", option.domid, function () {
  284. if (that.config.isOk) {
  285. //重新计算页面被拉伸
  286. that.resize();
  287. }else{
  288. that.render();
  289. }
  290. });
  291. };
  292. sliderVerify.render = function (option) {
  293. var inst = new Class(option);
  294. return thisSliderVerify.call(inst);
  295. };
  296. exports(MOD_NAME, sliderVerify);
  297. });