简单做了一个树+列表通用控件,依赖jquery和ztree,效果如图:
JS文件如下:
/**
* 树+列表组件化
* @author hyt
* @version 1.00.00
*/
(function ($) {
$.extend({
treelist: {
options: {
check: {
enable: false,
chkboxType: {"Y": "", "N": ""}
},
view: {
dblClickExpand: true
},
data: {
simpleData: {
enable: true
}
},
callback: {}
},
html: `
<div class="menuContent tree-list-container">
<div class="tree-list-box">
<div class="tree-list-tree">
<ul class="ztree" ></ul>
</div>
<div class="tree-list-list">
<div class="search-box">
</div>
<div class="tree-box">
<table class="tree-list">
<thead class="tree-list-thead fixed-table-header"><tr></tr></thead>
<tbody class="tree-list-tbody"></tbody>
</table>
</div>
<div class="tree-list-footer">
<button type="button" class="tree-list-btn" onclick="$.treelist.hideMenu()">确定</button>
</div>
</div>
</div>
</div>
`,
init(opt) {
//ID的input
let idElement = opt.idElement;
//名称的input
let nameElement = opt.nameElement;
let treeHtml = $($.treelist.html);
let tree = opt.tree;
let list = opt.list;
let id = tree.id;
let postKey = tree.postKey;
let treeUrl = tree.url;
let listUrl = list.url;
let multiSelect = opt.multiSelect;
let postWithSon = opt.postWithSon;
let columns = list.columns;
let searchColumns = list.searchColumns;
let idKey = list.idKey;
let nameKey = list.nameKey;
let listPostKey = list.postKey;
let idList = [];
let nameList= [];
treeHtml.attr("id", id + "-tree-box");
treeHtml.find("ul").attr("id", id + "-tree");
//宽度与input对齐
treeHtml.css("min-width", nameElement.outerWidth() + "px");
//追加到input后面
nameElement.after(treeHtml);
let treeOpt = JSON.parse(JSON.stringify($.treelist.options));
let category;
//查询方法
let search = function(){
//获取到treeNode,然后调用接口生成列表
let postJson = {
[listPostKey]: category,
pageNum: 1,
pageSize: 99999
};
//带上搜索条件
if (searchColumns && searchColumns.length > 0) {
for (let i = 0; i < searchColumns.length; i++) {
let key = searchColumns[i].key;
postJson[key] = treeHtml.find(".search-" + key).val();
}
}
$.post(ctx + listUrl, postJson, function (res) {
let data = res.data;
let listBody = treeHtml.find(".tree-list-tbody");
listBody.html("");
if (data.length>0){
for (let i = 0; i < data.length; i++) {
let tr = $("<tr></tr>");
//多选效果初始化
if (multiSelect) {
let checkboxElem = $(`<input type="checkbox" class="tree-list-checkbox">`);
let id = data[i][idKey];
let name = data[i][nameKey];
checkboxElem.change(function (e) {
let checked = e.currentTarget.checked;
if (checked){
idList.push(id);
nameList.push(name);
}else {
//判断是取消勾选则移除,否则追加
for (let j = 0; j < idList.length; j++) {
if (idList[j] === id){
idList.splice(j,1);
nameList.splice(j,1);
break;
}
}
}
nameElement.val(nameList.join(","));
idElement.val(idList.join(","));
});
for (let j = 0; j < idList.length; j++) {
if (idList[j] === id){
checkboxElem[0].checked = true;
}
}
let td = $("<td></td>");
td.html(checkboxElem);
tr.append(td);
}
for (let j = 0; j < columns.length; j++) {
let td = $("<td></td>");
td.text(data[i][columns[j].key]);
td.attr("title", data[i][columns[j].key]);
td.css("width", columns[j].width);
tr.append(td);
}
//多选,则勾选checkbox,单选直接关闭组件
if (multiSelect){
tr.click(function (e) {
let checkbox = tr.find("input")[0];
if (e.toElement!==checkbox){
checkbox.checked = !checkbox.checked;
$(checkbox).change();
}
});
}else {
tr.click(function () {
nameElement.val(data[i][nameKey]);
idElement.val(data[i][idKey]);
$.treelist.hideMenu();
});
}
listBody.append(tr);
}
}else{
listBody.html(`<tr style='text-align: center'><td colspan='${multiSelect?columns.length+1:columns.length}'>没有记录</td></tr>`)
}
})
};
//渲染搜索栏
if (searchColumns && searchColumns.length > 0) {
for (let i = 0; i < searchColumns.length; i++) {
let key = searchColumns[i].key;
let name = searchColumns[i].name;
treeHtml.find(".search-box").append(`
<div class="search-elem"><span>${name}:</span><input type="text" class="search-${key}"></div>
`);
}
let searchButton = $(`<button type="button" class="tree-list-btn">搜索</button>`);
searchButton.click(search);
treeHtml.find(".search-box").append(searchButton);
}
//渲染表头
if (columns && columns.length > 0) {
if (multiSelect){
//感觉全选没用,不做了
treeHtml.find(".tree-list-thead tr").append(`<td></td>`);
}
for (let i = 0; i < columns.length; i++) {
let key = columns[i].key;
let name = columns[i].name;
let width = columns[i].width;
let td = $("<td></td>");
td.text(name);
td.css("width", width);
treeHtml.find(".tree-list-thead tr").append(td);
}
}
//树选中事件
treeOpt.callback.onClick = function (e, treeId, treeNode) {
let zTree = $.fn.zTree.getZTreeObj(id + "-tree");
category = treeNode[postKey];
//如果需要带上子节点,拼接到请求参数里。
if (postWithSon){
let nodes = zTree.getNodesByFilter(()=>{return true},false,treeNode);
let nodeIds = [treeNode[postKey]];
for (let i = 0; i < nodes.length; i++) {
nodeIds.push(nodes[i][postKey]);
}
category = nodeIds.join(",");
search();
}
};
treeOpt = {
...treeOpt,
...opt
};
//获取树数据
$.post(ctx + treeUrl, {}, function (data) {
let zTree = $.fn.zTree.init($("#" + id + "-tree"), treeOpt, data);
search();
});
//设置input点击事件
nameElement.click(function () {
$("#" + id + "-tree-box").show();
$("body").bind("mousedown", $.treelist.onBodyDown);
});
},
hideMenu() {
$(".menuContent").fadeOut("fast");
$("body").unbind("mousedown", $.treelist.onBodyDown);
},
onBodyDown(event) {
let target = $(event.target);
if (!(target.hasClass("menuContent") || $(target).parents(".menuContent").length > 0)) {
$.treelist.hideMenu();
}
}
},
});
})(jQuery);
css文件如下:
.tree-list-container{
display:none;
position: absolute;
z-index: 300;
border:1px solid #3c8dbc;
padding: 10px;
background-color: #ffffff;
}
.tree-list-box{
width: 100%;
display: flex
}
.tree-list-tree{
flex: 1;
border: 1px solid #3c8dbc;
margin-right: 5px;
padding: 10px;
max-height: 430px;
overflow: auto;
}
.tree-list-list{
flex: 1;
border: 1px solid #3c8dbc;
padding: 10px;
position: relative;
}
.tree-list-checkbox{
width: unset!important;
height: unset!important;
}
.search-box{
margin-bottom: 5px;
}
.search-box>div{
display: inline-block;
}
.search-elem{
min-width: 200px;
font-size: 12px;
margin-bottom: 5px;
}
.search-elem>input{
width: 100px!important;
}
.tree-list-search-btn{
}
.tree-box{
width: 100%;
max-height: 300px;
margin-bottom: 40px;
overflow: auto;
}
.tree-list{
border-collapse: collapse;
border-spacing: 0;
table-layout: fixed;
word-wrap: break-word;
min-width: 300px;
max-height: 300px;
display: table;
}
.tree-list td{
border: 1px solid #3c8dbc;
padding: 5px 10px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.tree-list-tbody tr:hover{
cursor: pointer;
background-color: #ffd676;
}
.tree-list-footer{
position: absolute;
bottom: 10px;
right: 20px;
}
.tree-list-btn{
border-radius: 15px;
color: #ffffff;
padding: 5px 10px;
font-size: 12px;
background-color: #3c8dbc;
border: 1px solid #3c8dbc;
}
.tree-list-thead{
background-color: #3c8dbc;
color: #FFFFFF;
text-align: center;
}
引用代码如下:
$.treelist.init({
tree:{
id:'category',
postKey:'请求列表数据的分类参数名如id',
url: '树数据url'
},
list:{
url:'列表数据url',
columns:[
//列表展示的列
{
name:'名称',
key:'name',
width:'70%'
}
],
searchColumns:[
//搜索字段
{
name:'名称',
key:'name'
}
],
//回写到id的参数名
idKey:'id',
//回写到name的参数名
nameKey:'name',
//分类参数名
postKey:'categoryId'
},
//是否和子分类一起拼接请求列表数据
postWithSon:true,
//是否多选
multiSelect:false,
//id dom
idElement:$("#appId"),
//名称 dom
nameElement:$("#robotName")
});