需求描述

产品添加页面,需要选择车型。在bootStrap的modal上弹出子modal来使用。
车型一共有4级目录。要使用目录树。
然后分活动和商品两种,需要能够通过不通参数来调用该组件。
车型品牌要使用字母导航。

技术实现

数据都是后端传json过来,我们ajax获取然后操作。
由于车型总数据有几万条以上,不可能一次性请求过来。这里我们使用异步的方式,每点击一次目录节点,加载它的下一级。
这里我们用两个参数来控制活动和商品的不同加载。_showPrice和opened
后端传过来的第一级数据是车型品牌,其中有首字母的字段。字母导航的初始化,就是把这个数据用firstWord属性来排序,然后忽略掉其他首字母相同的元素。
对于活动类型,需要返回所勾选的最低一级的数据。(勾选奥迪和奥迪A6,则只返回A6的意思),这里用了整整4层循环。不过它是根据是否有checked来遍历的,速度不慢。

  1. /**
  2. * Created by nuenfeng on 2016/5/23.
  3. * 车型选择组件
  4. * 参数:
  5. * showPrice 是否要输入价格(不输入价格的从品牌开始就有选项框,没有全选功能)
  6. * params 外部传入的对象
  7. * callback 回调函数
  8. */
  9. (function () {
  10. var uriCarBrand = global.url.carBrandList;
  11. //var uri = uriCarBrand.url;
  12. var opened = false; //当前页面是否打开过本组件
  13. var _callback; //回调函数
  14. var requestParams; //请求时要使用的参数
  15. var _showPrice; //是否要输入价格
  16. var lastShowPrice; //前一次打开状态
  17. var charNavArr; //字母导航数组
  18.  
  19. function CarTree(showPrice, params, callback) {
  20. // 没打开过,初始化; 打开过,直接显示modal
  21. requestParams = params;
  22. _showPrice = showPrice;
  23. _callback = callback;
  24.  
  25. if (!opened || lastShowPrice != showPrice) {
  26. this.init();
  27. opened = true;
  28. lastShowPrice = showPrice;
  29. } else {
  30. $('#zc-sub-modal').modal('show');
  31. }
  32. }
  33.  
  34. CarTree.prototype.init = function () {
  35.  
  36. msjcTools.addSubModal();
  37. //设置大模态框
  38. $('#zc-sub-modal').addClass("bs-example-modal-lg");
  39. $('#zc-sub-modal .modal-dialog').addClass("modal-lg");
  40.  
  41. var str = '<form id="info-form" data-parsley-validate class="form-horizontal form-label-left">';
  42. str += '<ul id="resourceId" class="treeview-gray">'
  43. str += '<li id="cb_0"><span>汽车品牌选择</span>';
  44. str += "</li>"
  45. str += '</ul>'
  46. str += '</form>';
  47.  
  48. var objId = 'cb_0';
  49. var carBrandId = 0;
  50. loadSubMenu(objId, carBrandId, 1); //1 表示第一次加载,用于加载成功后判断时候要初始化字母导航
  51.  
  52. $('#zc-sub-modal-body').html(str);
  53. $('#zc-sub-modal').modal({
  54. keyboard: false,
  55. show: true
  56. });
  57.  
  58. // 点击保存事件
  59. $('#zc-sub-modal .modal-footer .btn.btn-primary').unbind().bind("click", function () {
  60. save();
  61. });
  62.  
  63. //$("#resourceId").find("input[type=checkbox]").unbind().bind("click",function(){
  64. // if($(this).is(':checked')==true){//选中 则其上层节点全部展开并选中
  65. // //上级选中
  66. // $(this).parents("li").each(function(){
  67. // $(this).find("input[type=checkbox]:first").attr("checked",true)
  68. // });
  69. // } else {
  70. // //下级取消选中
  71. // $(this).siblings("ul").find("input[type=checkbox]").each(function(){
  72. // $(this).removeAttr("checked");
  73. // });
  74. // }
  75. //});
  76.  
  77. //隐藏子窗口后 保持父窗口的滚动
  78. $("#zc-sub-modal").on("hidden.bs.modal", function () {
  79. $('body').addClass('modal-open')
  80. });
  81. }
  82.  
  83. CarTree.prototype.empty = function () {
  84. opened = false;
  85. console.log('empty me');
  86. }
  87.  
  88. //加载子菜单
  89. var loadSubMenu = function (objId, carBrandId, times) {
  90.  
  91. requestParams.brandId = carBrandId;
  92. executeAjax(global.url.carBrandList, requestParams, function (data) {
  93. // 给data风骚地排个序
  94. data.sort(keysrt("firstWord"));
  95.  
  96. var menuHtml = "<ul>";
  97. for (var index in data) {
  98. var menu = data[index];
  99. menuHtml += '<li id="cb_' + menu.carBrandId + '" value="' + menu.carBrandId + '" brand="' + menu.brand + '">';
  100.  
  101. // 带价格的树
  102. if (_showPrice) {
  103. // 最后一级,添加选项框
  104. if (menu.level > 3) {
  105. menuHtml += '<input type="checkbox" name="resourceIds" value="' + menu.carBrandId + '" />';
  106. }
  107. menuHtml += '<span>' + menu.name + '</span>';
  108.  
  109. // 最后一级,添加输入框
  110. if (menu.level == 4) {
  111. menuHtml += '<input type="text" maxlength="9">';
  112. }
  113. } else { // 不带价格的树
  114. menuHtml += '<input type="checkbox" name="resourceIds" value="' + menu.carBrandId + '" />';
  115. menuHtml += '<span>' + menu.name + '</span>';
  116. }
  117.  
  118. menuHtml += "</li>";
  119. }
  120. menuHtml += "</ul>";
  121. $('#' + objId).append(menuHtml);
  122. $('#' + objId).attr('data-load', 'loaded');
  123.  
  124. //汽车类型第一级加载完成后,初始化字符导航
  125. charNavArr = [];
  126. var fwdLast = ''; //上一次的首字母
  127.  
  128. for (var i in data) {
  129. var cobjTemp = {};
  130. if (fwdLast != data[i].firstWord) {
  131. fwdLast = data[i].firstWord;
  132. cobjTemp.firstWord = fwdLast;
  133. cobjTemp.targetId = 'cb_'+data[i].carBrandId;
  134. charNavArr.push(cobjTemp);
  135. }
  136. }
  137. if (times == 1) {
  138. initCharNav();
  139. // 点击保存事件
  140. $('.charNavSaveBtn').unbind().bind("click", function () {
  141. save();
  142. });
  143. }
  144. });
  145.  
  146. }
  147.  
  148. // 此处是风骚的数组对象排序
  149. var keysrt = function (propertyName) {
  150. return function (object1, object2) {
  151. var value1 = object1[propertyName];
  152. var value2 = object2[propertyName];
  153. if (value2 < value1) {
  154. return 1;
  155. }
  156. else if (value2 > value1) {
  157. return -1;
  158. }
  159. else {
  160. return 0;
  161. }
  162. }
  163. }
  164.  
  165. // 保存事件
  166. var save = function(){
  167. // 确认后,执行回调函数
  168. if (_showPrice) {
  169. var res = getPriceResult();
  170. if (res.status) {
  171. _callback(res.data);
  172. } else {
  173. alert(res.error);
  174. return;
  175. }
  176. } else {
  177. _callback(getNopriceResult());
  178. }
  179. //返回数据,然后隐藏
  180. $('#zc-sub-modal').modal('hide');
  181. }
  182.  
  183. // 设置字符导航初始化
  184. var initCharNav = function () {
  185. var charNavHtml = '<ul id="charNavBar" class="charNavBar pagination">';
  186. for (var i in charNavArr) {
  187. charNavHtml += '<li><a href="#'+charNavArr[i].targetId+'">'+charNavArr[i].firstWord+'</a></li>';
  188. }
  189. charNavHtml += '<li><a class="modalGoTop">↑</a></li>';
  190. charNavHtml += '<button type="button" class="btn btn-primary charNavSaveBtn">保存</button>';
  191. charNavHtml += '</ul>';
  192.  
  193. $('#zc-sub-modal').append(charNavHtml);
  194.  
  195. $('.modalGoTop').on('click', function(e){
  196. $('#zc-sub-modal').animate({scrollTop: 0}, 500);
  197. });
  198. }
  199.  
  200. // 统计带价格的返回数据
  201. var getPriceResult = function () {
  202. var result = {
  203. status : true,
  204. data : [],
  205. error : ''
  206. };
  207. var liTemp;
  208. var objTemp;
  209. $('.treeview-gray input:checkbox:checked').each(function (i) {
  210. liTemp = $(this).parent('li');
  211. objTemp = {};
  212. objTemp.carBrandId = liTemp.attr('value');
  213. objTemp.brand = liTemp.attr('brand');
  214. objTemp.carBrandName = liTemp.find('span').text();
  215. objTemp.unitPrice = liTemp.find('input:text').val();
  216.  
  217. // 如果价格没有输入,返回保存失败,并返回没有输入的carBrandName
  218. if(objTemp.unitPrice == '') {
  219. result.status = false;
  220. result.error = '请输入 ' + objTemp.carBrandName + ' 的价格!';
  221. return result;
  222. }
  223. result.data.push(objTemp);
  224. });
  225. return result;
  226. }
  227.  
  228. // 统计不带价格的返回数据
  229. var getNopriceResult = function () {
  230. var result = [];
  231. var liTemp;
  232. var objTemp;
  233. var flag1;
  234. var flag2;
  235. var flag3;
  236. var flag4;
  237. var level2Name;
  238.  
  239. // 遍历4层
  240. $('#cb_0').children().children('li').children('input:checkbox').each(function (i1) {
  241. if ($(this).is(':checked')) {
  242. flag1 = true;
  243. } else {
  244. flag1 = false;
  245. }
  246. $(this).parent().children().children('li').children('input:checkbox').each(function (i2) {
  247. if ($(this).is(':checked')) {
  248. flag1 = false;
  249. flag2 = true;
  250. } else {
  251. flag2 = false;
  252. }
  253. // 获取第二级的名字,给第三级使用
  254. liTemp = $(this).parent('li');
  255. level2Name = liTemp.children('span').text();
  256. $(this).parent().children().children('li').children('input:checkbox').each(function (i3) {
  257. if ($(this).is(':checked')) {
  258. flag1 = false;
  259. flag2 = false;
  260. flag3 = true;
  261. } else {
  262. flag3 = false;
  263. }
  264. $(this).parent().children().children('li').children('input:checkbox').each(function (i4) {
  265. if ($(this).is(':checked')) {
  266. flag1 = false;
  267. flag2 = false;
  268. flag3 = false;
  269. flag4 = true;
  270. } else {
  271. flag4 = false;
  272. }
  273. if (flag4) {
  274. liTemp = $(this).parent('li');
  275. objTemp = {};
  276. objTemp.carBrandId = liTemp.attr('value');
  277. objTemp.brand = liTemp.attr('brand');
  278. //objTemp.carBrandName = liTemp.children('span').text();
  279. objTemp.carBrandName = objTemp.brand + ' ' + liTemp.children('span').text();
  280. result.push(objTemp);
  281. }
  282. });
  283. if (flag3) {
  284. liTemp = $(this).parent('li');
  285. objTemp = {};
  286. objTemp.carBrandId = liTemp.attr('value');
  287. objTemp.brand = liTemp.attr('brand');
  288. //objTemp.carBrandName = liTemp.children('span').text();
  289. objTemp.carBrandName = objTemp.brand + ' ' + level2Name + ' ' + liTemp.children('span').text();
  290. result.push(objTemp);
  291. }
  292. });
  293. if (flag2) {
  294. //liTemp = $(this).parent('li');
  295. objTemp = {};
  296. objTemp.carBrandId = liTemp.attr('value');
  297. objTemp.brand = liTemp.attr('brand');
  298. //objTemp.carBrandName = objTemp.brand + liTemp.children('span').text();
  299. objTemp.carBrandName = objTemp.brand + ' ' + liTemp.children('span').text();
  300. result.push(objTemp);
  301. }
  302. });
  303. if (flag1) {
  304. liTemp = $(this).parent('li');
  305. objTemp = {};
  306. objTemp.carBrandId = liTemp.attr('value');
  307. objTemp.brand = liTemp.attr('brand');
  308. objTemp.carBrandName = liTemp.children('span').text();
  309. result.push(objTemp);
  310. }
  311. });
  312.  
  313. return result;
  314. }
  315.  
  316. // 给目录树绑定点击事件
  317. $(document).on('click', '#resourceId li', function (e) {
  318.  
  319. e.stopPropagation();
  320.  
  321. if ($(this).attr('open')) {
  322. $(this).removeAttr('open');
  323. $(this).children('ul').hide();
  324. } else {
  325. $(this).attr('open', 'opened');
  326. $(this).children('ul').show();
  327. }
  328. var objId = $(this).attr('id');
  329. var carBrandId = $(this).attr('value');
  330. //加载过的不执行
  331. if ($(this).attr('data-load')) {
  332. return;
  333. }
  334. loadSubMenu(objId, carBrandId);
  335. });
  336.  
  337. // 点击多选框时候不下拉
  338. $(document).on('click', 'input[type="checkbox"]', function (e) {
  339. e.stopPropagation();
  340. });
  341.  
  342. window.CarTree = CarTree;
  343. }());

调用方法:

  1. carTree = new CarTree(false, {}, function (data) {
  2. console.log(data);
  3. });

bootStrap树形目录组件的更多相关文章

  1. [moka同学收藏]Vim升华之树形目录插件NERDTree安装图解

    无意中看到实验室的朋友使用的vim竟然能在左边显示树形目录,感觉很方便,这样子文件夹有什么文件一目了然.她说是一个插件叫NERDTree,安装执行后的效果如下,不是你想要的效果就别安了.我的系统是Ub ...

  2. Vim升华之树形目录插件NERDTree安装图解

    来源:CSDN 作者:mybelief321 无意中看到实验室的朋友使用的vim竟然能在左边显示树形目录,感觉很方便,这样子文件夹有什么文件一目了然.他说是一个插件叫NERDTree,安装执行后的效果 ...

  3. 利用bootstrap的modal组件自定义alert,confirm和modal对话框

    由于浏览器提供的alert和confirm框体验不好,而且浏览器没有提供一个标准的以对话框的形式显示自定义HTML的弹框函数,所以很多项目都会自定义对话框组件.本篇文章介绍自己在项目中基于bootst ...

  4. vim 树形目录插件NERDTree安装及简单用法

    转自: http://blog.csdn.net/love__coder/article/details/6659103 1,安装NERDTree插件 先下载,官网:http://www.vim.or ...

  5. bootstrap轮播组件,大屏幕图片居中效果

    在慕课网学习bootstrap轮播组件的时候,了解到轮播的图片都放在了类名为item下的img中 视频中老师对图片自适应采用给图片img设置width=100%完成,然而这样自适应处理图片在不同屏幕中 ...

  6. bootstrap 之 列表组件使用

    列表是几乎所有网站都会用到的一个组件,正好bootstrap也给我们提供了这个组件的样式,下面我给大家简单介绍一下bootstrap中的列表组件的用法! 首先,重提一下引用bootstrap的核心文件 ...

  7. vim插件:显示树形目录插件NERDTree安装 和 使用

    下载和配置 NERDTree插件的官方地址如下,可以从这里获取最新的版本 https://github.com/scrooloose/nerdtree 下载zip安装包 或者使用下面官网源文件安装方法 ...

  8. JQuery树形目录插件Dynatree

    最近做网页需要做一个树形目录功能.找了一下发现有很多JQuery插件都可以实现这个功能.选了一个自己觉得最满意的插件Dynatree做个学习笔记. 可以把静态的html转成树形目录,还可以动态创建添加 ...

  9. bootstrap轮播组件之“如何关闭自动轮播”

    在一个页面里使用多个bootstrap轮播组件的时候,如果还让所有轮播图都自动轮播的话,整个画面都在动,会给用户一种很不好的体验感受.所以,需要关闭轮播图的自动轮播. 关闭方法:去除如下属性即可: d ...

随机推荐

  1. Wannafly Union Goodbye 2016

    A 题意:平面上有n个点(n<=100000),给你一个p(20<=p<=100) 判断是否存在一条直线至少过[np/100](向上取整)个点,时限20s,多组数据 分析:概率算法 ...

  2. MongoDB的备份和恢复

    1.导出数据库/备份: @echo off F: cd F:\software1\mongdb\mongodb-win32-x86_64-\bin start mongodump.exe -h -d ...

  3. 【WPF】 返回随机颜色,Random r= new Random() 不能放在函数里!

  4. logback 常用配置详解<appender>

    logback 常用配置详解 <appender> <appender>: <appender>是<configuration>的子节点,是负责写日志的 ...

  5. Laravel增删改查语句总结

    <?php Class Que { /* * 查询: */ public function index() { $users = User::query()->paginate(20); ...

  6. ios app 企业帐号发布,在浏览器中直接点击链接下载安装

    软件环境:Xcode 6.4 参考链接: 1.http://zxs19861202.iteye.com/blog/1997722 2.http://www.cnblogs.com/abl1992/p/ ...

  7. iOS推送流程

    1. 在apple开发者帐号上创建一个BundleID,创建证书或者Xcode上都是用这个BundleID(例如com.mycompany.pushDemo) 2. 代码层面: 在capability ...

  8. BZOJ 3931: [CQOI2015]网络吞吐量

    3931: [CQOI2015]网络吞吐量 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1555  Solved: 637[Submit][Stat ...

  9. Apriori算法的原理与python 实现。

    前言:这是一个老故事, 但每次看总是能从中想到点什么.在一家超市里,有一个有趣的现象:尿布和啤酒赫然摆在一起出售.但是这个奇怪的举措却使尿布和啤酒的销量双双增加了.这不是一个笑话,而是发生在美国沃尔玛 ...

  10. iBatis.net 类的继承extends和懒加载

    <resultMaps> <resultMap id="FullResultMap" class="t_c_team_member_permission ...