上一篇讲到菜单:
手写jquery生成无限极的菜单https://blog.csdn.net/qq_50145597/article/details/137338101?spm=1001.2014.3001.5502
这一次改成文件夹菜单,效果图如下:
Java对象和后端传入数据可以去看上一篇文章开头就是
css:
<style type="text/css">
li{
margin-left: 10%;
list-style-type: none;
/*disclosure-closed*/
}
.opr-span{
width: 20%;
}
.opr li{
display:inline-block;
}
.opr{
width: 100px;
position: absolute;
}
.new-li{
font-size: 60%;
width: 125%;
}
.menu-li{
margin: 2%;
}
html:
<div class="parent">
<ul class="parent_ul" style="background-color: whitesmoke; width: 20%"></ul>
</div>
<ul class="opr">
<!--添加文件的按钮-->
<li><span class="opr-span glyphicon glyphicon-file" id="file"></span></li>
<!--添加文件夹的按钮-->
<li><span class="opr-span glyphicon glyphicon-folder-close" id="folder"></span></li>
</ul>
html主要写了两个部分,第一个是菜单div。第二个是一个创建文件和文件夹的按钮。
整体的js:
var $opr = $(".opr");
$(function (){
$opr.hide();
init();
closeAndOpen();
// $("ul li .menu-ul").hide();
});
/**
* 开光
*/
function closeAndOpen(){
let _this;
var $body = $("body");
var $oprli = $(".opr li");
$body.on("click contextmenu","li span",function (e) {
var children = $(this).parent().children(".menu-ul");
if (e.type==="click" ){
children.toggle(500);
e.stopPropagation();
$(this).toggleClass(function (){
if ($(this).is("glyphicon-folder-close")){
return "glyphicon-folder-close";
}
return "glyphicon-folder-open";});
}
if (e.type==="contextmenu" && !($(this).hasClass("glyphicon-file")) &&!($(this).hasClass("opr-span"))){
//console.log($(this).attr("class"))
e.preventDefault();
var position = $(this).offset();
$opr.css({
top:position.top+"px",
left:(position.left*(1.1))+"px"
}).fadeIn(100);
// console.log(children.attr('class'));
_this=$(this);
$(document).one("click", function(){
$opr.hide();
});
e.stopPropagation();
}
});
$oprli.on("click",function () {
console.log($(this).attr("id"))
if ($(this).attr("id")==="file"){
//console.log( _this.parent("li").html())
var childrens = _this.parent("li").children("ul>li");
_this.parent().children("ul").append("<li><input class='new-li' value='新建文件夹'"+childrens.length+"/><span class='new-li-delete'>-</span></li>");
}
});
$body.on("click","new-li-delete",function () {
console.log($(this))
$(this).parent("li").remove();
alert($(this))
});
}
/**
* 初始化函数
*/
function init(){
$(".parent>ul>li>ul").remove();
$.ajax({
url: '/test/array',
type: 'GET',
dataType: 'json',
}).done(function (data) {
if (data.rs) {
var res = data.data;
var h1 = "<li>菜单";
h1 =ul(res,h1);
h1+="</li>";
$(".parent>ul").append(h1);
$("ul li .ul-close1").hide();
}
}).fail(function () {
});
}
/**
* 递归菜单
* @param arry
* @param h1
* @returns {*}
*/
var a1;
var a2;
var className;
var childFlag = 0;
var ulCloseClass = "";
function ul(arry){
if (arry.length===""){
return "";
}
if (arry.length===0){
return "";
}
ulCloseClass = (childFlag===0)?"":" ul-close1";
var h1="<ul class='menu-ul "+ulCloseClass+ "'>";
arry.forEach(item=>{
a1 = (item.url!==null&&item.child.length===0)?"<a href='"+item.url+"'>":"";
a2 = (item.child.length===0)?"</a>":"";
className = item.child.length!==0?"glyphicon glyphicon-folder-close":"glyphicon glyphicon-file";
h1+="<li class='menu-li'>"+a1+"<span class='menu-span "+className+"'" +
"style=' background-image: url("+item.backgroundImage+"')\">"+item.name+"</span>";
if (item.child.length!==0){
childFlag = 1;
var child = item.child;
h1+=ul(child);
childFlag =0;
}
h1+=(a2)+"</li>";
})
h1+="</ul>";
return h1;
}
js也就是想到哪儿写到哪儿,比较繁杂,毕竟不是前端出生,望请谅解。
解析js:
var $opr = $(".opr");
$(function (){
$opr.hide();
init();
closeAndOpen();
});
加载js
执行事件{
1.隐藏创建文件夹和文件的按钮;
2.初始化;
3.监听文件<li>标签鼠标点击事件;
}
没啥技术和坑点;
function init(){
var h1 = "<li>菜单";
h1 =ul(data,h1);
h1+="</li>";
$(".parent>ul").append(h1);
$("ul li .ul-close1").hide();
}
初始化函数
注意data是上一篇中的后端传入的data json数据。关闭子菜单。也没啥坑点
/**
* 递归菜单
* @param arry
* @param h1
* @returns {*}
*/
var a1;
var a2;
var className;
var childFlag = 0;
var ulCloseClass = "";
function ul(arry){
if (arry.length===""){
return "";
}
if (arry.length===0){
return "";
}
ulCloseClass = (childFlag===0)?"":" ul-close1";
var h1="<ul class='menu-ul "+ulCloseClass+ "'>";
arry.forEach(item=>{
a1 = (item.url!==null&&item.child.length===0)?"<a href='"+item.url+"'>":"";
a2 = (item.child.length===0)?"</a>":"";
className = item.child.length!==0?"glyphicon glyphicon-folder-close":"glyphicon glyphicon-file";
h1+="<li class='menu-li'>"+a1+"<span class='menu-span "+className+"'" +
"style=' background-image: url("+item.backgroundImage+"')\">"+item.name+"</span>";
if (item.child.length!==0){
childFlag = 1;
var child = item.child;
h1+=ul(child);
childFlag =0;
}
h1+=(a2)+"</li>";
})
h1+="</ul>";
return h1;
}
这个递归函数升级了下,a1,a2都代表根据url是否生成a标签。ulCloseClass,ulCloseClass标记子文件ul,方便初始化时关闭子菜单。childFlag 是辅助标记为子文件的变量,初始为0,发动子文件递归调动时childFlag为1,结束复位为0.className确定确定是否为文件夹或者为文件,写上不同的图标(glyphicon glyphicon-folder-close和glyphicon glyphicon-file)制作好html后返回出去。
/**
* 开光
*/
function closeAndOpen(){
let _this;
var $body = $("body");
var $oprli = $(".opr li");
$body.on("click contextmenu","li span",function (e) {
var children = $(this).parent().children(".menu-ul");
if (e.type==="click" ){
children.toggle(500);
e.stopPropagation();
$(this).toggleClass(function (){
if ($(this).is("glyphicon-folder-close")){
return "glyphicon-folder-close";
}
return "glyphicon-folder-open";});
}
if (e.type==="contextmenu" && !($(this).hasClass("glyphicon-file")) &&!($(this).hasClass("opr-span"))){
//console.log($(this).attr("class"))
e.preventDefault();
var position = $(this).offset();
$opr.css({
top:position.top+"px",
left:(position.left*(1.1))+"px"
}).fadeIn(100);
// console.log(children.attr('class'));
_this=$(this);
$(document).one("click", function(){
$opr.hide();
});
e.stopPropagation();
}
});
$body.on("click","new-li-delete",function () {
console.log($(this))
$(this).parent("li").remove();
alert($(this))
});
}
开关函数
委托函数on,监听对象li标签中的span模块,执行两个函数(click 和contextmenu)。鼠标左键(click)单击时出现文件的开启和闭合,toggle函数负责关闭和开启子文件夹和文件,toggleClass负责改变图标文件夹的样式(开合),如下图
鼠标右击(contextmenu)文件夹时,会出现新建文件和文件夹的图标
后面两个判断是为什么呢?那是因为文件不具有创建文件和文件夹的功能,这是文夹特有的功能。即鼠标右点击文件时,不会产生创建文件和文件夹的图标。还有一个是因为创造文件文件夹的span,不去判断这个span就会去偏移,对于位置问题,我觉得$(this).offset()比较好用,我看很多博主推荐event.target().left和top,我这里感觉不是很好用,因为这个事件点击span位置会不断变化,因为span标签是有一定的范围,不好控制,所以用了$(this).offset()确定位置。底下则是定位和执行一次解绑one函数,作用就是点击其他地方时,这个创建的图标就会消失。其他的函数上一篇也有说到,就不过多赘叙了。都看到这里了,不点个关注?
总结:
总体写起来还是挺麻烦的,还是一个动态dom确定。工作时我当然优先选择一些框架直接执行,但学习的话,感觉底层还是更好一点。好比说,隐藏在js中是display:none;而jquery直接hide()。有什么想法发表在评论区,大家一起探讨一下。
打赏
创作不易,打赏鼓励(zfb)