thr-linkage-1.0.js.bak 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. /**
  2. * JQ多级联动通用插件
  3. * 初始化 $.linkAgeInit(options);
  4. * @param options
  5. * @version 1.0
  6. * @email 641453620@qq.com
  7. *
  8. * id,插件内部唯一Id
  9. * zIndex,层级,默认899
  10. * shade,遮罩,默认0.2。支持true,false,0~1
  11. * fadeTime,淡入淡出时间(毫秒)
  12. * dataModel,插件数据来源模式:http 通过url插件自动请求获取数据源,data 通过 “dataSource” 注入数据源
  13. * dataHttpUri,当 dataModel = http时,代表请求数据源的URL地址(使用GET请求方式)
  14. * dataHttpPidKeyName,当 dataModel = http时,请求 dataHttpUri 时携带当前选项Id的键值名称,默认 pid
  15. * dataHttpParams,当 dataModel = http时,需另外携带的请求参数
  16. * dataHttpResultHandle,当 dataModel = http时,请求数据成功后,将调用该方法进行数据二次处理,然后返回给插件使用
  17. * dataIndex, 联动数据层级,范围2~5,默认2
  18. * dataName,联动显示名称,默认:['一级' , '二级' , '三级']
  19. * dataSource,当 dataModel = data时,为数据源
  20. * dataOnePid,当 dataModel = data时,一级数据源Id,默认0
  21. * dataIdKey,数据源Id键值名,默认id
  22. * selectedValues,默认选中项,形式:[{id:442001001,name:'测试项1',route:id路径}],route可选
  23. * maxChecked,最大支持选中项数量,默认5
  24. * boxClickShow,选择后显示下一级列表,默认true。支持true,false
  25. * showHtml,Box主体模板
  26. * showListHtml,下拉框主体Box html
  27. * showSelectHtml,下拉选择行 html,模板可自定义。内置变量:{id},{name},{route}
  28. * showCheckHtml,单项选择 html,模板可自定义。内置变量:{id},{name},{route},{_on_}(高亮class)
  29. * showCheckedHtml,已选择项 html,模板可自定义。内置变量:{id},{name},{route}
  30. * showShadeHtml,遮罩 html
  31. * closeCallBack,关闭按钮回调方法,传入已选中的项
  32. * confirmCallBack,确认按钮回调方法,传入已选中的项
  33. * msgCallBack,提示信息处理方法,传入提示消息
  34. * @type {{id: number, zIndex: number, shade: boolean, fadeTime: number, dataModel: string, dataHttpUri: Array, dataHttpPidKeyName: string, dataHttpParams: {}, dataHttpResultHandle: (function(*): *), dataIndex: number, dataName: string[], dataSource: Array, dataOnePid: number, dataIdKey: string, selectedValues: Array, maxChecked: number, showHtml: string, showListHtml: string, showSelectHtml: string, showCheckHtml: string, showCheckedHtml: string, showShadeHtml: string, closeCallBack: string, confirmCallBack: string, msgCallBack: msgCallBack}}
  35. * @returns {*}
  36. */
  37. ;(function ($) {
  38. var instanceNums = 0;
  39. $.extend({
  40. linkAgeInit:function (options) {
  41. var defaults = {
  42. id:12138,
  43. zIndex:899,
  44. shade:0.2,
  45. fadeTime:600,
  46. boxTitle:'请选择地区',
  47. dataModel:'http',
  48. dataHttpUri:[],
  49. dataHttpPidKeyName:'pid',
  50. dataHttpParams:{},
  51. dataHttpResultHandle:function (res) {
  52. return res.data;
  53. },
  54. dataIndex:2,
  55. dataName:['一级' , '二级' , '三级'],
  56. dataSource:[],
  57. dataOnePid:0,
  58. dataIdKey:'id',
  59. inputkey:'inputkey';
  60. //已选择Id项
  61. selectedValues:[],
  62. maxChecked:1,
  63. boxClickShow:true,
  64. showHtml:' <div class="thr-linkage thr-box-{id}" style="z-index: {z_index};display:none;">\n' +
  65. ' <div class="thr-header">{boxTitle}\n' +
  66. ' <i class="thr-close thr-close-{id} fr lh30"></i>\n' +
  67. ' </div>\n' +
  68. ' <div class="thr-areas pd10">\n' +
  69. ' <h4 class="mtb5">您已选择<small class="fz12 fw">(最多可选择{maxChecked}个)</small><button class="fr thr-confirm">确定</button></h4>\n' +
  70. ' <dl class="fz14 thr-select-area">\n' +
  71. ' {selectedList}' +
  72. ' </dl>\n' +
  73. ' </div>\n' +
  74. '{selectList}' +
  75. ' <div class="thr-check-box fz14">\n' +
  76. ' <dl class="pd10">\n' +
  77. ' </dl>\n' +
  78. ' </div>\n' +
  79. ' </div>',
  80. showListHtml:'<div class="thr-list-area thr-list-{index} fz14 mt10 fl" data-index="{index}" {display}>\n' +
  81. ' <ul>\n' +
  82. ' <li class="fz16 thr-name">{name}</li>\n' +
  83. ' {volistItem}' +
  84. ' </ul>\n' +
  85. ' </div>',
  86. showSelectHtml:'<li data-id="{id}" data-route="{route}" class="">{name}</li>',
  87. showCheckHtml:'<dd data-id="{id}" data-route="{route}" class="{_on_}">{name}</dd>',
  88. showCheckedHtml:'<dd data-id="{id}" data-route="{route}" class="on">{name}</dd>',
  89. showShadeHtml:'<div class="thr-linkage-shade" style="display: block;background-color: rgba(0,0,0,{shadeNums});z-index: {z_index}"></div>',
  90. closeCallBack:'',
  91. confirmCallBack:'',
  92. msgCallBack:function (msg) {
  93. alert(msg);
  94. }
  95. };
  96. if (!options) options = {};
  97. //初始化配置
  98. options = $.extend(defaults, options);
  99. //唯一Id
  100. instanceNums++;
  101. options.id = options.id + instanceNums;
  102. if (options.dataIndex < 2) {
  103. console.log('Error : dataIndex 不能小于2!');
  104. return false;
  105. }
  106. try {
  107. //实例化
  108. return init(options);
  109. } catch (e) {
  110. console.log('Error : ' , e);
  111. return false;
  112. }
  113. },
  114. });
  115. //私有业务方法
  116. //实例化插件
  117. function init(options) {
  118. return {
  119. options:options,
  120. /**
  121. * 打开窗口
  122. * @param areaItem
  123. */
  124. open:function (areaItem) {
  125. var $this = this;
  126. var $thisSys = $this.options;
  127. //选择元素
  128. if (!areaItem) areaItem = 'body';
  129. //BoxId
  130. var thisBoxId = '.thr-box-'+$thisSys.id + ' ';
  131. //遮罩
  132. if ($thisSys.shade !== false) {
  133. var thisShadeTpl = $thisSys.showShadeHtml;
  134. var shadeNums = $thisSys.shade === true ? 0.2 : $thisSys.shade;
  135. thisShadeTpl = thisShadeTpl.replace(/{shadeNums}/g , shadeNums);
  136. thisShadeTpl = thisShadeTpl.replace(/{z_index}/g , $thisSys.zIndex-1);
  137. $(areaItem).append(thisShadeTpl);
  138. }
  139. //判断Box是否存在
  140. var thisStatus = $(".thr-box-" + $thisSys.id).css('display');
  141. if (thisStatus == 'none') {
  142. $(".thr-box-" + $thisSys.id).fadeIn($thisSys.fadeTime);
  143. //局部渲染
  144. if ($thisSys.selectedValues.constructor == Array && $thisSys.selectedValues.length > 0) {
  145. var thisSelectedIds = [];
  146. for (var i in $thisSys.selectedValues) {
  147. thisSelectedIds.push($thisSys.selectedValues[i].id);
  148. }
  149. $(thisBoxId + '.thr-select-area dd').each(function () {
  150. var $this = $(this);
  151. var $thisId = $(this).data('id');
  152. if (!in_array($thisId , thisSelectedIds)) {
  153. //丢弃选项
  154. $this.remove();
  155. //丢球选中
  156. $(thisBoxId + ".thr-check-box dd[data-id='"+$thisId+"']").removeClass('on');
  157. }
  158. })
  159. }
  160. return;
  161. }
  162. var thisHtml = $thisSys.showHtml;
  163. //替换
  164. thisHtml = thisHtml.replace(/{id}/g , $thisSys.id);
  165. thisHtml = thisHtml.replace(/{z_index}/g , $thisSys.zIndex);
  166. thisHtml = thisHtml.replace(/{boxTitle}/g , $thisSys.boxTitle);
  167. thisHtml = thisHtml.replace(/{maxChecked}/g , $thisSys.maxChecked);
  168. //遍历结构体
  169. thisHtml = thisHtml.replace(/{selectList}/g , loopSelectBoxInit($thisSys));
  170. //遍历已选择项
  171. if ($thisSys.selectedValues.constructor == Array) {
  172. var selectedHtml = '';
  173. for (var s in $thisSys.selectedValues) {
  174. var selectedTpl = $thisSys.showCheckedHtml;
  175. selectedTpl = selectedTpl.replace(/{id}/g , $thisSys.selectedValues[s].id);
  176. selectedTpl = selectedTpl.replace(/{name}/g , $thisSys.selectedValues[s].name);
  177. selectedTpl = selectedTpl.replace(/{route}/g , '');
  178. selectedHtml += selectedTpl;
  179. }
  180. thisHtml = thisHtml.replace(/{selectedList}/g , selectedHtml);
  181. } else {
  182. thisHtml = thisHtml.replace(/{selectedList}/g , '');
  183. }
  184. //输出
  185. $(areaItem).append(thisHtml);
  186. //显示
  187. $(thisBoxId).fadeIn($thisSys.fadeTime);
  188. //移除事件
  189. $('body').off('click' , thisBoxId + '.thr-list-area ul li');
  190. $('body').off('click' , thisBoxId + '.thr-check-box dl dd');
  191. $('body').off('click' , thisBoxId + '.thr-select-area dd');
  192. $('body').off('click' , thisBoxId + '.thr-confirm');
  193. $('body').off('click' , thisBoxId + '.thr-close-'+$thisSys.id);
  194. //绑定事件
  195. //下拉选择区点击
  196. $('body').on('click', thisBoxId + '.thr-list-area ul li:not(:first-child)' , function () {
  197. var $thisLi = $(this);
  198. var $index = $thisLi.parent().parent().data('index');
  199. var nextIndex = parseInt($index)+1;
  200. var $thisId = $thisLi.data('id');
  201. var $thisRoute = $thisLi.data('route');
  202. $thisLi.siblings().removeClass('on');
  203. $thisLi.addClass('on');
  204. if (nextIndex < $thisSys.dataIndex) {
  205. if ($thisSys.boxClickShow) {
  206. //显示
  207. $('.thr-box-'+$thisSys.id+' .thr-list-'+nextIndex).show();
  208. }
  209. var nextHtml = loopSelectBoxItem($thisId , $thisSys.showSelectHtml , nextIndex , $thisRoute , $thisSys);
  210. $('.thr-box-'+$thisSys.id+' .thr-list-'+nextIndex+' ul li.thr-name').nextUntil().remove();
  211. $('.thr-box-'+$thisSys.id+' .thr-list-'+nextIndex+' ul').append(nextHtml);
  212. return;
  213. }
  214. //最后一级
  215. var nextHtml = loopSelectBoxItem($thisId , $thisSys.showCheckHtml , nextIndex , $thisRoute , $thisSys);
  216. $('.thr-box-'+$thisSys.id+' .thr-check-box dl').html('').append(nextHtml);
  217. });
  218. //选择项事件
  219. $('body').on('click' , thisBoxId + '.thr-check-box dl dd' , function () {
  220. var $thisDd = $(this);
  221. var $thisId = $thisDd.data('id');
  222. var $thisRoute = $thisDd.data('route');
  223. var $thisName = $.trim($thisDd.text());
  224. if ($thisSys.selectedValues.constructor != Array) {
  225. $thisSys.selectedValues = [];
  226. }
  227. //验证已选择
  228. for (var s in $thisSys.selectedValues) {
  229. if ($thisId == $thisSys.selectedValues[s].id) {
  230. //删除操作
  231. $thisSys.selectedValues.splice(s , 1);
  232. $thisDd.removeClass('on');
  233. $(thisBoxId + ".thr-select-area dd[data-id='"+$thisId+"']").remove();
  234. return false;
  235. }
  236. }
  237. //验证最大选择数量
  238. if ($thisSys.selectedValues.length >= $thisSys.maxChecked) {
  239. if (typeof $thisSys.msgCallBack == 'function') {
  240. $thisSys.msgCallBack('您最多只可选择 '+$thisSys.maxChecked+' 个哦!');
  241. }
  242. return false;
  243. }
  244. //添加
  245. var thisTpl = $thisSys.showCheckedHtml;
  246. thisTpl = thisTpl.replace(/{id}/g , $thisId);
  247. thisTpl = thisTpl.replace(/{name}/g , $thisName);
  248. thisTpl = thisTpl.replace(/{route}/g , $thisRoute);
  249. $(thisBoxId + '.thr-select-area').append(thisTpl);
  250. $thisSys.selectedValues.push({id:$thisId,name:$thisName,route:$thisRoute});
  251. $thisDd.addClass('on');
  252. });
  253. //点击删除项
  254. $('body').on('click' , thisBoxId + '.thr-select-area dd' , function () {
  255. var $thisDd = $(this);
  256. var $thisId = $thisDd.data('id');
  257. if ($thisSys.selectedValues.constructor != Array) {
  258. $thisSys.selectedValues = [];
  259. return false;
  260. }
  261. //删除数据
  262. for (var s in $thisSys.selectedValues) {
  263. if ($thisId == $thisSys.selectedValues[s].id) {
  264. //删除
  265. $thisSys.selectedValues.splice(s , 1);
  266. }
  267. }
  268. $thisDd.remove();
  269. $(thisBoxId + ".thr-check-box dl dd[data-id='"+$thisId+"']").removeClass('on');
  270. });
  271. //确定事件
  272. $('body').on('click' , thisBoxId + '.thr-confirm' , function () {
  273. $(".thr-linkage-shade").remove();
  274. $(".thr-box-" + $thisSys.id).fadeOut($thisSys.fadeTime);
  275. //回调
  276. if (typeof $thisSys.confirmCallBack == 'function') {
  277. $thisSys.confirmCallBack($thisSys.selectedValues);
  278. }
  279. $.each($thisSys.selectedValues,function(i,file){
  280. $("#"+options.inputkey).val(file.name);
  281. });
  282. });
  283. //关闭
  284. $('body').on('click' , thisBoxId + '.thr-close-'+$thisSys.id , function () {
  285. $(".thr-linkage-shade").remove();
  286. $(".thr-box-" + $thisSys.id).fadeOut($thisSys.fadeTime , function () {
  287. $(this).remove();
  288. });
  289. //回调
  290. if (typeof $thisSys.closeCallBack == 'function') {
  291. $thisSys.closeCallBack($thisSys.selectedValues);
  292. }
  293. //清空已选数据
  294. $thisSys.selectedValues = [];
  295. });
  296. },
  297. /**
  298. * 注入已选数据,格式:[{id:1,name:名称,route:id路径}]
  299. * @param selected
  300. */
  301. set:function (selected) {
  302. var $this = this;
  303. if (selected && selected.constructor == Array) {
  304. $this.options.selectedValues = selected;
  305. return;
  306. }
  307. $this.options.selectedValues = [];
  308. }
  309. };
  310. }
  311. /**
  312. * 根据配置遍历单项下拉选择数据(初始化)
  313. * @param thisSys
  314. */
  315. function loopSelectBoxInit(thisSys) {
  316. var thisList = '';
  317. for (var i=0;i<(thisSys.dataIndex-1);i++) {
  318. var volistItem = '';
  319. var thisListHtml = thisSys.showListHtml;
  320. thisListHtml = thisListHtml.replace(/{index}/g , (i+1));
  321. thisListHtml = thisListHtml.replace(/{name}/g , thisSys.dataName[i]);
  322. //初始化
  323. if (i == 0) {
  324. thisListHtml = thisListHtml.replace(/{display}/g , '');
  325. volistItem = loopSelectBoxItem(thisSys.dataOnePid , thisSys.showSelectHtml , (i+1) , '' , thisSys);
  326. } else {
  327. thisListHtml = thisListHtml.replace(/{display}/g , thisSys.boxClickShow ? 'style="display:none;"' : '');
  328. volistItem = '';
  329. }
  330. thisListHtml = thisListHtml.replace(/{volistItem}/ , volistItem)
  331. thisList += thisListHtml;
  332. }
  333. return thisList;
  334. }
  335. function loopSelectBoxItem(thisPid , thisHtml , thisIndex , thisRoute , thisSys){
  336. var thisData = [];
  337. var thisSelectIdValue = [];
  338. if (thisSys.selectedValues.constructor == Array) {
  339. for (var s in thisSys.selectedValues) {
  340. thisSelectIdValue.push(thisSys.selectedValues[s].id);
  341. }
  342. }
  343. switch (thisSys.dataModel) {
  344. case 'http':
  345. if (thisSys.dataHttpUri.constructor == Array) {
  346. var thisUrl = thisSys.dataHttpUri[thisIndex-1];
  347. } else {
  348. var thisUrl = thisSys.dataHttpUri;
  349. }
  350. if (isNull(thisUrl)) {
  351. throw new Error('dataHttpUri Error : data error !');
  352. }
  353. //构造请求参数
  354. var requestData = {};
  355. requestData[thisSys.dataHttpPidKeyName] = thisPid;
  356. requestData = $.extend(requestData , thisSys.dataHttpParams);
  357. //请求
  358. $.ajax({
  359. async:false,
  360. type:'GET',
  361. url:thisUrl,
  362. data:requestData,
  363. error:function () {},
  364. success:function (res) {
  365. if (typeof thisSys.dataHttpResultHandle == 'function') {
  366. thisData = thisSys.dataHttpResultHandle(res);
  367. }
  368. }
  369. });
  370. break;
  371. case 'data':
  372. if (!(thisSys.dataSource).hasOwnProperty(thisPid)) {
  373. throw new Error('dataSource Error : '+thisPid+' Property does not exist !');
  374. }
  375. thisData = thisSys.dataSource[thisPid];
  376. break;
  377. default:
  378. throw new Error('dataModel Error !');
  379. }
  380. if (isNull(thisData)) return '';
  381. //遍历html
  382. var returnHtml = '';
  383. for (var i in thisData) {
  384. var thisForHtml = thisHtml;
  385. if (thisData[i].constructor == Object) {
  386. for (var j in thisData[i]) {
  387. var thisExp = new RegExp('{'+j+'}' , 'g');
  388. thisForHtml = thisForHtml.replace(thisExp , thisData[i][j]);
  389. //选项高亮
  390. if (!isNull(thisSelectIdValue) && thisIndex == thisSys.dataIndex && in_array(thisData[i][thisSys.dataIdKey] , thisSelectIdValue)) {
  391. thisForHtml = thisForHtml.replace(/{_on_}/ , 'on');
  392. } else {
  393. thisForHtml = thisForHtml.replace(/{_on_}/ , '');
  394. }
  395. //路由Id
  396. var thisRouteTxt = '';
  397. if (isNull(thisRoute)) {
  398. thisRouteTxt = thisData[i][thisSys.dataIdKey];
  399. } else {
  400. thisRouteTxt = thisRoute + '-' + thisData[i][thisSys.dataIdKey];
  401. }
  402. thisForHtml = thisForHtml.replace(/{route}/ , thisRouteTxt);
  403. }
  404. } else {
  405. throw new Error('dataSource Error : ' , thisData[i]);
  406. }
  407. returnHtml += thisForHtml;
  408. }
  409. //返回
  410. return returnHtml;
  411. }
  412. //公共方法
  413. /**
  414. * 检验数据是否为 null,undefined,""
  415. * @param string
  416. * @returns {boolean}
  417. */
  418. function isNull(string) {
  419. string = $.trim(string);
  420. if (string === 0) {
  421. return false;
  422. }
  423. if(string == "" || string == undefined || string == null || string == "undefined") {
  424. return true;
  425. }
  426. return false;
  427. }
  428. /**
  429. * 搜索某个值是否存在数组之内
  430. * @param needle 搜索的值
  431. * @param haystack 被搜索的数组
  432. * */
  433. function in_array(needle, haystack) {
  434. if (haystack.constructor != Array) {
  435. haystack = String(haystack).split(',');
  436. }
  437. var length = haystack.length;
  438. for(var i = 0; i < length; i++) {
  439. if(haystack[i] == needle) return true;
  440. }
  441. return false;
  442. }
  443. })(jQuery);