BootStrap实现树形目录组件代码详解

需求描述

产品添加页面,需要选择车型。在bootStrap的modal上弹出子modal来使用。

车型一共有4级目录。要使用目录树。

然后分活动和商品两种,需要能够通过不通参数来调用该组件。

车型品牌要使用字母导航。

技术实现

数据都是后端传json过来,我们ajax获取然后操作。

由于车型总数据有几万条以上,不可能一次性请求过来。这里我们使用异步的方式,每点击一次目录节点,加载它的下一级。

这里我们用两个参数来控制活动和商品的不同加载。_showPrice和opened

后端传过来的第一级数据是车型品牌,其中有首字母的字段。字母导航的初始化,就是把这个数据用firstWord属性来排序,然后忽略掉其他首字母相同的元素。

对于活动类型,需要返回所勾选的最低一级的数据。(勾选奥迪和奥迪A6,则只返回A6的意思),这里用了整整4层循环。不过它是根据是否有checked来遍历的,速度不慢。

 /**
 * Created by nuenfeng on 2016/5/23.
 * 车型选择组件
 * 参数:
 * showPrice 是否要输入价格(不输入价格的从品牌开始就有选项框,没有全选功能)
 * params 外部传入的对象
 * callback 回调函数
 */
 (function () {
 var uriCarBrand = global.url.carBrandList;
 //var uri = uriCarBrand.url;
 var opened = false; //当前页面是否打开过本组件
 var _callback; //回调函数
 var requestParams; //请求时要使用的参数
 var _showPrice; //是否要输入价格
 var lastShowPrice; //前一次打开状态
 var charNavArr; //字母导航数组
 function CarTree(showPrice, params, callback) {
 // 没打开过,初始化; 打开过,直接显示modal
 requestParams = params;
 _showPrice = showPrice;
 _callback = callback;
 if (!opened || lastShowPrice != showPrice) {
 this.init();
 opened = true;
 lastShowPrice = showPrice;
 } else {
 $('#zc-sub-modal').modal('show');
 }
 }
 CarTree.prototype.init = function () {
 msjcTools.addSubModal();
 //设置大模态框
 $('#zc-sub-modal').addClass("bs-example-modal-lg");
 $('#zc-sub-modal .modal-dialog').addClass("modal-lg");
 var str = '<form id="info-form" data-parsley-validate class="form-horizontal form-label-left">';
 str += '<ul id="resourceId" class="treeview-gray">'
 str += '<li id="cb_"><span>汽车品牌选择</span>';
 str += "</li>"
 str += '</ul>'
 str += '</form>';

 var objId = 'cb_0';
 var carBrandId = 0;
loadSubMenu(objId, carBrandId, 1); //1 表示第一次加载,用于加载成功后判断时候要初始化字母导航
 $('#zc-sub-modal-body').html(str);
 $('#zc-sub-modal').modal({
 keyboard: false,
 show: true
 });
 // 点击保存事件
 $('#zc-sub-modal .modal-footer .btn.btn-primary').unbind().bind("click", function () {
 save();
 });
 //$("#resourceId").find("input[type=checkbox]").unbind().bind("click",function(){
 // if($(this).is(':checked')==true){//选中 则其上层节点全部展开并选中
 // //上级选中
 // $(this).parents("li").each(function(){
 // $(this).find("input[type=checkbox]:first").attr("checked",true)
 // });
 // } else {
 // //下级取消选中
 // $(this).siblings("ul").find("input[type=checkbox]").each(function(){
 // $(this).removeAttr("checked");
 // });
 // }
 //});
 //隐藏子窗口后 保持父窗口的滚动
 $("#zc-sub-modal").on("hidden.bs.modal", function () {
 $('body').addClass('modal-open')
 });
 }
 CarTree.prototype.empty = function () {
 opened = false;
 console.log('empty me');
 }
 //加载子菜单
 var loadSubMenu = function (objId, carBrandId, times) {
 requestParams.brandId = carBrandId;
 executeAjax(global.url.carBrandList, requestParams, function (data) {
 // 给data风骚地排个序
 data.sort(keysrt("firstWord"));
 var menuHtml = "<ul>";
 for (var index in data) {
 var menu = data[index];
 menuHtml += '<li id="cb_' + menu.carBrandId + '" value="' + menu.carBrandId + '" brand="' + menu.brand + '">';
 // 带价格的树
 if (_showPrice) {
 // 最后一级,添加选项框
 if (menu.level > 3) {
 menuHtml += '<input type="checkbox" name="resourceIds" value="' + menu.carBrandId + '" />';
 }
 menuHtml += '<span>' + menu.name + '</span>';
 // 最后一级,添加输入框
 if (menu.level == 4) {
 menuHtml += '<input type="text" maxlength="">';
 }
 } else { // 不带价格的树
 menuHtml += '<input type="checkbox" name="resourceIds" value="' + menu.carBrandId + '" />';
 menuHtml += '<span>' + menu.name + '</span>';
 }
 menuHtml += "</li>";
 }
 menuHtml += "</ul>";
 $('#' + objId).append(menuHtml);
 $('#' + objId).attr('data-load', 'loaded');
 //汽车类型第一级加载完成后,初始化字符导航
 charNavArr = [];
 var fwdLast = ''; //上一次的首字母
 for (var i in data) {
 var cobjTemp = {};
 if (fwdLast != data[i].firstWord) {
 fwdLast = data[i].firstWord;
 cobjTemp.firstWord = fwdLast;
 cobjTemp.targetId = 'cb_'+data[i].carBrandId;
 charNavArr.push(cobjTemp);
 }
 }
 if (times == 1) {
 initCharNav();
 // 点击保存事件
 $('.charNavSaveBtn').unbind().bind("click", function () {
 save();
 });
 }
 });
 }
 // 此处是风骚的数组对象排序
 var keysrt = function (propertyName) {
 return function (object1, object2) {
 var value1 = object1[propertyName];
 var value2 = object2[propertyName];
 if (value2 < value1) {
 return 1;
 }
else if (value2 > value1) {
 return -;
 }
 else {
 return ;
 }
 }
 }
 // 保存事件
 var save = function(){
 // 确认后,执行回调函数
 if (_showPrice) {
 var res = getPriceResult();
 if (res.status) {
 _callback(res.data);
 } else {
 alert(res.error);
 return;
 }
 } else {
 _callback(getNopriceResult());
 }
 //返回数据,然后隐藏
 $('#zc-sub-modal').modal('hide');
 }
 // 设置字符导航初始化
 var initCharNav = function () {
 var charNavHtml = '<ul id="charNavBar" class="charNavBar pagination">';
 for (var i in charNavArr) {
 charNavHtml += '<li><a href="#'+charNavArr[i].targetId+'">'+charNavArr[i].firstWord+'</a></li>';
 }
 charNavHtml += '<li><a class="modalGoTop">↑</a></li>';
 charNavHtml += '<button type="button" class="btn btn-primary charNavSaveBtn">保存</button>';
 charNavHtml += '</ul>';
 $('#zc-sub-modal').append(charNavHtml);
 $('.modalGoTop').on('click', function(e){
 $('#zc-sub-modal').animate({scrollTop: }, );
 });
 }
 // 统计带价格的返回数据
 var getPriceResult = function () {
 var result = {
 status : true,
 data : [],
 error : ''
 };
 var liTemp;
 var objTemp;
 $('.treeview-gray input:checkbox:checked').each(function (i) {
 liTemp = $(this).parent('li');
 objTemp = {};
 objTemp.carBrandId = liTemp.attr('value');
 objTemp.brand = liTemp.attr('brand');
 objTemp.carBrandName = liTemp.find('span').text();
 objTemp.unitPrice = liTemp.find('input:text').val();
 // 如果价格没有输入,返回保存失败,并返回没有输入的carBrandName
 if(objTemp.unitPrice == '') {
 result.status = false;
 result.error = '请输入 ' + objTemp.carBrandName + ' 的价格!';
 return result;
 }
 result.data.push(objTemp);
 });
 return result;
 }
 // 统计不带价格的返回数据
 var getNopriceResult = function () {
 var result = [];
 var liTemp;
 var objTemp;
 var flag1;
 var flag2;
 var flag3;
 var flag4;
 var levelName;

 // 遍历4层
 $('#cb_').children().children('li').children('input:checkbox').each(function (i) {
 if ($(this).is(':checked')) {
 flag = true;
 } else {
 flag = false;
 }
 $(this).parent().children().children('li').children('input:checkbox').each(function (i) {
 if ($(this).is(':checked')) {
 flag = false;
 flag = true;
 } else {
 flag = false;
 }
 // 获取第二级的名字,给第三级使用
 liTemp = $(this).parent('li');
 level2Name = liTemp.children('span').text();
 $(this).parent().children().children('li').children('input:checkbox').each(function (i3) {
 if ($(this).is(':checked')) {
 flag1 = false;
 flag2 = false;
 flag3 = true;
 } else {
 flag3 = false;
 }
 $(this).parent().children().children('li').children('input:checkbox').each(function (i4) {
 if ($(this).is(':checked')) {
 flag1 = false;
 flag2 = false;
 flag3 = false;
 flag4 = true;
 } else {
 flag4 = false;
 }
 if (flag4) {
 liTemp = $(this).parent('li');
 objTemp = {};
 objTemp.carBrandId = liTemp.attr('value');
 objTemp.brand = liTemp.attr('brand');
 //objTemp.carBrandName = liTemp.children('span').text();
 objTemp.carBrandName = objTemp.brand + ' ' + liTemp.children('span').text();
 result.push(objTemp);
 }
 });
 if (flag) {
 liTemp = $(this).parent('li');
 objTemp = {};
 objTemp.carBrandId = liTemp.attr('value');
 objTemp.brand = liTemp.attr('brand');
 //objTemp.carBrandName = liTemp.children('span').text();
 objTemp.carBrandName = objTemp.brand + ' ' + levelName + ' ' + liTemp.children('span').text();
 result.push(objTemp);
 }
 });
if (flag2) {
 //liTemp = $(this).parent('li');
 objTemp = {};
 objTemp.carBrandId = liTemp.attr('value');
 objTemp.brand = liTemp.attr('brand');
 //objTemp.carBrandName = objTemp.brand + liTemp.children('span').text();
 objTemp.carBrandName = objTemp.brand + ' ' + liTemp.children('span').text();
 result.push(objTemp);
 }
 });
 if (flag1) {
 liTemp = $(this).parent('li');
 objTemp = {};
 objTemp.carBrandId = liTemp.attr('value');
 objTemp.brand = liTemp.attr('brand');
 objTemp.carBrandName = liTemp.children('span').text();
 result.push(objTemp);
 }
 });
 return result;
 }
 // 给目录树绑定点击事件
 $(document).on('click', '#resourceId li', function (e) {
 e.stopPropagation();
 if ($(this).attr('open')) {
 $(this).removeAttr('open');
 $(this).children('ul').hide();
 } else {
 $(this).attr('open', 'opened');
 $(this).children('ul').show();
 }
 var objId = $(this).attr('id');
 var carBrandId = $(this).attr('value');
 //加载过的不执行
 if ($(this).attr('data-load')) {
 return;
 }
 loadSubMenu(objId, carBrandId);
 });
 // 点击多选框时候不下拉
 $(document).on('click', 'input[type="checkbox"]', function (e) {
 e.stopPropagation();
 });
 window.CarTree = CarTree;
 }()); 

调用方法:

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

以上所述是小编给大家介绍的BootStrap实现树形目录组件代码详解的相关知识,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Bootstrap布局组件教程之Bootstrap下拉菜单

    本章将重点介绍 Bootstrap 下拉菜单.下拉菜单是可切换的,是以列表格式显示链接的上下文菜单.这可以通过与 下拉菜单(Dropdown) JavaScript 插件 的互动来实现. 如需使用下列菜单,只需要在 class .dropdown 内加上下拉菜单即可.下面的实例演示了基本的下拉菜单: <!DOCTYPE html> <html> <head> <title>Bootstrap 实例 - 下拉菜单(Dropdowns)</title>

  • Bootstrap Fileinput文件上传组件用法详解

    最近时间空余,总结了一些关于bootstrap fileinput组件的一些常见用法,特此分享到我们平台,供大家参考,同时也方便以后的查找.本文写的不好还请见谅. 一.效果展示 1.原始的input type='file',简直不忍直视. 2.不做任何装饰的bootstrap fileinput:(bootstrap fileinput初级进化) 3.bootstrap fileinput高级进化:中文化.可拖拽上传.文件扩展名校验(如果不是需要的文件,不让上传) 拖拽上传 上传中 4.boot

  • JS组件系列之Bootstrap table表格组件神器【终结篇】

    bootstrap table系列: JS表格组件神器bootstrap table详解(基础版) JS组件系列之Bootstrap table表格组件神器[终结篇] JS组件系列之Bootstrap table表格组件神器[二.父子表和行列调序] Bootstrap Table是轻量级的和功能丰富的以表格的形式显示的数据,支持单选,复选框,排序,分页,显示/隐藏列,固定标题滚动表,响应式设计,Ajax加载JSON数据,点击排序的列,卡片视图等.那么本文给大家介绍JS组件系列之Bootstrap

  • BootStrap 智能表单实战系列(十)自动完成组件的支持

    web开发中,肯定遇到像百度.google这种搜索的功能吧,那智能表单中的自动完成可以做什么呢,下面来揭晓: 1.包含像google.百度等类似的简单搜索 2.复杂结构的支持,比如说 输入产品编号,需要将产品的编号.产品的名称.产品的单价.产品的备注信息等填写会表单中的某个位置 代码如下(页面地址:https://github.com/xiexingen/Bootstrap-SmartForm/blob/master/demo/form3-ele-autocomplete.html): 自动完成

  • JS组件系列之Bootstrap table表格组件神器【二、父子表和行列调序】

    Bootstrap Table是轻量级的和功能丰富的以表格的形式显示的数据,支持单选,复选框,排序,分页,显示/隐藏列,固定标题滚动表,响应式设计,Ajax加载JSON数据,点击排序的列,卡片视图等.今天就结合Bootstrap table的父子表和行列调序的用法再来介绍下它稍微高级点的用法. bootstrap table系列: JS表格组件神器bootstrap table详解(基础版) JS组件系列之Bootstrap table表格组件神器[终结篇] JS组件系列之Bootstrap t

  • Bootstrap组件(一)之菜单

    Glyphicons字体图标 基类.glyphicon {position/top/display/font-family/} 具体类 {content} --表现在伪元素上 使用要点:a.基类+具体类 b.一般图标和文本之间添加一个空格 注意点:a.不要和其他组件混用,单独使用一个标签,一般使用span,e.g.:<span class="glyphicon glyphicon-search"></span> b.已使用字体图标类的标签不要再嵌套元素或包含文本

  • Bootstrap 组件之按钮(二)

    Bootstrap是Twitter推出的一个用于前端开发的开源工具包.它由Twitter的设计师Mark Otto和Jacob Thornton合作开发,是一个CSS/HTML框架. 按钮组 .btn-group>.btn : 一组.btn按钮包裹在.btn-group 外包元素.btn-group {position/display/} 按钮元素.btn <div class="btn-group" role="group"> <butto

  • Bootstrap按钮下拉菜单组件详解

    按钮组也是一个独立的组件,按钮组和下拉菜单组件一样,需要依赖于button.js插件才能正常运作. 把一组<div class="btn-group">组合进一个<div class="btn-toolbar">做成更复杂的组件. <div class="btn-toolbar" role="toolbar"> <div class="btn-group">

  • Bootstrap组件系列之福利篇几款好用的组件(推荐)

    前言:之前分享过很多bootstrap常用组件,包括表格.表单验证.文件上传.复选下拉框.弹出框等.这段时间,博主又收藏了一些好用的组件(有些在项目中已经用起来了),经过两天的时间,已经整理出了一部分,本着"好东西要与人分享"的原则,今天还是来点福利,将博主收藏的东西分享出来,供需要的园友参考.组件大部分都是些开源组件,也有部分是博主自己在网上找到然后改写出来的效果,可能不尽如人意,有兴趣的且看看吧. 一.时间组件 bootstrap风格的时间组件非常多,你可以在github上面随便搜

  • BootStrap实现树形目录组件代码详解

    需求描述 产品添加页面,需要选择车型.在bootStrap的modal上弹出子modal来使用. 车型一共有4级目录.要使用目录树. 然后分活动和商品两种,需要能够通过不通参数来调用该组件. 车型品牌要使用字母导航. 技术实现 数据都是后端传json过来,我们ajax获取然后操作. 由于车型总数据有几万条以上,不可能一次性请求过来.这里我们使用异步的方式,每点击一次目录节点,加载它的下一级. 这里我们用两个参数来控制活动和商品的不同加载._showPrice和opened 后端传过来的第一级数据

  • 第七篇Bootstrap表单布局实例代码详解(三种表单布局)

    Bootstrap提供了三种表单布局:垂直表单,内联表单和水平表单.下面逐一给大家介绍,有兴趣的朋友一起学习吧. 创建垂直或基本表单: •·向父 <form> 元素添加 role="form". •·把标签和控件放在一个带有 class .form-group 的 <div> 中.这是获取最佳间距所必需的. •·向所有的文本元素 <input>.<textarea> 和 <select> 添加 class .form-cont

  • Bootstrap 按钮样式与使用代码详解

    1. 可用于<a>, <button>, 或 <input> 元素的按钮样式 按钮样式使用: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>My Test bootstrap</title> &l

  • bootstrap confirmation按钮提示组件使用详解

    bootstrap-confirmation按钮提示组件,它类似于js里面confirm的功能,界面更加美观. 介绍这个组件之前,可以先来看看bootstrap里面提示框的效果: 1.源码地址 http://ethaizone.github.io/Bootstrap-Confirmation/ 2.效果展示 3.代码示例 所需引入的js和css <link href="css/bootstrap.css" rel="external nofollow" rel

  • Vue开发Sort组件代码详解

    目录 <template> <ul class="container"> <li v-for="(item,index) in datalist" :key="index"> {{item.text}}<span></span> </li> </ul> </template> <script> export default{ props:{

  • Bootstrap进度条组件知识详解

    在网页中,经常见到进度条效果,如:平分系统.加载状态等,进度条组件使用了css3的transition和animation属性来完成一些特效,这些特效在IE9及IE9以下版本.Firefox的老版本中并不支持,Opera 12 不支持 animation 属性. 进度条和其他独立组件一样,开发者可以根据自己的需要选择对应的版本: LESS: progress-bars.less SASS: _progress-bars.scss 基础进度条 实现原理: 需要两个容器,外容器使用类名.progre

  • Vue.js子组件向父组件通信的方法实例代码详解

    一.场景描述: 曾经有个电商项目,其中有个"老带新"模块,而且该模块新增的入口很多,但是新增后展示效果还不一样,当时就考虑将新增的组件单独拿出来,其实就是一个子组件向父组同步数据的过程. 当然,背景不重要了,关键是看实现的方式. 二.场景展示效果 (PS:展示效果请忽略美感) 三.如何实现 注意:Vuejs架构通过vue-cli 3.X搭建的项目,版本无所谓. 1.先看下目录体系,下图子组件放在components文件夹内,模拟子组件为itemAdd.vue,父组件视图放在views文

  • OpenDataV低代码平台新增组件流程详解

    目录 正文 创建组件目录和文件 初始化组件文件 组件配置项 样式配置 属性配置 属性使用 总结 正文 OpenDataV计划采用子库的方式添加子组件,即每一个组件都当做一个子库,子库有自己的依赖,而项目本身的依赖只针对框架,因此每一个组件我们都当做一个子库来开发.下面我带着大家一步步详细的开发一个数字展示组件. 创建组件目录和文件 进入组件库目录下 所有的可拖拽组件都存放在src/resource/components目录下 cd src/resource/components 根据组件名称创建

  • Spring组件自动扫描详解及实例代码

    Spring组件自动扫描详解及实例代码 问题描述 一个系统往往有成千上万的组件,如果需要手动将所有组件都纳入spring容器中管理,是一个浩大的工程. 解决方案 Spring 提供组件扫描(component scanning)功能.它能从classpath里自动扫描.侦测和实例化具有特定注解的组件.基本的注解是@Component,它标识一个受Spring管理的组件.其他特定的注解有@Repository.@Service和@Controller,它们分别标识了持久层.服务处和表现层的组件.

随机推荐