基於jquery的復選樹的插件。
業務需求:復選樹,帶有多選功能,有子級被選中時父級需要有提示,層級不定,基於jquery。
/*
* name: checkboxTree 復選樹結構
*/
/**輸入的數據結構:
data
[
{
name: 'label1',
value: 'some info'
children: [
{
name: 'label11'
}
]
},
{
name: 'label1',
value: 'some info'
children: [
{
name: 'label11'
}
]
}
]
initSelectOptions
[]
暴露的方法:
addSelect: 增加選中
getSelect: 獲取選中的項
*/
(function($) {
jQuery.fn.checkboxTree = function (settings_) {
settings = $.extend({
data:[],
initSelectOptions: null // 默認選中項,只要底層。
}, settings_)
var container = $(this)
// 子元素html
function getChildrenHtml(treesdata){
var result = '',
len = treesdata.length,
node, // 節點
clen // 子元素的數量
for(var i = 0; i < len; i++){
node = treesdata[i]
// 判斷子元素數量
clen = (node.children && node.children.length > 0) ? node.children.length : 0
result += "<li"
if (!clen) result += " class='nochildren'"
result += " data-rel='" + node.value + "'>"
if (clen) result += "<i class='fa fa-plus-square'></i>"
result += "<input type='checkbox' id='" + node.name + "'><div class='checkbox'><label for='" + node.name + "'></label></div><label for='" + node.name + "'>" + node.name + "</label>"
// 加載子元素
if (clen) result += "<ul class='hide'>" + getChildrenHtml(node.children) + "</ul>"
result += "</li>"
}
return result
}
// 渲染樹
(function initCheckTree() {
var treesHtml = "<ul class='checktree'><li><i class='fa fa-minus-square'></i><input type='checkbox' id='all'><div class='checkbox'><label for='all'></label></div><label for='all'>全部</label><ul>"
treesHtml += getChildrenHtml(settings.data)
container.empty().append(treesHtml + '</ul></li></ul>')
})();
// checkbox的click事件
container.on('click', 'input', function () {
var $this = $(this),
$li = $this.parent(),
$parentCheckbox, // 父級的復選框
checked = $this.prop("checked")
// 向下傳遞
// 1.獲取所有后輩checkbox。 2.選中狀態改成和祖輩一樣 3.取消所有后輩的半選狀態
var childCheckbox = $li.find("input[type='checkbox']")
if (childCheckbox.length > 1) {
$li.find(".checkbox").removeClass("half-select")
childCheckbox.each(function () {
if($(this).prop("checked") !== checked) {
$(this).prop("checked", checked)
}
})
}
// 判斷修改父級checkbox狀態
(function calculateParentStatus (li_) {
var elementLi = $(li_)
if (elementLi.parent().hasClass("checktree")) return
// 1.獲取兄弟li的數量。 2.遍歷查看是否全被選中。 4.未全部選中,判斷所有父級是否選中,選中就改為未選中。
// selectOne判斷半選狀態.表明是否有一個元素被選中
var $sibCheckbox = elementLi.parent().find("li").children("input[type='checkbox']")
var selectAll = true
var selectOne = false
for (var i = 0; i < $sibCheckbox.length; i++) {
if (!$sibCheckbox[i].checked) {
selectAll = false
if (selectOne === true) break
} else {
selectOne = true
if (selectAll === false) break
}
}
// 全部選中。觸發父級選中事件(父級checkboxclick事件)
if (selectAll) {
// 上層
elementLi.parent().parent().children(".checkbox").removeClass("half-select")
$parentCheckbox = elementLi.parent().parent().children("input[type='checkbox']")
$parentCheckbox.trigger("click")
}
if (selectAll === false) {
$parentCheckbox = elementLi.parents("li").children("input[type='checkbox']")
if ($parentCheckbox.prop("checked")) {
$parentCheckbox.prop("checked", false)
}
if (selectOne) {
// 祖先元素全部半選
elementLi.parents("li").children(".checkbox").addClass("half-select")
} else {
// 取消父輩半選狀態
elementLi.parent().parent().children(".checkbox").removeClass("half-select")
// 向上再檢查
calculateParentStatus(elementLi.parent().parent())
}
}
})($li)
})
// 開合操作
container.off('click', '.fa').on('click', '.fa', function () {
var $i = $(this)
var $li = $(this).parent()
var $ul = $li.find(">ul")
if ($i.hasClass("fa-plus-square")) {
$i.removeClass("fa-plus-square").addClass("fa-minus-square")
$ul.removeClass("hide")
} else if ($i.hasClass("fa-minus-square")) {
$i.removeClass("fa-minus-square").addClass("fa-plus-square")
$ul.addClass("hide")
}
});
// 通過傳入li的value集合,選中相應checkbox
function addSelect (options_) {
if (options_ && options_.length) {
for (var i = 0; i < options_.length; i++) {
container.find("li[data-rel='" + options_[i] + "']").children("input").trigger("click")
}
}
}
// 獲取已經被選中的子項
function getSelect () {
var selectedLi = container.find("li.nochildren").find("input[type=checkbox]:checked").parent()
var selectedValue = []
selectedLi.each(function (i, e) {
selectedValue.push(e.getAttribute("data-rel"))
})
return selectedValue
}
// initSelect
if (settings.initSelectOptions) addSelect(settings.initSelectOptions)
return {
addSelect: addSelect,
getSelect: getSelect
}
}
})(jQuery)
css
// 自定義復選框樹組件
.checkboxTree {
max-height: 400px;
overflow: auto;
.checktree {
width: 400px;
padding-left: 100px;
li {
list-style-type: none;
input[type="checkbox"] {
position: relative;
top: 7px;
visibility: hidden;
&:checked + .checkbox label:after {
opacity: 1;
}
}
label {
position: relative;
left: -10px;
cursor: pointer;
}
.checkbox {
width: 13px;
height: 13px;
display: inline-block;
position: relative;
margin: 3px 3px 3px 4px;
top: 7px;
left: -16px;
&.half-select {
label {
background-color: #BBE5DF;
}
}
label {
cursor: pointer;
position: absolute;
width: 13px;
height: 13px;
top: 0;
left: 0;
background: #eee;
border: 1px solid #ddd;
&:after {
opacity: 0;
content: '';
position: absolute;
width: 8px;
height: 4px;
top: 2px;
left: 1px;
background: 0 0;
border: 1px solid #000000;
border-top: none;
border-right: none;
transform: rotate(-47deg);
-webkit-transform: rotate(-47deg);
-moz-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
}
}
}
i {
color: #BBE5DF;
cursor: pointer;
}
}
.hide {
display: none;
}
}
}