BootStrap實(shí)現(xiàn)樹形目錄組件代碼詳解
需求描述
產(chǎn)品添加頁(yè)面,需要選擇車型。在bootStrap的modal上彈出子modal來(lái)使用。
車型一共有4級(jí)目錄。要使用目錄樹。
然后分活動(dòng)和商品兩種,需要能夠通過(guò)不通參數(shù)來(lái)調(diào)用該組件。
車型品牌要使用字母導(dǎo)航。

技術(shù)實(shí)現(xiàn)
數(shù)據(jù)都是后端傳json過(guò)來(lái),我們ajax獲取然后操作。
由于車型總數(shù)據(jù)有幾萬(wàn)條以上,不可能一次性請(qǐng)求過(guò)來(lái)。這里我們使用異步的方式,每點(diǎn)擊一次目錄節(jié)點(diǎn),加載它的下一級(jí)。
這里我們用兩個(gè)參數(shù)來(lái)控制活動(dòng)和商品的不同加載。_showPrice和opened
后端傳過(guò)來(lái)的第一級(jí)數(shù)據(jù)是車型品牌,其中有首字母的字段。字母導(dǎo)航的初始化,就是把這個(gè)數(shù)據(jù)用firstWord屬性來(lái)排序,然后忽略掉其他首字母相同的元素。
對(duì)于活動(dòng)類型,需要返回所勾選的最低一級(jí)的數(shù)據(jù)。(勾選奧迪和奧迪A6,則只返回A6的意思),這里用了整整4層循環(huán)。不過(guò)它是根據(jù)是否有checked來(lái)遍歷的,速度不慢。
/**
* Created by nuenfeng on 2016/5/23.
* 車型選擇組件
* 參數(shù):
* showPrice 是否要輸入價(jià)格(不輸入價(jià)格的從品牌開始就有選項(xiàng)框,沒有全選功能)
* params 外部傳入的對(duì)象
* callback 回調(diào)函數(shù)
*/
(function () {
var uriCarBrand = global.url.carBrandList;
//var uri = uriCarBrand.url;
var opened = false; //當(dāng)前頁(yè)面是否打開過(guò)本組件
var _callback; //回調(diào)函數(shù)
var requestParams; //請(qǐng)求時(shí)要使用的參數(shù)
var _showPrice; //是否要輸入價(jià)格
var lastShowPrice; //前一次打開狀態(tài)
var charNavArr; //字母導(dǎo)航數(shù)組
function CarTree(showPrice, params, callback) {
// 沒打開過(guò),初始化; 打開過(guò),直接顯示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();
//設(shè)置大模態(tài)框
$('#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 表示第一次加載,用于加載成功后判斷時(shí)候要初始化字母導(dǎo)航
$('#zc-sub-modal-body').html(str);
$('#zc-sub-modal').modal({
keyboard: false,
show: true
});
// 點(diǎn)擊保存事件
$('#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){//選中 則其上層節(jié)點(diǎn)全部展開并選中
// //上級(jí)選中
// $(this).parents("li").each(function(){
// $(this).find("input[type=checkbox]:first").attr("checked",true)
// });
// } else {
// //下級(jí)取消選中
// $(this).siblings("ul").find("input[type=checkbox]").each(function(){
// $(this).removeAttr("checked");
// });
// }
//});
//隱藏子窗口后 保持父窗口的滾動(dòng)
$("#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風(fēng)騷地排個(gè)序
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 + '">';
// 帶價(jià)格的樹
if (_showPrice) {
// 最后一級(jí),添加選項(xiàng)框
if (menu.level > 3) {
menuHtml += '<input type="checkbox" name="resourceIds" value="' + menu.carBrandId + '" />';
}
menuHtml += '<span>' + menu.name + '</span>';
// 最后一級(jí),添加輸入框
if (menu.level == 4) {
menuHtml += '<input type="text" maxlength="">';
}
} else { // 不帶價(jià)格的樹
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');
//汽車類型第一級(jí)加載完成后,初始化字符導(dǎo)航
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();
// 點(diǎn)擊保存事件
$('.charNavSaveBtn').unbind().bind("click", function () {
save();
});
}
});
}
// 此處是風(fēng)騷的數(shù)組對(duì)象排序
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(){
// 確認(rèn)后,執(zhí)行回調(diào)函數(shù)
if (_showPrice) {
var res = getPriceResult();
if (res.status) {
_callback(res.data);
} else {
alert(res.error);
return;
}
} else {
_callback(getNopriceResult());
}
//返回?cái)?shù)據(jù),然后隱藏
$('#zc-sub-modal').modal('hide');
}
// 設(shè)置字符導(dǎo)航初始化
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: }, );
});
}
// 統(tǒng)計(jì)帶價(jià)格的返回?cái)?shù)據(jù)
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();
// 如果價(jià)格沒有輸入,返回保存失敗,并返回沒有輸入的carBrandName
if(objTemp.unitPrice == '') {
result.status = false;
result.error = '請(qǐng)輸入 ' + objTemp.carBrandName + ' 的價(jià)格!';
return result;
}
result.data.push(objTemp);
});
return result;
}
// 統(tǒng)計(jì)不帶價(jià)格的返回?cái)?shù)據(jù)
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;
}
// 獲取第二級(jí)的名字,給第三級(jí)使用
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;
}
// 給目錄樹綁定點(diǎn)擊事件
$(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');
//加載過(guò)的不執(zhí)行
if ($(this).attr('data-load')) {
return;
}
loadSubMenu(objId, carBrandId);
});
// 點(diǎn)擊多選框時(shí)候不下拉
$(document).on('click', 'input[type="checkbox"]', function (e) {
e.stopPropagation();
});
window.CarTree = CarTree;
}());
調(diào)用方法:
carTree = new CarTree(false, {}, function (data) {
console.log(data);
});
以上所述是小編給大家介紹的BootStrap實(shí)現(xiàn)樹形目錄組件代碼詳解的相關(guān)知識(shí),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
javascript模擬php函數(shù)in_array
就是判斷一個(gè)元素是否存在于數(shù)組中的函數(shù),既然js里string都有indexOf函數(shù),為什么不在Array對(duì)象里設(shè)置一個(gè)這樣的函數(shù)呢,其實(shí)就用indexOf這個(gè)思想挺好的,不知道制定JS標(biāo)準(zhǔn)的人是基于什么考慮,把這樣一個(gè)如此常用的功能沒考慮在內(nèi)的。2015-04-04
JavaScript判斷FileUpload控件上傳文件類型
在CS后臺(tái)代碼中獲取FileUpload控件上傳文件的類型是比較容易的!那么,能否在客戶端通過(guò)JavaScript腳本判斷FileUpload上傳文件類型呢?答案是可以的,下面通過(guò)一個(gè)小例子為大家展示2015-09-09
javascript打印大全(打印頁(yè)面設(shè)置/打印預(yù)覽代碼)
打印頁(yè)面設(shè)置,打印頁(yè)面預(yù)覽在打印過(guò)程中經(jīng)常會(huì)遇到,網(wǎng)上搜集整理了一些實(shí)用的打印方法與大家分享,感興趣的朋友可以了解下哈2013-03-03
快速解決bootstrap下拉菜單無(wú)法隱藏的問(wèn)題
今天小編就為大家分享一篇快速解決bootstrap下拉菜單無(wú)法隱藏的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
JS?簡(jiǎn)單實(shí)現(xiàn)拖拽評(píng)星的示例代碼
本文主要介紹了JS?簡(jiǎn)單實(shí)現(xiàn)拖拽評(píng)星,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
微信小程序?qū)W習(xí)總結(jié)(四)事件與冒泡實(shí)例分析
這篇文章主要介紹了微信小程序?qū)W習(xí)總結(jié)(四)事件與冒泡,結(jié)合實(shí)例形式分析了微信小程序事件、冒泡、數(shù)據(jù)獲取相關(guān)機(jī)制、原理與操作注意事項(xiàng),需要的朋友可以參考下2020-06-06
JavaScript Accessor實(shí)現(xiàn)說(shuō)明
關(guān)于Getter與Setter大家一定不會(huì)陌生,下面簡(jiǎn)單介紹幾種我所知道的在JavaScript中實(shí)現(xiàn)G/S的方法.2010-12-12
JavaScript高級(jí)教程5.6之基本包裝類型(詳細(xì))
在基本類型當(dāng)中,有三種類型是我們經(jīng)常使用的:boolean,number,string,通過(guò)本篇文章給大家介紹javascript高級(jí)教程5.6之基本包裝類型,感興趣的朋友一起學(xué)習(xí)吧2015-11-11
鼠標(biāo)右擊事件代碼(asp.net后臺(tái))
本程序由一個(gè)js文件和aspx文件組成,沒有后臺(tái)CS代碼。2011-01-01

