最近做了一个项目,是在网页中实现一份包含树目录导航的word文档的功能,简单点说就是将一个word文档,包括它的左侧导航部分,用网页的方式实现。
一、需求
1、 左侧实现目录树,右侧是内容
2、 点击左侧目录,右侧跳转到对应的章节
3、 左侧树要有全部展开、全部折叠、点击父节点前的加号可展开收缩、点击目录只可展开不可收缩、按关键字搜索目录等功能
4、 右侧内容包含翻页,点击翻页时,右侧在跳转到对应页面的同时,左侧要选中右侧页面对应的章节目录
二、思路
1、用iframe分左右两栏,左侧是目录树页面,右侧是内容页面
2、树用zTree实现
三、实现过程
1、iframe实现分栏
<iframe height="100%" id="left" style="border:none"></iframe> <iframe height="100%" id="right" name="main" style="border:none;"></iframe>
$("iframe").css({ "border" : "1", "border-color" : "#B2DFEE", "scrolling" : "yes" }); $("#left").attr({ "src" : "left.html", "width" : "20%" }); $("#right").attr({ "src" :"right.html" "width" : "79.7%" });
上面的代码中有两个iframe,用jqueruy添加src属性,分别嵌入左侧的目录树left.html页面和右侧的right.html页面,并设置它们各自所占的宽度。
2、实现左侧的目录树
在实现树之前,要引入ztree的js库和css样式表以及jquery库,除此之外还可根据自己的需求,引入不同的js和css外部文件。如下所示:
<link rel="stylesheet" type="text/css" href="../js/zTree/js/zTreeStyle/zTreeStyle.css" /> <link rel="stylesheet" href="../js/bootstrap/css/bootstrap.min.css" /> <script type="text/javascript" src="../js/jquery-1.9.1.min.js"></script> <script type="text/javascript" src="../js/bootstrap/js/bootstrap.min.js"></script> <script type="text/javascript" src="../js/zTree/js/jquery.ztree.core-3.5.min.js"></script>
实现一棵ztree树,基本的操作有四步:
第一步:设置树的id,注意用的是<ul></ul>标签
<ul id="helpTree" class="ztree"></ul>
第二步:配置树
var setting = { edit :{ enable:true }, view : { dblClickExpand: false, showLine : true, checkable:true, showIcon:true, showTitle:true, fontCss:{ 'color' : '#009ACD',//#009ACD 'font-weight' : 'normal' } }, data : { simpleData : { enable : true, idKey : "id", pIdKey : "pId", rootPid :0 }, key:{ title:"title" } }, check:{ enable:false,//不显示checkbox、radio chkStyle:"checkbox", radioType:"level" }, callback : { beforeClick:function(treeId,treeNode){ zTree=$.fn.zTree.getZTreeObj("helpTree"); if (treeNode.isParent) { zTree.expandNode(treeNode,true); return; } }, beforeDblClick:function(treeId,treeNode){ return false;//禁止双击事件onDblClick }, onExpand : function(event,treeId,treeNode) { zTree = $.fn.zTree.getZTreeObj("helpTree"); zTree.expandNode(treeNode,true); }, onCollapse : function(event,treeId,treeNode) { zTree = $.fn.zTree.getZTreeObj("helpTree"); zTree.expandNode(treeNode,false); }, onClick :onClick /* beforeCollapse:function(treeId,treeNode){ var id = treeNode.id; if(id==1||id==2||id==3||id==4||id==5){ return true;//禁止所有 }else{ return false; } }, */ } }; /* 节点点击事件 :点击某个节点将其值赋值给文本框*/ function onClick(treeId, treeNode) { //在不输入关键字选中节点时禁止点击事件的发生 var search = $("#keyName").val(); if (search == "" || search == null) { return; } else { var zTree = getTree(); var nodes = zTree.getSelectedNodes(); var v = ""; for (var i = 0, l = nodes.length; i < l; i++) { v += nodes[i].name + ","; } if (v.length > 1) { v = v.substring(0, v.length - 1); } $("#keyName").attr("value", v); $("#keyName").attr("title", v); return false; } }
第三步:设置树节点数据,以及各节点的链接页面
var zNodes =[ /* 前言 */ { id:17, pId:0, name:"前言",url:"./foreword.html",target:"main",icon:"../js/zTree/js/zTreeStyle/img/diy/3.png"}, /* 第一章 */ { id:1, pId:0, name:"1 第一章", open:false,url:"./cluster/cluster_1.1.html",target:"main"}, { id:11, pId:1, name:"1.1 第一节", open:true,url:"./cluster/cluster_1.1.html",target:"main"}, { id:12, pId:1, name:"1.2 第二节群",open:true,url:"./cluster/cluster_1.2.1.html",target:"main"}, { id:120, pId:12, name:"1.2.1 第二节1群",open:true,url:"./cluster/cluster_1.2.1.html",target:"main"}, { id:121, pId:120, name:"1.2.1.1 第二节11", open:true,url:"./cluster/cluster_1.2.1.html",target:"main"}, { id:122, pId:120, name:"1.2.1.2第二节12", open:true,url:"./cluster/cluster_1.2.1.html#2",target:"main"}, { id:123, pId:120, name:"1.2.1.3 第二节13", open:true,url:"./cluster/cluster_1.2.1.html#3",target:"main"}, { id:124, pId:120, name:"1.2.1.4 第二节14", open:true,url:"./cluster/cluster_1.2.1.html#4",target:"main"}, { id:125, pId:120, name:"1.2.1.5 第二节15", open:true,url:"./cluster/cluster_1.2.1.html#5",target:"main"}, { id:126, pId:120, name:"1.2.1.6 第二节16", open:true,url:"./cluster/cluster_1.2.1.html#6",target:"main"}, { id:127, pId:12, name:"1.2.2 第二节2",open:true,url:"./cluster/cluster_1.2.2.html",target:"main"}, { id:13, pId:1, name:"1.3 第三节",open:true,url:"./cluster/cluster_1.3.html",target:"main"}, { id:131, pId:13, name:"1.3.1 第三节1",open:true,url:"./cluster/cluster_1.3.html",target:"main"}, { id:14, pId:1, name:"1.4 第四节",open:true,url:"./cluster/cluster_1.4.1.html",target:"main"}, { id:141, pId:14, name:"1.4.1 第四节1",open:true,url:"./cluster/cluster_1.4.1.html",target:"main"}, { id:142, pId:14, name:"1.4.2 第四节2",open:true,url:"./cluster/cluster_1.4.2.html",target:"main"}, { id:143, pId:14, name:"1.4.3 第四节3",open:true,url:"./cluster/cluster_1.4.3.html",target:"main"}, { id:15, pId:1, name:"1.5 第五节",open:true,url:"./cluster/cluster_1.5.html",target:"main"}, { id:16, pId:1, name:"1.6 第六节",open:true,url:"./cluster/cluster_1.6.html",target:"main"}, /*第二章 */ { id:2, pId:0, name:"2 第二章",open:false,url:"./viewinfo/viewinfo_2.1.html",target:"main"}, { id:21, pId:2, name:"2.1第一节", open:true,url:"./viewinfo/viewinfo_2.1.html",target:"main"}, { id:22, pId:2, name:"2.2 第二节", open:true,url:"./viewinfo/viewinfo_2.2.html",target:"main"}, { id:23, pId:2, name:"2.3 第三节", open:true,url:"./viewinfo/viewinfo_2.3.html",target:"main"}, { id:24, pId:2, name:"2.4 第四节", open:true,url:"./viewinfo/viewinfo_2.4.1.html",target:"main"}, { id:241, pId:24, name:"2.4.1 第四节1", open:true,url:"./viewinfo/viewinfo_2.4.1.html",target:"main"}, { id:242, pId:24, name:"2.4.2 第四节2", open:true,url:"./viewinfo/viewinfo_2.4.2.html",target:"main"}, { id:25, pId:2, name:"2.5 第五节", open:true,url:"./viewinfo/viewinfo_2.5.1.html",target:"main"}, { id:251, pId:25, name:"2.5.1 第五节1", open:true,url:"./viewinfo/viewinfo_2.5.1.html",target:"main"}, { id:252, pId:25, name:"2.5.2 第五节2", open:true,url:"./viewinfo/viewinfo_2.5.2.html",target:"main"}, { id:253, pId:25, name:"2.5.3 3第五节", open:true,url:"./viewinfo/viewinfo_2.5.3.html",target:"main"}, { id:26, pId:2, name:"2.6 第六节", open:true,url:"./viewinfo/viewinfo_2.6.html",target:"main"},
第四步:初始化树,即形成树
/* 初始化树 */ function initialTree() { $.fn.zTree.init($("#helpTree"), setting, zNodes); }
通过以上这些步骤,就实现了前两个需求:创建一棵目录树,并在点击左侧树的目录标题时右侧会跳转到相应的内容。
关于树的配置,可以参考zTree的API进行查看,这里只是配置了一部分,根据不同的需求会有不同的配置,这里不加以阐述,因为我也还需要继续学习,毕竟我也是个后端儿!
3、点击按钮实现全部展开和全部折叠功能
第一步:创建按钮
<a href="#" title="全部展开" class="btn btn-info btn-sm" onclick="down()"> <span class="glyphicon glyphicon-plus" ></span></a>
<a href="#" title="全部折叠" class="btn btn-info btn-sm" onclick="up()"> <span class="glyphicon glyphicon-minus" ></span></a>
第二步:点击【全部展开】功能
/*
* 展开所有树节点
*/
function down() { $.fn.zTree.getZTreeObj("helpTree").expandAll(true); }
第三步:点击【全部折叠】功能
/* * 折叠所有树节点 */ function up() { $.fn.zTree.getZTreeObj("helpTree").expandAll(false); }
4、按关键字搜索树【该功能的实现是利用zTree中的getNodesByParamFuzzy("name", "test", null)方法进行模糊匹配】
第一步:创建搜索输入框和按钮
<input id="keyName" value="" type="text" placeholder="请输入搜索关键字"
class="form-control" onkeyup="searchClear()" style=" 180px;">
<a href="#" title="搜索" class="btn btn-info btn-sm" onclick="search()"> <span class="glyphicon glyphicon-search" ></span></a>
可以看到在input中有一个onkeyup()事件,这个事件会在键盘按键被松开时触发,即当用户准备输入时就会触发;另外在搜索按钮上也有一个点击事件,这个事件是当用户在输入搜索关键字,并点击搜索按钮时才会执行搜索动作
第二步:用户输入时,根据输入信息实时匹配出搜索结果
function searchClear() { var keyValue = $("#keyName").val();
/* 当输入值为空时展示完整的树,并给树添加title属性*/ if (keyValue == "") { clear(); } else { autoMatch(keyValue) } } /* 自动匹配搜索结果 */ function autoMatch(name) { var nameValue = name.replace(/s+/g, ""); if (nameValue.length > 0) { initialTree(); var treeObj = getTree(); var nodeList = treeObj.getNodesByParamFuzzy("name", nameValue, null); /* 将搜索结果重新生成一棵树展示,并设置目录的title属性 */
if (nodeList && nodeList.length > 1) {
$.fn.zTree.init($("#helpTree"), setting, nodeList); showTree(); setTitle(); } else { hideTree(); initialTree(); setTitle(); } } else { showTree(); } } //手动清除搜索内容时初始化并显示树 function clear() { initialTree(); showTree(); setTitle(); } /* 隐藏树 */ function hideTree() { $("#content").hide(); } /* 显示树 */ function showTree() { $("#content").show(); }
/*给树节点设置title属性 */ function setTitle() { var zTree = getTree(); nodes = zTree.transformToArray(zTree.getNodes()); for (var i = 0; i < nodes.length; i++) { nodes[i].title = nodes[i].name; zTree.updateNode(nodes[i]); } }
第三步:点击搜索按钮时进行搜索
//点击搜索按钮进行模糊匹配 function search() { var keyValue = $("#keyName").val(); autoMatch(keyValue); }
5、点击清空按钮时显示整个树
当用户想改变搜索条件时,可以点击清空按钮重新输入搜索关键字,但是在清空搜索条件后,会还原树
清空按钮:
<a href="#" title="清空" class="btn btn-info btn-sm" onclick="clearKey()"> <span class="glyphicon glyphicon-remove" ></span></a>
清空功能:
/* 点击清空按钮时清除搜索内容并显示初始化树 */ function clearKey() { $("#keyName").val(""); initialTree(); showTree(); setTitle(); inPlaceholder(); } /** * IE9和IE8中实现placeholder属性的功能 * @param inputId */ function inPlaceholder(){ var inputId = "keyName"; var isFocus = $("#"+inputId).is(":focus"); var inputValue = $("#"+inputId).val(); var phContent = $("#"+inputId).attr("placeholder"); var isPlaceholder = "placeholder" in document.createElement("input"); if(!isPlaceholder){ //失去焦点并且input值为空时显示placeholder if(!isFocus){ if(inputValue===""){ $("#"+inputId).val(phContent).css("color","gray"); } } $("#"+inputId).focus(function(){ var inputValue1 = $("#"+inputId).val(); if(inputValue1 && inputValue1==phContent){ $("#"+inputId).val(""); }else{ $("#"+inputId).val(inputValue1); } }); $("#"+inputId).blur(function(){ var inputValue1 = $("#"+inputId).val(); if(inputValue1 == ""){ $("#"+inputId).val(phContent).css("color","gray"); }else{ $("#"+inputId).val(inputValue1); } }); } }
上面的3、4、5步实现了第二个需求,并且在清空搜索条件中有一个inPlaceholder()方法,解决了IE8和IE9不支持H5新特性placeholder属性的问题
6、实现翻页功能
第一步:在每一个内容页创建【上一页】和【下一页】的链接或按钮
<div style="text-align: right;margin-top: 100px;margin-right: 100px;font: 25px;font-weight: bolder;"> <a type="button" href="../cluster/cluster_1.6.html" style="text-decoration: none;" class="lastbtn">上一节</a> <a type="button" href="../viewinfo/viewinfo_2.2.html" style="text-decoration: none;" class="nextbtn">下一节</a> </div>
第二步:给所有页面的上一页和下一页添加id属性
$(".nextbtn").attr("id","nextBtn");
$(".lastbtn").attr("id","lastBtn");
第三步:点击翻页按钮,进行页面跳转
$("#nextBtn").click(function(){ selectNode(this); }) ; $("#lastBtn").click(function(){ selectNode(this); }) ; /** * 调用左边iframe中的选中节点方法 * @param id */ function selectNode(id){ var href = $(id).attr("href"); var start = href.lastIndexOf("/"); if(start!=-1){ href=href.substr(start+1,href.length); } getParent().getNode(href); } function getParent(){ var frames=window.parent.window.document.getElementById("left"); return frames.contentWindow; } /* 读取并选中链接所对应的树节点 */ function getNode(href) { var treeObj = getTree(); var childNodes = treeObj.transformToArray(treeObj.getNodes()); var url, id; for (var j = 0; j < childNodes.length; j++) { url = childNodes[j].url; id = childNodes[j].id; var start = url.lastIndexOf("/"); var urlHref = url.substr(start+1, url.length); if (href == urlHref) { treeObj.selectNode(treeObj.getNodeByParam("id",id, null)); return; } } }
注意:上面的getNode(href)方法是在left.html页面,即在右侧页面的父页面中,所以在内容页面调用该方法时就要用到iframe在子页面获取父页面中元素或方法的方法getParent()
下面是实现翻页并选中对应页面目录的思路:
1、获取翻页链接中最后一个斜杠之后的内容right_href;
2、遍历树节点中的链接,并获取最后一个斜杠之后的内容left_href;
3、对比right_href和right_href,如果相同,则选中该节点;
最后附上一张树的效果图
以上就是这次遇到的问题及解决方法,里面延伸了一些内容,如IE89中不支持placeholder属性的解决方法,自己解决的有点击翻页选中跳转页面的目录,用户输入时进行匹配搜索结果等,
除此之外,其他内容都是关于ztree的部分,zTree中的内容比较多,我这里只是显示,没有涉及到编辑树的内容,所以这部分还需继续学习研究,以后有时间再补充吧,此篇就到这里......