1、前端小练习(一)-------- 实现网页端的文件资源管理器

JS实现资源管理器功能介绍:


内容目录:

  • 效果图
  • 界面介绍
  • 实现原理
  • 总结

网页效果图


image

界面介绍


整个页面比较简单,主要有两个部分组成,

分别是:左边显示文件夹层级目录、右边显示文件内容的显示区域。

实现原理


技术:html+CSS+JS(+JQuery)

组件: 图标样式库 css文件;
解析markdown文件

  <link rel="stylesheet" href="../css/all.min.css">
 	<script src="../js/marked.min.js" type="module"></script>

根据上面的页面介绍我们将页面大致分为两个部分:文件夹层级显示区域、文件内容显示区域

直接上代码:

<body>
        <!--显示文件层级目录结构-->
        <div id="showFolder">
            <!-- 标题栏显示区域 -->
            <div id="showTitle">
                <i class="fa fa-bars" style="margin-left: 10px;"></i>
                <div class="titleText" style="margin-left: 10px;">资源管理器</div>
            </div>
            <!--文件夹层级显示管理-->
            <div class="folderMenu">
                <!--打开文件按钮-->
                <button id="openFolder">打开文件夹</button>
            </div>
        </div>
        <!--显示文本区域-->
        <div id="showTxt">
            <div class="showTxt_Title">
                <!--扩大显示文件内容的图标-->
                <i class="fa fa-expand"></i>
            </div>
            <!--文件内容主要显示区域-->
            <div class="showTxt_Content"></div>
        </div>
</body>

因为个人原因给初始页面只是加载两个小按钮,需要点击按钮后进行扩展,下面我直接贴上CSS代码

*{
    margin: 0;
    padding: 0;
}

body{
    position: fixed;
    width: 100%;
    height: 100%;
    background: url("../image/background/personage.jpg")no-repeat;
    background-size: cover;
}

/*开始整体框架进行搭建*/


/*首先是左边的资源管理器界面端*/
/*这边进行做一个动画效果*/
#showFolder{
    width:50px;
    height: 50px;
    border-radius: 10px;
    background: rgba(0,0,0,.3);
    color: white;
    user-select: none;
    transition: width 1s,height 1s;
    overflow: hidden;
}
/*左边上面的标题部分*/
#showFolder #showTitle{
    width: 100%;
    height:50px;
    display: flex;
    font-size: 20px;
    align-items: center;
    overflow: hidden;
}

#showTitle:hover{
    cursor: pointer;
}

#showFolder .titleText{
    width: calc(100% - 50px);
    display: none;
}
/*下面的层级目录的显示修饰部分*/
#showFolder .folderMenu{
    margin-top: 10px;
    width: 100%;
    height: calc(100% - 60px);
    transition: height 1s;
    text-align: center;
    display: none;
    overflow-y: visible;
    overflow-x:hidden ;
}

/*打开文件按钮的修饰*/
#showFolder .folderMenu Button{
    border-radius: 3px;
    border-style: none;
    text-align: center;
    padding: 3px;
    width: 98%;
    background: #4158D0;
    color: white;
}

/* 下面我们需要对文件资源管理器进行修饰管理 */
.folderMenu .folder,.folderMenu .file{
    width: 230px;
    height: 28px;
    display: flex;
    align-items: center;
    overflow: hidden;
    font-size: 14px;
}

.folderMenu .folder:hover,
.folderMenu .file:hover{
    cursor: pointer;
    color:#FFE4C4;
}
.folderMenu .file .fileName{
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
}

.folderMenu .childen_Area{
    margin-left: 20px;
    overflow: hidden;
}
/*右边文件内容显示区域*/
#showTxt{
    color: white;
    font-size: 20px;
    position: fixed;
    top: 0;
    right: 0;
    width: 50px;
    height: 50px;
    border-radius: 20px;
    background: rgba(0,0,170,.3);
    transition: height 1s,width 1s;
}
/*右边文件内容显示区域中标题栏*/
#showTxt .showTxt_Title{
    position: fixed;
    top: 0px;
    right: 0px;
    user-select: none;
    width: 50px;
    height: 50px;
    text-align: center;
    line-height: 50px;
}
/*文件内容显示区域中主体部分*/
#showTxt .showTxt_Content{
    margin: 60px 10px 5px 30px;
    width: calc(100% - 40px);
    height: calc(100% - 65px);
    overflow-y: auto;
    font-family: "华文宋体";
}

JS部分,主要讲一下主要实现思路:

1、首先是用户点击按钮,触发事件。
2、然后JS通过异步调用 window.showDirectoryPicker()函数,获得到选中的文件夹的句柄(handle)
3、创建一个异步函数进行处理这个句柄 (我自己命名)processHandle(handle, Elem),分别有两个参数,分别是需要传递的句柄,需要向某个元素添加内容(也就是需要显示在哪块区域中)。
4、在processHandle(handle, Elem)中我们需要做的事情有下面两个:
~ 通过entires()函数,获取一个异步迭代器
~ 然后就需要遍历这个迭代器(这个时候我们获取的是我们选择的文件夹中子文件以及子文件夹),通过判断迭代器中每个元素中kind属性,进行判断该元素是文件(同时创建文件图标以及显示文件名)还是文件夹(同样的创建下拉图标、文件夹图标以及显示文件夹名字);
5、创建文件图标的函数creatElem_File(root,Elem) :root是当前文件夹句柄,Elem是当前文件夹所对应的document的元素

  • 首先创建外面的div进行包裹着整个边框
  • 创建 用来显示文件图标
  • 创建一个div显示文件名字
  • 然后将2和3添加到1中
  • 最后将1添加到参数Elem中
  • 创建对应的点击事件(点击事件是load线程中,而之前访问夹是异步线程)

6、创建文件夹图标的函数 creatElem_Folder(root,Elem):root是当前文件夹句柄,Elem是当前文件夹所对应的document的元素

  • 首先创建外面的div进行包裹着整个边框
  • 创建 用来显示下拉图标
  • 创建 用来显示文件夹图标
  • 创建一个div显示文件名字
  • 需要将2和3添加到1中
  • 然后将1添加到参数Elem中
  • 我们需要再次调用processHandle(handle, Elem)函数,形成递归过程,达到遍历每一个文件夹的目的
  • 创建对应的点击事件(点击事件是load线程中,而之前访问夹是异步线程)

下面就是展示JS代码:

window.onload=async () => {
    // fa-bar图标的点击事件
    $("#showTitle").click(showTitle_Click);

    // 打开文件夹的点击事件
    $("#openFolder").click(await openFolder_Click);

    // 点击expand图标后显示文本区域
    $("#showTxt .showTxt_Title .fa").click(expandICON_Click);
}

// 区域动画展示效果函数
function showTitle_Click() {
    /* 主要是做一个动画效果 */
    const showFolder=$("#showFolder")[0];
    const titleText= $(".titleText")[0];
    const folderMenu=$("#showFolder .folderMenu")[0];
    if(showFolder.clientWidth==50){
        showFolder.style.width="200px";
        showFolder.style.height="100%";

        setTimeout(()=>{titleText.style.display="block";
            folderMenu.style.display="block";
            folderMenu.style.height="calc(100% - 60px)";
            },800);
    }else{
        // 返回到原来的样式
        showFolder.style.width="50px";
        showFolder.style.height="50px";
        titleText.style.display="none";
        folderMenu.style.height="0px";
    }

}

/**
 * 打开文件夹按钮响应事件
 * @returns {Promise<void>}
 */
async function openFolder_Click(){
    try{
        const handle=await window.showDirectoryPicker();
        const folderMenu=$(".folderMenu")[0];
        $("#openFolder")[0].style.display="none";
        // 然后将handle交给专门的函数进行处理
        await processHandle(handle,folderMenu);
    }catch (e){
        console.log(e)
    }
}

/**
 * 处理获取本地文件的句柄,运用递归的方式进行遍历旗下所有的子文件以及子目录
 * @param handle
 * @param Elem
 * @returns {Promise<void>}
 */
async function processHandle(handle, Elem) {
    const iter = handle.entries();
    for await (const item of iter) {
        if (item[1].kind == "file") {
            creatElem_File(item[1], Elem);
        } else {
            creatElem_Folder(item[1], Elem);
        }
    }
    return;
}

function creatElem_File(root,Elem) {
    // 首先是创建外面包裹的标签
    let facting_File=document.createElement("div");
    facting_File.className="file";
    facting_File.style.marginLeft="10px";
    /*
        1、文件图标包括:图标+文件名
        2、创建每一个文件点击响应事件
     */
    // 创建文件夹图标节点
    let file_ICON=document.createElement("i");
    file_ICON.className="file_ICON fa fa-file";
    let file_Name=document.createElement("div");
    file_Name.className="fileName";
    file_Name.style.marginLeft="5px";
    file_Name.prepend(root.name);
    facting_File.appendChild(file_ICON);
    facting_File.appendChild(file_Name);
    Elem.appendChild(facting_File);

    // 创建每个文件的对应的点击事件
    facting_File.onclick=()=>{
        // 从支线线程转到加载线程 此时调用异步线程中对象会包裹成promise对象
        const showTxt=$("#showTxt")[0];
        const showTxt_Content=$("#showTxt .showTxt_Content")[0]
        if(showTxt.clientWidth<=60){
            // 首先调用文本区域的显示函数
            expandICON_Click();
        }
        let promise=root.getFile();
        // 这边读取时是需要进行分类解析的
        /* 首先是创建几个正则表达式,用来检测是否是对应的文件
        */

        const  reg=/(.csv|.txt)$/m
        const  reg1=/(.md)$/m;
        const  reg2=/(.jp[e]g|.png)$/m;

        const reader=new FileReader();
        promise.then(result=>{
          // 然后进入promise对象处理异步线程中进行分门别类进行读取文件
           if(reg.test(result.name)){
                console.log("读取文件");
                reader.readAsText(result,"utf-8");
                reader.onload=(evt)=>{
                    showTxt_Content.innerHTML=evt.target.result;
                }
            }
            if(reg1.test(result.name)){
                console.log("读取markdown文件");
                reader.readAsText(result,"utf-8");
                reader.onload=(evt)=>{
                    showTxt_Content.innerHTML=marked.parse(evt.target.result);
                }
            }

            if(reg2.test(result.name)){
                console.log("读取二进制文件")
                reader.readAsDataURL(result);
                reader.onload=(evt)=>{
                    showTxt_Content.innerHTML="";
                    let image=document.createElement("img");
                    image.style.width="95%";
                    image.style.height="80%";
                    image.style.margin=" 0 auto";
                    image.src=evt.target.result;
                    console.log(evt.target.result);
                    showTxt_Content.appendChild(image);
                }
            }
        });
    }
}

function creatElem_Folder(root,Elem){
    /*
        1、创建文件夹层级包含:箭头、文件夹图标、文件名
        2、创建子级隐藏的区域,并且调用process函数进行遍历文件夹层级
     */
    // 这是创建外面包裹的边框
    let facting_Folder=document.createElement("div");
    facting_Folder.className="folder";
    // 创建下拉箭头
    let xiala=document.createElement("i");
    xiala.className="xiala fa fa-circle-chevron-right"
    xiala.style.marginLeft="5px";
    // 创建文件夹图标
    let folder_ICON=document.createElement("i");
    folder_ICON.className="folder_ICON fa fa-folder-closed";
    folder_ICON.style.marginLeft="5px";
    // 创建文件夹名字显示区域
    let folder_Name=document.createElement("div");
    folder_Name.append(root.name);
    folder_Name.style.marginLeft="5px";

    facting_Folder.appendChild(xiala);
    facting_Folder.appendChild(folder_ICON);
    facting_Folder.appendChild(folder_Name);
    Elem.appendChild(facting_Folder);
    // 然后我们需要创建专门的区域来显示子层级目录
    let childen_Area=document.createElement("div");
    childen_Area.className="childen_Area";
    childen_Area.style.display="none";
    Elem.appendChild(childen_Area);
    processHandle(root,childen_Area);

    // 我们还需要创建对应文件夹打开响应事件
    facting_Folder.onclick=()=>{
        if(childen_Area.style.display=="none"){
            // 首先是将下拉图标的方向进行更换
            xiala.className="xiala fa fa-circle-chevron-down";
            folder_ICON.className="folder_ICON fa fa-folder-open";
            // 然后将这个子层级显示出来
            childen_Area.style.display="block";
        }else{
            xiala.className="xiala fa fa-circle-chevron-right";
            folder_ICON.className="folder_ICON fa fa-folder-closed";
            // 然后将这个子层级显示出来
            childen_Area.style.display="none";
        }
    }
}

// 显示文本区域动画过度效果
function expandICON_Click() {
    const showTxt=$("#showTxt")[0];
    if(showTxt.clientWidth<=70){
        showTxt.style.width="calc(100% - 200px)";
        showTxt.style.height ="100%";
    }else{
        showTxt.style.width="50px";
        showTxt.style.height ="50px";
    }
}

总结


主要自己从想出概念,到找到思路然后确定思路(中间花费很多时间),然后到代码落地碰到很多困难。也是幸运地能够实现自己想出来的概念。我自己是从CSDN、博客园以及抖音中无意中看到推荐视频,刚好看到该知识点的视频,解决我自己碰到的问题,幸运儿。

posted @   什么都会有的  阅读(866)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示