| | |
| | | <template> |
| | | <div class="ztree" :id="ztreeId"></div> |
| | | <div> |
| | | <div class="searchTree"> |
| | | <el-input |
| | | placeholder="搜索" |
| | | v-model="keyWord" |
| | | size="mini" |
| | | v-show="search" |
| | | > |
| | | <i |
| | | slot="suffix" |
| | | class="el-input__icon el-icon-search" |
| | | :id="searchBtnId" |
| | | ></i> |
| | | </el-input> |
| | | </div> |
| | | <div class="ztree" :id="ztreeId"></div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import * as $ from "jquery"; |
| | | import { Loading } from "element-ui"; |
| | | |
| | | if (!window.jQuery) { |
| | | window.jQuery = $; |
| | | } |
| | | |
| | | // require("@ztree/ztree_v3/js/jquery.ztree.all"); |
| | | require("./ztree_v3/jquery.ztree.all"); |
| | | require("./ztree_v3/jquery.ztree.exhide"); |
| | | |
| | | export default { |
| | | props: { |
| | | showCheckbox: { type: Boolean, default: false }, |
| | | readonly: { type: Boolean, default: true }, |
| | | gb28181: { type: Boolean, default: false }, |
| | | search: { type: Boolean, default: false }, |
| | | setting: { |
| | | type: Object, |
| | | require: false, |
| | |
| | | data() { |
| | | return { |
| | | ztreeId: "ztree_" + parseInt(Math.random() * 1e10), |
| | | searchBtnId: "search_" + parseInt(Math.random() * 1e10), |
| | | ztreeObj: null, |
| | | list: [], |
| | | loading: false, |
| | | ztreeSetting: { |
| | | view: { |
| | | showLine: true, |
| | |
| | | }, |
| | | onClick: (...arg) => { |
| | | this.$emit("onClick", ...arg); |
| | | //this.removeHoverIcon(...arg); |
| | | this.removeHoverIcon(...arg); |
| | | }, |
| | | onCollapse: (...arg) => { |
| | | this.$emit("onCollapse", ...arg); |
| | |
| | | }, |
| | | }, |
| | | }, |
| | | keyWord: "", |
| | | options: { |
| | | target: "", |
| | | }, |
| | | }; |
| | | }, |
| | | watch: { |
| | |
| | | Object.assign({}, this.ztreeSetting, this.setting), |
| | | this.list |
| | | ); |
| | | this.fuzzySearch(this.ztreeObj, this.searchBtnId, false, true); //初始化模糊搜索方法 |
| | | this.$emit("onCreated", this.ztreeObj); |
| | | }); |
| | | }, |
| | |
| | | }, |
| | | showCheckbox: { |
| | | handler: function () { |
| | | let top = $("#" + this.ztreeId) |
| | | .parent() |
| | | .scrollTop(); |
| | | |
| | | this.ztreeSetting.check.enable = this.showCheckbox; |
| | | |
| | | if (this.ztreeObj) { |
| | |
| | | Object.assign({}, this.ztreeSetting, this.setting), |
| | | this.list |
| | | ); |
| | | $("#" + this.ztreeId) |
| | | .parent() |
| | | .scrollTop(top); |
| | | this.$emit("onCreated", this.ztreeObj); |
| | | }); |
| | | }, |
| | |
| | | // 文件夹新增按钮 |
| | | if ( |
| | | item && |
| | | !item.querySelector(".addIcon") && |
| | | !item.querySelector(".el-icon-circle-plus-outline") && |
| | | treeNode.isParent && |
| | | !this.readonly && |
| | | !this.gb28181 |
| | | ) { |
| | | const btn = document.createElement("a"); |
| | | const btn = document.createElement("i"); |
| | | btn.id = `${treeid}_${treeNode.id}_btn`; |
| | | btn.classList.add("addIcon"); |
| | | btn.classList.add("iconfont"); |
| | | btn.title = "新增"; |
| | | btn.classList.add("el-icon-circle-plus-outline"); |
| | | btn.classList.add("primary"); |
| | | // btn.innerText = '删除'; |
| | | btn.addEventListener("click", (e) => { |
| | | e.stopPropagation(); |
| | |
| | | // 文件夹删除按钮 |
| | | if ( |
| | | item && |
| | | !item.querySelector(".delIcon") && |
| | | !item.querySelector(".el-icon-remove-outline") && |
| | | treeNode.isParent && |
| | | !this.readonly && |
| | | !treeNode.children && |
| | | !this.gb28181 |
| | | ) { |
| | | const btn = document.createElement("a"); |
| | | const btn = document.createElement("i"); |
| | | btn.id = `${treeid}_${treeNode.id}_btn`; |
| | | btn.classList.add("delIcon"); |
| | | btn.classList.add("iconfont"); |
| | | btn.title = "删除"; |
| | | btn.classList.add("el-icon-remove-outline"); |
| | | btn.classList.add("danger"); |
| | | // btn.innerText = '删除'; |
| | | btn.addEventListener("click", (e) => { |
| | | e.stopPropagation(); |
| | |
| | | // 文件夹编辑按钮 |
| | | if ( |
| | | item && |
| | | !item.querySelector(".editIcon") && |
| | | !item.querySelector(".el-icon-edit") && |
| | | treeNode.isParent && |
| | | !this.readonly |
| | | ) { |
| | | const btn = document.createElement("a"); |
| | | const btn = document.createElement("i"); |
| | | btn.id = `${treeid}_${treeNode.id}_btn`; |
| | | btn.classList.add("editIcon"); |
| | | btn.classList.add("iconfont"); |
| | | btn.title = "编辑"; |
| | | btn.classList.add("el-icon-edit"); |
| | | btn.classList.add("primary"); |
| | | // btn.innerText = '删除'; |
| | | btn.addEventListener("click", (e) => { |
| | | e.stopPropagation(); |
| | |
| | | |
| | | item.appendChild(btn); |
| | | } |
| | | |
| | | // 添加摄像机按钮 |
| | | if ( |
| | | item && |
| | | !item.querySelector(".addCameraIcon") && |
| | | !item.querySelector(".iconshishishipin") && |
| | | treeNode.isParent && |
| | | !this.readonly && |
| | | !this.gb28181 |
| | | ) { |
| | | const btn = document.createElement("a"); |
| | | const btn = document.createElement("i"); |
| | | btn.id = `${treeid}_${treeNode.id}_btn`; |
| | | btn.classList.add("iconfont"); |
| | | btn.classList.add("addCameraIcon"); |
| | | btn.title = "添加摄像机"; |
| | | btn.classList.add("iconshishishipin"); |
| | | btn.classList.add("primary"); |
| | | btn.classList.add("icon-fix"); |
| | | // btn.innerText = '删除'; |
| | | btn.addEventListener("click", (e) => { |
| | | e.stopPropagation(); |
| | |
| | | // 导入摄像机按钮 |
| | | if ( |
| | | item && |
| | | !item.querySelector(".importIcon") && |
| | | !item.querySelector(".icondaoru") && |
| | | treeNode.isParent && |
| | | !this.readonly && |
| | | !this.gb28181 |
| | | ) { |
| | | const btn = document.createElement("a"); |
| | | const btn = document.createElement("i"); |
| | | btn.id = `${treeid}_${treeNode.id}_btn`; |
| | | btn.classList.add("iconfont"); |
| | | btn.classList.add("importIcon"); |
| | | btn.title = "导入摄像机"; |
| | | btn.classList.add("icondaoru"); |
| | | btn.classList.add("primary"); |
| | | btn.classList.add("icon-fix"); |
| | | // btn.innerText = '删除'; |
| | | btn.addEventListener("click", (e) => { |
| | | e.stopPropagation(); |
| | |
| | | // 查看底图按钮 |
| | | if ( |
| | | item && |
| | | !item.querySelector(".icontupian1") && |
| | | !item.querySelector(".el-icon-picture") && |
| | | treeNode.type == "camera" |
| | | ) { |
| | | const btn = document.createElement("a"); |
| | | const btn = document.createElement("i"); |
| | | btn.id = `${treeid}_${treeNode.id}_btn`; |
| | | btn.classList.add("iconfont"); |
| | | btn.classList.add("icontupian1"); |
| | | btn.classList.add("el-icon-picture"); |
| | | btn.classList.add("primary"); |
| | | btn.classList.add("icon-fix"); |
| | | btn.title = "查看底图"; |
| | | // btn.innerText = '删除'; |
| | | btn.addEventListener("click", (e) => { |
| | | e.stopPropagation(); |
| | |
| | | removeHoverDom(treeid, treeNode) { |
| | | const item = document.getElementById(`${treeNode.tId}_a`); |
| | | if (item) { |
| | | let btn = item.querySelector(".addIcon"); |
| | | let btn = item.querySelector(".el-icon-circle-plus-outline"); |
| | | if (btn) { |
| | | item.removeChild(item.querySelector(".addIcon")); |
| | | item.removeChild(item.querySelector(".el-icon-circle-plus-outline")); |
| | | } |
| | | |
| | | btn = item.querySelector(".delIcon"); |
| | | btn = item.querySelector(".el-icon-remove-outline"); |
| | | if (btn) { |
| | | item.removeChild(item.querySelector(".delIcon")); |
| | | item.removeChild(item.querySelector(".el-icon-remove-outline")); |
| | | } |
| | | |
| | | btn = item.querySelector(".editIcon"); |
| | | btn = item.querySelector(".el-icon-edit"); |
| | | if (btn) { |
| | | item.removeChild(item.querySelector(".editIcon")); |
| | | item.removeChild(item.querySelector(".el-icon-edit")); |
| | | } |
| | | |
| | | btn = item.querySelector(".addCameraIcon"); |
| | | btn = item.querySelector(".iconshishishipin"); |
| | | if (btn) { |
| | | item.removeChild(item.querySelector(".addCameraIcon")); |
| | | item.removeChild(item.querySelector(".iconshishishipin")); |
| | | } |
| | | |
| | | btn = item.querySelector(".importIcon"); |
| | | btn = item.querySelector(".icondaoru"); |
| | | if (btn) { |
| | | item.removeChild(item.querySelector(".importIcon")); |
| | | item.removeChild(item.querySelector(".icondaoru")); |
| | | } |
| | | |
| | | btn = item.querySelector(".icontupian1"); |
| | | btn = item.querySelector(".el-icon-picture"); |
| | | if (btn) { |
| | | item.removeChild(item.querySelector(".icontupian1")); |
| | | item.removeChild(item.querySelector(".el-icon-picture")); |
| | | } |
| | | } |
| | | }, |
| | | fuzzySearch(zTreeObj, searchField, isHighLight, isExpand) { |
| | | const _this = this; |
| | | |
| | | if (!zTreeObj) { |
| | | alert("fail to get ztree object"); |
| | | } |
| | | var nameKey = zTreeObj.setting.data.key.name; //get the key of the node name |
| | | isHighLight = isHighLight === false ? false : true; //default true, only use false to disable highlight |
| | | isExpand = isExpand ? true : false; // not to expand in default |
| | | zTreeObj.setting.view.nameIsHTML = isHighLight; //allow use html in node name for highlight use |
| | | |
| | | var metaChar = "[\\[\\]\\\\^\\$\\.\\|\\?\\*\\+\\(\\)]"; //js meta characters |
| | | var rexMeta = new RegExp(metaChar, "gi"); //regular expression to match meta characters |
| | | |
| | | // keywords filter function |
| | | function ztreeFilter(zTreeObj, _keywords, callBackFunc) { |
| | | if (!_keywords) { |
| | | _keywords = ""; //default blank for _keywords |
| | | } |
| | | |
| | | // function to find the matching node |
| | | function filterFunc(node) { |
| | | if (node && node.oldname && node.oldname.length > 0) { |
| | | node[nameKey] = node.oldname; //recover oldname of the node if exist |
| | | } |
| | | zTreeObj.updateNode(node); //update node to for modifications take effect |
| | | if (_keywords.length == 0) { |
| | | //return true to show all nodes if the keyword is blank |
| | | zTreeObj.showNode(node); |
| | | zTreeObj.expandNode(node, isExpand); |
| | | return true; |
| | | } |
| | | //transform node name and keywords to lowercase |
| | | if ( |
| | | node[nameKey] && |
| | | node[nameKey].toLowerCase().indexOf(_keywords.toLowerCase()) != -1 |
| | | ) { |
| | | if (isHighLight) { |
| | | //highlight process |
| | | //a new variable 'newKeywords' created to store the keywords information |
| | | //keep the parameter '_keywords' as initial and it will be used in next node |
| | | //process the meta characters in _keywords thus the RegExp can be correctly used in str.replace |
| | | var newKeywords = _keywords.replace(rexMeta, function (matchStr) { |
| | | //add escape character before meta characters |
| | | return "\\" + matchStr; |
| | | }); |
| | | node.oldname = node[nameKey]; //store the old name |
| | | var rexGlobal = new RegExp(newKeywords, "gi"); //'g' for global,'i' for ignore case |
| | | //use replace(RegExp,replacement) since replace(/substr/g,replacement) cannot be used here |
| | | node[nameKey] = node.oldname.replace( |
| | | rexGlobal, |
| | | function (originalText) { |
| | | //highlight the matching words in node name |
| | | var highLightText = |
| | | '<span style="color: whitesmoke;background-color: darkred;">' + |
| | | originalText + |
| | | "</span>"; |
| | | return highLightText; |
| | | } |
| | | ); |
| | | zTreeObj.updateNode(node); //update node for modifications take effect |
| | | } |
| | | zTreeObj.showNode(node); //show node with matching keywords |
| | | return true; //return true and show this node |
| | | } |
| | | |
| | | zTreeObj.hideNode(node); // hide node that not matched |
| | | return false; //return false for node not matched |
| | | } |
| | | |
| | | var nodesShow = zTreeObj.getNodesByFilter(filterFunc); //get all nodes that would be shown |
| | | processShowNodes(nodesShow, _keywords); //nodes should be reprocessed to show correctly |
| | | _this.$emit("onAfterSearch", null); |
| | | } |
| | | |
| | | /** |
| | | * reprocess of nodes before showing |
| | | */ |
| | | function processShowNodes(nodesShow, _keywords) { |
| | | if (nodesShow && nodesShow.length > 0) { |
| | | //process the ancient nodes if _keywords is not blank |
| | | if (_keywords.length > 0) { |
| | | $.each(nodesShow, function (n, obj) { |
| | | var pathOfOne = obj.getPath(); //get all the ancient nodes including current node |
| | | if (pathOfOne && pathOfOne.length > 0) { |
| | | //i < pathOfOne.length-1 process every node in path except self |
| | | for (var i = 0; i < pathOfOne.length - 1; i++) { |
| | | zTreeObj.showNode(pathOfOne[i]); //show node |
| | | zTreeObj.expandNode(pathOfOne[i], true); //expand node |
| | | } |
| | | } |
| | | }); |
| | | } else { |
| | | //show all nodes when _keywords is blank and expand the root nodes |
| | | var rootNodes = zTreeObj.getNodesByParam("level", "0"); //get all root nodes |
| | | $.each(rootNodes, function (n, obj) { |
| | | zTreeObj.expandNode(obj, true); //expand all root nodes |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | |
| | | //listen to change in input element |
| | | $("#" + searchField).bind("click", function () { |
| | | // _this.options.target = document.querySelector("#" + _this.ztreeId).parentNode.parentNode |
| | | // console.log(_this.options.target); |
| | | // let loadingInstance = Loading.service(_this.options) |
| | | // console.log(_this.keyWord); |
| | | // var _keywords = $(this).val(); |
| | | $("#" + searchField).removeClass("el-icon-search"); |
| | | $("#" + searchField).addClass("el-icon-loading"); |
| | | searchNodeLazy(_this.keyWord); //call lazy load |
| | | // loadingInstance.close() |
| | | setTimeout(() => { |
| | | $("#" + searchField).removeClass("el-icon-loading"); |
| | | $("#" + searchField).addClass("el-icon-search"); |
| | | }, 300); |
| | | }); |
| | | |
| | | var lastKeyword = ""; |
| | | // excute lazy load once after input change, the last pending task will be cancled |
| | | function searchNodeLazy(_keywords) { |
| | | if (lastKeyword === _keywords) { |
| | | return; |
| | | } |
| | | ztreeFilter(zTreeObj, _keywords); //lazy load ztreeFilter function |
| | | // $(searchField).focus();//focus input field again after filtering |
| | | lastKeyword = _keywords; |
| | | } |
| | | }, |
| | | handleSearch() { |
| | | this.loading = true; |
| | | searchNodeLazy(this.keyWord); //call lazy load |
| | | this.loading = false; |
| | | }, |
| | | }, |
| | | }; |
| | |
| | | filter: alpha(opacity=0); |
| | | position: absolute; |
| | | } |
| | | |
| | | .iconfont.el-icon-picture.primary.icon-fix { |
| | | margin-left: 10px; |
| | | margin-right: 10px; |
| | | font-size: 16px; |
| | | color: #0065ff; |
| | | } |
| | | </style> |
| | | |
| | | <style scoped lang="scss"> |
| | | .searchTree { |
| | | margin: 5px 5px; |
| | | display: flex; |
| | | justify-content: center; |
| | | |
| | | .el-input { |
| | | margin: 0 auto; |
| | | width: 350px; |
| | | } |
| | | |
| | | ::v-deep .el-input__suffix { |
| | | right: 0; |
| | | width: 50px; |
| | | background: skyblue; |
| | | color: #fff; |
| | | cursor: pointer; |
| | | background-color: rgb(61, 104, 255); |
| | | } |
| | | |
| | | .el-icon-search:before { |
| | | content: "搜索"; |
| | | } |
| | | } |
| | | </style> |