element.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. /**
  2. @Name:layui.element 常用元素操作
  3. @Author:贤心
  4. @License:MIT
  5. */
  6. layui.define('jquery', function(exports){
  7. "use strict";
  8. var $ = layui.$
  9. ,hint = layui.hint()
  10. ,device = layui.device()
  11. ,MOD_NAME = 'element', THIS = 'layui-this', SHOW = 'layui-show'
  12. ,Element = function(){
  13. this.config = {};
  14. };
  15. //全局设置
  16. Element.prototype.set = function(options){
  17. var that = this;
  18. $.extend(true, that.config, options);
  19. return that;
  20. };
  21. //表单事件监听
  22. Element.prototype.on = function(events, callback){
  23. return layui.onevent.call(this, MOD_NAME, events, callback);
  24. };
  25. //外部Tab新增
  26. Element.prototype.tabAdd = function(filter, options){
  27. var TITLE = '.layui-tab-title'
  28. ,tabElem = $('.layui-tab[lay-filter='+ filter +']')
  29. ,titElem = tabElem.children(TITLE)
  30. ,barElem = titElem.children('.layui-tab-bar')
  31. ,contElem = tabElem.children('.layui-tab-content')
  32. ,li = '<li lay-id="'+ (options.id||'') +'"'
  33. +(options.attr ? ' lay-attr="'+ options.attr +'"' : '') +'>'+ (options.title||'unnaming') +'</li>';
  34. barElem[0] ? barElem.before(li) : titElem.append(li);
  35. contElem.append('<div class="layui-tab-item">'+ (options.content||'') +'</div>');
  36. call.hideTabMore(true);
  37. call.tabAuto();
  38. return this;
  39. };
  40. //外部Tab删除
  41. Element.prototype.tabDelete = function(filter, layid){
  42. var TITLE = '.layui-tab-title'
  43. ,tabElem = $('.layui-tab[lay-filter='+ filter +']')
  44. ,titElem = tabElem.children(TITLE)
  45. ,liElem = titElem.find('>li[lay-id="'+ layid +'"]');
  46. call.tabDelete(null, liElem);
  47. return this;
  48. };
  49. //外部Tab切换
  50. Element.prototype.tabChange = function(filter, layid){
  51. var TITLE = '.layui-tab-title'
  52. ,tabElem = $('.layui-tab[lay-filter='+ filter +']')
  53. ,titElem = tabElem.children(TITLE)
  54. ,liElem = titElem.find('>li[lay-id="'+ layid +'"]');
  55. call.tabClick.call(liElem[0], null, null, liElem);
  56. return this;
  57. };
  58. //自定义Tab选项卡
  59. Element.prototype.tab = function(options){
  60. options = options || {};
  61. dom.on('click', options.headerElem, function(e){
  62. var index = $(this).index();
  63. call.tabClick.call(this, e, index, null, options);
  64. });
  65. };
  66. //动态改变进度条
  67. Element.prototype.progress = function(filter, percent){
  68. var ELEM = 'layui-progress'
  69. ,elem = $('.'+ ELEM +'[lay-filter='+ filter +']')
  70. ,elemBar = elem.find('.'+ ELEM +'-bar')
  71. ,text = elemBar.find('.'+ ELEM +'-text');
  72. elemBar.css('width', percent);
  73. text.text(percent);
  74. return this;
  75. };
  76. var NAV_ELEM = '.layui-nav', NAV_ITEM = 'layui-nav-item', NAV_BAR = 'layui-nav-bar'
  77. ,NAV_TREE = 'layui-nav-tree', NAV_CHILD = 'layui-nav-child', NAV_MORE = 'layui-nav-more'
  78. ,NAV_ANIM = 'layui-anim layui-anim-upbit'
  79. //基础事件体
  80. ,call = {
  81. //Tab点击
  82. tabClick: function(e, index, liElem, options){
  83. options = options || {};
  84. var othis = liElem || $(this)
  85. ,index = index || othis.parent().children('li').index(othis)
  86. ,parents = options.headerElem ? othis.parent() : othis.parents('.layui-tab').eq(0)
  87. ,item = options.bodyElem ? $(options.bodyElem) : parents.children('.layui-tab-content').children('.layui-tab-item')
  88. ,elemA = othis.find('a')
  89. ,filter = parents.attr('lay-filter');
  90. if(!(elemA.attr('href') !== 'javascript:;' && elemA.attr('target') === '_blank')){
  91. othis.addClass(THIS).siblings().removeClass(THIS);
  92. item.eq(index).addClass(SHOW).siblings().removeClass(SHOW);
  93. }
  94. layui.event.call(this, MOD_NAME, 'tab('+ filter +')', {
  95. elem: parents
  96. ,index: index
  97. });
  98. }
  99. //Tab删除
  100. ,tabDelete: function(e, othis){
  101. var li = othis || $(this).parent(), index = li.index()
  102. ,parents = li.parents('.layui-tab').eq(0)
  103. ,item = parents.children('.layui-tab-content').children('.layui-tab-item')
  104. ,filter = parents.attr('lay-filter');
  105. if(li.hasClass(THIS)){
  106. if(li.next()[0]){
  107. call.tabClick.call(li.next()[0], null, index + 1);
  108. } else if(li.prev()[0]){
  109. call.tabClick.call(li.prev()[0], null, index - 1);
  110. }
  111. }
  112. li.remove();
  113. item.eq(index).remove();
  114. setTimeout(function(){
  115. call.tabAuto();
  116. }, 50);
  117. layui.event.call(this, MOD_NAME, 'tabDelete('+ filter +')', {
  118. elem: parents
  119. ,index: index
  120. });
  121. }
  122. //Tab自适应
  123. ,tabAuto: function(){
  124. var SCROLL = 'layui-tab-scroll', MORE = 'layui-tab-more', BAR = 'layui-tab-bar'
  125. ,CLOSE = 'layui-tab-close', that = this;
  126. $('.layui-tab').each(function(){
  127. var othis = $(this)
  128. ,title = othis.children('.layui-tab-title')
  129. ,item = othis.children('.layui-tab-content').children('.layui-tab-item')
  130. ,STOPE = 'lay-stope="tabmore"'
  131. ,span = $('<span class="layui-unselect layui-tab-bar" '+ STOPE +'><i '+ STOPE +' class="layui-icon">&#xe61a;</i></span>');
  132. if(that === window && device.ie != 8){
  133. call.hideTabMore(true)
  134. }
  135. //允许关闭
  136. if(othis.attr('lay-allowClose')){
  137. title.find('li').each(function(){
  138. var li = $(this);
  139. if(!li.find('.'+CLOSE)[0]){
  140. var close = $('<i class="layui-icon layui-unselect '+ CLOSE +'">&#x1006;</i>');
  141. close.on('click', call.tabDelete);
  142. li.append(close);
  143. }
  144. });
  145. }
  146. if(typeof othis.attr('lay-unauto') === 'string') return;
  147. //响应式
  148. if(title.prop('scrollWidth') > title.outerWidth()+1){
  149. if(title.find('.'+BAR)[0]) return;
  150. title.append(span);
  151. othis.attr('overflow', '');
  152. span.on('click', function(e){
  153. title[this.title ? 'removeClass' : 'addClass'](MORE);
  154. this.title = this.title ? '' : '收缩';
  155. });
  156. } else {
  157. title.find('.'+BAR).remove();
  158. othis.removeAttr('overflow');
  159. }
  160. });
  161. }
  162. //隐藏更多Tab
  163. ,hideTabMore: function(e){
  164. var tsbTitle = $('.layui-tab-title');
  165. if(e === true || $(e.target).attr('lay-stope') !== 'tabmore'){
  166. tsbTitle.removeClass('layui-tab-more');
  167. tsbTitle.find('.layui-tab-bar').attr('title','');
  168. }
  169. }
  170. //点击一级菜单
  171. /*
  172. ,clickThis: function(){
  173. var othis = $(this), parents = othis.parents(NAV_ELEM)
  174. ,filter = parents.attr('lay-filter')
  175. ,elemA = othis.find('a')
  176. ,unselect = typeof othis.attr('lay-unselect') === 'string';
  177. if(othis.find('.'+NAV_CHILD)[0]) return;
  178. if(!(elemA.attr('href') !== 'javascript:;' && elemA.attr('target') === '_blank') && !unselect){
  179. parents.find('.'+THIS).removeClass(THIS);
  180. othis.addClass(THIS);
  181. }
  182. layui.event.call(this, MOD_NAME, 'nav('+ filter +')', othis);
  183. }
  184. )
  185. */
  186. //点击菜单 - a标签触发
  187. ,clickThis: function(){
  188. var othis = $(this)
  189. ,parents = othis.parents(NAV_ELEM)
  190. ,filter = parents.attr('lay-filter')
  191. ,parent = othis.parent()
  192. ,child = othis.siblings('.'+NAV_CHILD)
  193. ,unselect = typeof parent.attr('lay-unselect') === 'string';
  194. if(!(othis.attr('href') !== 'javascript:;' && othis.attr('target') === '_blank') && !unselect){
  195. if(!child[0]){
  196. parents.find('.'+THIS).removeClass(THIS);
  197. parent.addClass(THIS);
  198. }
  199. }
  200. //如果是垂直菜单
  201. if(parents.hasClass(NAV_TREE)){
  202. child.removeClass(NAV_ANIM);
  203. //如果有子菜单,则展开
  204. if(child[0]){
  205. parent[child.css('display') === 'none' ? 'addClass': 'removeClass'](NAV_ITEM+'ed');
  206. if(parents.attr('lay-shrink') === 'all'){
  207. parent.siblings().removeClass(NAV_ITEM + 'ed');
  208. }
  209. }
  210. }
  211. layui.event.call(this, MOD_NAME, 'nav('+ filter +')', othis);
  212. }
  213. //点击子菜单选中
  214. /*
  215. ,clickChild: function(){
  216. var othis = $(this), parents = othis.parents(NAV_ELEM)
  217. ,filter = parents.attr('lay-filter');
  218. parents.find('.'+THIS).removeClass(THIS);
  219. othis.addClass(THIS);
  220. layui.event.call(this, MOD_NAME, 'nav('+ filter +')', othis);
  221. }
  222. */
  223. //折叠面板
  224. ,collapse: function(){
  225. var othis = $(this), icon = othis.find('.layui-colla-icon')
  226. ,elemCont = othis.siblings('.layui-colla-content')
  227. ,parents = othis.parents('.layui-collapse').eq(0)
  228. ,filter = parents.attr('lay-filter')
  229. ,isNone = elemCont.css('display') === 'none';
  230. //是否手风琴
  231. if(typeof parents.attr('lay-accordion') === 'string'){
  232. var show = parents.children('.layui-colla-item').children('.'+SHOW);
  233. show.siblings('.layui-colla-title').children('.layui-colla-icon').html('&#xe602;');
  234. show.removeClass(SHOW);
  235. }
  236. elemCont[isNone ? 'addClass' : 'removeClass'](SHOW);
  237. icon.html(isNone ? '&#xe61a;' : '&#xe602;');
  238. layui.event.call(this, MOD_NAME, 'collapse('+ filter +')', {
  239. title: othis
  240. ,content: elemCont
  241. ,show: isNone
  242. });
  243. }
  244. };
  245. //初始化元素操作
  246. Element.prototype.init = function(type, filter){
  247. var that = this, elemFilter = function(){
  248. return filter ? ('[lay-filter="' + filter +'"]') : '';
  249. }(), items = {
  250. //Tab选项卡
  251. tab: function(){
  252. call.tabAuto.call({});
  253. }
  254. //导航菜单
  255. ,nav: function(){
  256. var TIME = 200, timer = {}, timerMore = {}, timeEnd = {}, follow = function(bar, nav, index){
  257. var othis = $(this), child = othis.find('.'+NAV_CHILD);
  258. if(nav.hasClass(NAV_TREE)){
  259. bar.css({
  260. top: othis.position().top
  261. ,height: othis.children('a').outerHeight()
  262. ,opacity: 1
  263. });
  264. } else {
  265. child.addClass(NAV_ANIM);
  266. bar.css({
  267. left: othis.position().left + parseFloat(othis.css('marginLeft'))
  268. ,top: othis.position().top + othis.height() - bar.height()
  269. });
  270. timer[index] = setTimeout(function(){
  271. bar.css({
  272. width: othis.width()
  273. ,opacity: 1
  274. });
  275. }, device.ie && device.ie < 10 ? 0 : TIME);
  276. clearTimeout(timeEnd[index]);
  277. if(child.css('display') === 'block'){
  278. clearTimeout(timerMore[index]);
  279. }
  280. timerMore[index] = setTimeout(function(){
  281. child.addClass(SHOW)
  282. othis.find('.'+NAV_MORE).addClass(NAV_MORE+'d');
  283. }, 300);
  284. }
  285. }
  286. $(NAV_ELEM + elemFilter).each(function(index){
  287. var othis = $(this)
  288. ,bar = $('<span class="'+ NAV_BAR +'"></span>')
  289. ,itemElem = othis.find('.'+NAV_ITEM);
  290. //Hover滑动效果
  291. if(!othis.find('.'+NAV_BAR)[0]){
  292. othis.append(bar);
  293. itemElem.on('mouseenter', function(){
  294. follow.call(this, bar, othis, index);
  295. }).on('mouseleave', function(){
  296. if(!othis.hasClass(NAV_TREE)){
  297. clearTimeout(timerMore[index]);
  298. timerMore[index] = setTimeout(function(){
  299. othis.find('.'+NAV_CHILD).removeClass(SHOW);
  300. othis.find('.'+NAV_MORE).removeClass(NAV_MORE+'d');
  301. }, 300);
  302. }
  303. });
  304. othis.on('mouseleave', function(){
  305. clearTimeout(timer[index])
  306. timeEnd[index] = setTimeout(function(){
  307. if(othis.hasClass(NAV_TREE)){
  308. bar.css({
  309. height: 0
  310. ,top: bar.position().top + bar.height()/2
  311. ,opacity: 0
  312. });
  313. } else {
  314. bar.css({
  315. width: 0
  316. ,left: bar.position().left + bar.width()/2
  317. ,opacity: 0
  318. });
  319. }
  320. }, TIME);
  321. });
  322. }
  323. //展开子菜单
  324. itemElem.find('a').each(function(){
  325. var thisA = $(this)
  326. ,parent = thisA.parent()
  327. ,child = thisA.siblings('.'+NAV_CHILD);
  328. //输出小箭头
  329. if(child[0] && !thisA.children('.'+NAV_MORE)[0]){
  330. thisA.append('<span class="'+ NAV_MORE +'"></span>');
  331. }
  332. thisA.off('click', call.clickThis).on('click', call.clickThis); //点击菜单
  333. });
  334. });
  335. }
  336. //面包屑
  337. ,breadcrumb: function(){
  338. var ELEM = '.layui-breadcrumb';
  339. $(ELEM + elemFilter).each(function(){
  340. var othis = $(this)
  341. ,ATTE_SPR = 'lay-separator'
  342. ,separator = othis.attr(ATTE_SPR) || '/'
  343. ,aNode = othis.find('a');
  344. if(aNode.next('span['+ ATTE_SPR +']')[0]) return;
  345. aNode.each(function(index){
  346. if(index === aNode.length - 1) return;
  347. $(this).after('<span '+ ATTE_SPR +'>'+ separator +'</span>');
  348. });
  349. othis.css('visibility', 'visible');
  350. });
  351. }
  352. //进度条
  353. ,progress: function(){
  354. var ELEM = 'layui-progress';
  355. $('.' + ELEM + elemFilter).each(function(){
  356. var othis = $(this)
  357. ,elemBar = othis.find('.layui-progress-bar')
  358. ,percent = elemBar.attr('lay-percent');
  359. elemBar.css('width', function(){
  360. return /^.+\/.+$/.test(percent)
  361. ? (new Function('return '+ percent)() * 100) + '%'
  362. : percent;
  363. }());
  364. if(othis.attr('lay-showPercent')){
  365. setTimeout(function(){
  366. elemBar.html('<span class="'+ ELEM +'-text">'+ percent +'</span>');
  367. },350);
  368. }
  369. });
  370. }
  371. //折叠面板
  372. ,collapse: function(){
  373. var ELEM = 'layui-collapse';
  374. $('.' + ELEM + elemFilter).each(function(){
  375. var elemItem = $(this).find('.layui-colla-item')
  376. elemItem.each(function(){
  377. var othis = $(this)
  378. ,elemTitle = othis.find('.layui-colla-title')
  379. ,elemCont = othis.find('.layui-colla-content')
  380. ,isNone = elemCont.css('display') === 'none';
  381. //初始状态
  382. elemTitle.find('.layui-colla-icon').remove();
  383. elemTitle.append('<i class="layui-icon layui-colla-icon">'+ (isNone ? '&#xe602;' : '&#xe61a;') +'</i>');
  384. //点击标题
  385. elemTitle.off('click', call.collapse).on('click', call.collapse);
  386. });
  387. });
  388. }
  389. };
  390. return items[type] ? items[type]() : layui.each(items, function(index, item){
  391. item();
  392. });
  393. };
  394. Element.prototype.render = Element.prototype.init;
  395. var element = new Element(), dom = $(document);
  396. element.render();
  397. var TITLE = '.layui-tab-title li';
  398. dom.on('click', TITLE, call.tabClick); //Tab切换
  399. dom.on('click', call.hideTabMore); //隐藏展开的Tab
  400. $(window).on('resize', call.tabAuto); //自适应
  401. exports(MOD_NAME, element);
  402. });