1
0

lay.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. // *! lay 基础 DOM 操作 | MIT Licensed */
  2. ;!function(window){ //gulp build: lay-header
  3. "use strict";
  4. var MOD_NAME = 'lay' //模块名
  5. ,document = window.document
  6. //DOM查找
  7. ,lay = function(selector){
  8. return new LAY(selector);
  9. }
  10. //DOM构造器
  11. ,LAY = function(selector){
  12. var index = 0
  13. ,nativeDOM = typeof selector === 'object' ? [selector] : (
  14. this.selector = selector
  15. ,document.querySelectorAll(selector || null)
  16. );
  17. for(; index < nativeDOM.length; index++){
  18. this.push(nativeDOM[index]);
  19. }
  20. };
  21. /*
  22. lay 对象操作
  23. */
  24. LAY.prototype = [];
  25. LAY.prototype.constructor = LAY;
  26. //普通对象深度扩展
  27. lay.extend = function(){
  28. var ai = 1, args = arguments
  29. ,clone = function(target, obj){
  30. target = target || (layui._typeof(obj) === 'array' ? [] : {}); //目标对象
  31. for(var i in obj){
  32. //如果值为普通对象,则进入递归,继续深度合并
  33. target[i] = (obj[i] && obj[i].constructor === Object)
  34. ? clone(target[i], obj[i])
  35. : obj[i];
  36. }
  37. return target;
  38. }
  39. args[0] = typeof args[0] === 'object' ? args[0] : {};
  40. for(; ai < args.length; ai++){
  41. if(typeof args[ai] === 'object'){
  42. clone(args[0], args[ai]);
  43. }
  44. }
  45. return args[0];
  46. };
  47. //lay 模块版本
  48. lay.v = '1.0.8';
  49. //ie版本
  50. lay.ie = function(){
  51. var agent = navigator.userAgent.toLowerCase();
  52. return (!!window.ActiveXObject || "ActiveXObject" in window) ? (
  53. (agent.match(/msie\s(\d+)/) || [])[1] || '11' //由于 ie11 并没有 msie 的标识
  54. ) : false;
  55. }();
  56. /**
  57. * 获取 layui 常见方法,以便用于组件单独版
  58. */
  59. lay.layui = layui || {};
  60. lay.getPath = layui.cache.dir; //获取当前 JS 所在目录
  61. lay.stope = layui.stope; //中止冒泡
  62. lay.each = function(){ //遍历
  63. layui.each.apply(layui, arguments);
  64. return this;
  65. };
  66. //数字前置补零
  67. lay.digit = function(num, length, end){
  68. var str = '';
  69. num = String(num);
  70. length = length || 2;
  71. for(var i = num.length; i < length; i++){
  72. str += '0';
  73. }
  74. return num < Math.pow(10, length) ? str + (num|0) : num;
  75. };
  76. //创建元素
  77. lay.elem = function(elemName, attr){
  78. var elem = document.createElement(elemName);
  79. lay.each(attr || {}, function(key, value){
  80. elem.setAttribute(key, value);
  81. });
  82. return elem;
  83. };
  84. //当前页面是否存在滚动条
  85. lay.hasScrollbar = function(){
  86. return document.body.scrollHeight > (window.innerHeight || document.documentElement.clientHeight);
  87. };
  88. //元素定位
  89. lay.position = function(elem, elemView, obj){
  90. if(!elemView) return;
  91. obj = obj || {};
  92. //如果绑定的是 document 或 body 元素,则直接获取鼠标坐标
  93. if(elem === document || elem === lay('body')[0]){
  94. obj.clickType = 'right';
  95. }
  96. //绑定绑定元素的坐标
  97. var rect = obj.clickType === 'right' ? function(){
  98. var e = obj.e || window.event || {};
  99. return {
  100. left: e.clientX
  101. ,top: e.clientY
  102. ,right: e.clientX
  103. ,bottom: e.clientY
  104. }
  105. }() : elem.getBoundingClientRect()
  106. ,elemWidth = elemView.offsetWidth //控件的宽度
  107. ,elemHeight = elemView.offsetHeight //控件的高度
  108. //滚动条高度
  109. ,scrollArea = function(type){
  110. type = type ? 'scrollLeft' : 'scrollTop';
  111. return document.body[type] | document.documentElement[type];
  112. }
  113. //窗口宽高
  114. ,winArea = function(type){
  115. return document.documentElement[type ? 'clientWidth' : 'clientHeight']
  116. }, margin = 5, left = rect.left, top = rect.bottom;
  117. //相对元素居中
  118. if(obj.align === 'center'){
  119. left = left - (elemWidth - elem.offsetWidth)/2;
  120. } else if(obj.align === 'right'){
  121. left = left - elemWidth + elem.offsetWidth;
  122. }
  123. //判断右侧是否超出边界
  124. if(left + elemWidth + margin > winArea('width')){
  125. left = winArea('width') - elemWidth - margin; //如果超出右侧,则将面板向右靠齐
  126. }
  127. //左侧是否超出边界
  128. if(left < margin) left = margin;
  129. //判断底部和顶部是否超出边界
  130. if(top + elemHeight + margin > winArea()){
  131. //优先顶部是否有足够区域显示完全
  132. if(rect.top > elemHeight + margin){
  133. top = rect.top - elemHeight - margin*2; //顶部有足够的区域显示
  134. } else {
  135. //如果面板是鼠标右键弹出,且顶部没有足够区域显示,则将面板向底部靠齐
  136. if(obj.clickType === 'right'){
  137. top = winArea() - elemHeight - margin*2;
  138. if(top < 0) top = 0; //不能溢出窗口顶部
  139. }
  140. }
  141. }
  142. //定位类型
  143. var position = obj.position;
  144. if(position) elemView.style.position = position;
  145. //设置坐标
  146. elemView.style.left = left + (position === 'fixed' ? 0 : scrollArea(1)) + 'px';
  147. elemView.style.top = top + (position === 'fixed' ? 0 : scrollArea()) + 'px';
  148. //防止页面无滚动条时,又因为弹出面板而出现滚动条导致的坐标计算偏差
  149. if(!lay.hasScrollbar()){
  150. var rect1 = elemView.getBoundingClientRect();
  151. //如果弹出面板的溢出窗口底部,则表示将出现滚动条,此时需要重新计算坐标
  152. if(!obj.SYSTEM_RELOAD && (rect1.bottom + margin) > winArea()){
  153. obj.SYSTEM_RELOAD = true;
  154. setTimeout(function(){
  155. lay.position(elem, elemView, obj);
  156. }, 50);
  157. }
  158. }
  159. };
  160. //获取元素上的参数配置上
  161. lay.options = function(elem, attr){
  162. var othis = lay(elem)
  163. ,attrName = attr || 'lay-options';
  164. try {
  165. return new Function('return '+ (othis.attr(attrName) || '{}'))();
  166. } catch(ev) {
  167. hint.error('parseerror:'+ ev, 'error');
  168. return {};
  169. }
  170. };
  171. //元素是否属于顶级元素(document 或 body)
  172. lay.isTopElem = function(elem){
  173. var topElems = [document, lay('body')[0]]
  174. ,matched = false;
  175. lay.each(topElems, function(index, item){
  176. if(item === elem){
  177. return matched = true
  178. }
  179. });
  180. return matched;
  181. };
  182. //追加字符
  183. LAY.addStr = function(str, new_str){
  184. str = str.replace(/\s+/, ' ');
  185. new_str = new_str.replace(/\s+/, ' ').split(' ');
  186. lay.each(new_str, function(ii, item){
  187. if(!new RegExp('\\b'+ item + '\\b').test(str)){
  188. str = str + ' ' + item;
  189. }
  190. });
  191. return str.replace(/^\s|\s$/, '');
  192. };
  193. //移除值
  194. LAY.removeStr = function(str, new_str){
  195. str = str.replace(/\s+/, ' ');
  196. new_str = new_str.replace(/\s+/, ' ').split(' ');
  197. lay.each(new_str, function(ii, item){
  198. var exp = new RegExp('\\b'+ item + '\\b')
  199. if(exp.test(str)){
  200. str = str.replace(exp, '');
  201. }
  202. });
  203. return str.replace(/\s+/, ' ').replace(/^\s|\s$/, '');
  204. };
  205. //查找子元素
  206. LAY.prototype.find = function(selector){
  207. var that = this;
  208. var index = 0, arr = []
  209. ,isObject = typeof selector === 'object';
  210. this.each(function(i, item){
  211. var nativeDOM = isObject ? item.contains(selector) : item.querySelectorAll(selector || null);
  212. for(; index < nativeDOM.length; index++){
  213. arr.push(nativeDOM[index]);
  214. }
  215. that.shift();
  216. });
  217. if(!isObject){
  218. that.selector = (that.selector ? that.selector + ' ' : '') + selector
  219. }
  220. lay.each(arr, function(i, item){
  221. that.push(item);
  222. });
  223. return that;
  224. };
  225. //DOM遍历
  226. LAY.prototype.each = function(fn){
  227. return lay.each.call(this, this, fn);
  228. };
  229. //添加css类
  230. LAY.prototype.addClass = function(className, type){
  231. return this.each(function(index, item){
  232. item.className = LAY[type ? 'removeStr' : 'addStr'](item.className, className)
  233. });
  234. };
  235. //移除 css 类
  236. LAY.prototype.removeClass = function(className){
  237. return this.addClass(className, true);
  238. };
  239. //是否包含 css 类
  240. LAY.prototype.hasClass = function(className){
  241. var has = false;
  242. this.each(function(index, item){
  243. if(new RegExp('\\b'+ className +'\\b').test(item.className)){
  244. has = true;
  245. }
  246. });
  247. return has;
  248. };
  249. //添加或获取 css style
  250. LAY.prototype.css = function(key, value){
  251. var that = this
  252. ,parseValue = function(v){
  253. return isNaN(v) ? v : (v +'px');
  254. };
  255. return (typeof key === 'string' && value === undefined) ? function(){
  256. if(that.length > 0) return that[0].style[key];
  257. }() : that.each(function(index, item){
  258. typeof key === 'object' ? lay.each(key, function(thisKey, thisValue){
  259. item.style[thisKey] = parseValue(thisValue);
  260. }) : item.style[key] = parseValue(value);
  261. });
  262. };
  263. //添加或获取宽度
  264. LAY.prototype.width = function(value){
  265. var that = this;
  266. return value === undefined ? function(){
  267. if(that.length > 0) return that[0].offsetWidth; //此处还需做兼容
  268. }() : that.each(function(index, item){
  269. that.css('width', value);
  270. });
  271. };
  272. //添加或获取高度
  273. LAY.prototype.height = function(value){
  274. var that = this;
  275. return value === undefined ? function(){
  276. if(that.length > 0) return that[0].offsetHeight; //此处还需做兼容
  277. }() : that.each(function(index, item){
  278. that.css('height', value);
  279. });
  280. };
  281. //添加或获取属性
  282. LAY.prototype.attr = function(key, value){
  283. var that = this;
  284. return value === undefined ? function(){
  285. if(that.length > 0) return that[0].getAttribute(key);
  286. }() : that.each(function(index, item){
  287. item.setAttribute(key, value);
  288. });
  289. };
  290. //移除属性
  291. LAY.prototype.removeAttr = function(key){
  292. return this.each(function(index, item){
  293. item.removeAttribute(key);
  294. });
  295. };
  296. //设置或获取 HTML 内容
  297. LAY.prototype.html = function(html){
  298. var that = this;
  299. return html === undefined ? function(){
  300. if(that.length > 0) return that[0].innerHTML;
  301. }() : this.each(function(index, item){
  302. item.innerHTML = html;
  303. });
  304. };
  305. //设置或获取值
  306. LAY.prototype.val = function(value){
  307. var that = this;
  308. return value === undefined ? function(){
  309. if(that.length > 0) return that[0].value;
  310. }() : this.each(function(index, item){
  311. item.value = value;
  312. });
  313. };
  314. //追加内容
  315. LAY.prototype.append = function(elem){
  316. return this.each(function(index, item){
  317. typeof elem === 'object'
  318. ? item.appendChild(elem)
  319. : item.innerHTML = item.innerHTML + elem;
  320. });
  321. };
  322. //移除内容
  323. LAY.prototype.remove = function(elem){
  324. return this.each(function(index, item){
  325. elem ? item.removeChild(elem) : item.parentNode.removeChild(item);
  326. });
  327. };
  328. //事件绑定
  329. LAY.prototype.on = function(eventName, fn){
  330. return this.each(function(index, item){
  331. item.attachEvent ? item.attachEvent('on' + eventName, function(e){
  332. e.target = e.srcElement;
  333. fn.call(item, e);
  334. }) : item.addEventListener(eventName, fn, false);
  335. });
  336. };
  337. //解除事件
  338. LAY.prototype.off = function(eventName, fn){
  339. return this.each(function(index, item){
  340. item.detachEvent
  341. ? item.detachEvent('on'+ eventName, fn)
  342. : item.removeEventListener(eventName, fn, false);
  343. });
  344. };
  345. //暴露 lay 到全局作用域
  346. window.lay = lay;
  347. //如果在 layui 体系中
  348. if(window.layui && layui.define){
  349. layui.define(function(exports){ //layui 加载
  350. exports(MOD_NAME, lay);
  351. });
  352. }
  353. }(window, window.document);