创建文件系统文件夹浏览器

在开发网页应用时,经常需要为用户提供一个界面,让他们能够浏览文件系统并选择文件夹进行操作,比如备份。本文将介绍如何利用Bootstrap Treeview插件,快速实现一个简单的文件夹浏览器。

不久前,遇到了一个编码需求,需要为一个网页应用实现文件系统文件夹浏览器的功能。用户需要能够选择一个文件夹,以便将其备份到另一个位置。在寻找解决方案的过程中,发现了Bootstrap Treeview,这是一个简单易用且与项目风格一致的插件。

Bootstrap Treeview的初步设置

要将Bootstrap Treeview包含到项目中,首先需要下载或安装它,并在视图(或布局页面)中引用相应的脚本和样式。Bootstrap Treeview可以通过npm和bower安装,或者直接从GitHub克隆或下载整个仓库。选择将所需的文件放置在wwwroot/lib/bootstrap-treeview目录下,以便服务。

样式和脚本引用

在开发环境中,通常会使用非压缩版本的文件,以便调试。以下是开发环境中样式的引用方式:

<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css">
<link rel="stylesheet" href="~/css/site.css">
<link href="~/lib/bootstrap-treeview/bootstrap-treeview.min.css" rel="stylesheet">

在非开发环境中,会使用所有样式表的压缩版本(如果可用)。

以下是开发环境中脚本的引用方式:

<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/lib/bootstrap-treeview/bootstrap-treeview.min.js"></script>

通常,也会在开发中使用非压缩版本的脚本,除非不可用。

容器视图和脚本

在视图中放置一个容器和脚本,理想情况下是一个div,其中TreeView将出现:

<div id="tree"></div>
function getTree() {
    // 一些逻辑来检索或生成树结构
    return data;
}
$('#tree').treeview({data: getTree()});

获取数据是Bootstrap Treeview的一个关键步骤,因为它需要在初始化TreeView之前准备好树形图数据。每个节点的最基本数据结构只有两个属性:Text是文件夹的名称,Nodes是该文件夹子节点的集合。

Ajax回调

由于必须在初始化控件之前拥有数据,可以在jQuery Ajax方法的done回调中初始化treeview:

$.ajax("@Url.Action("TreeData", "TreeView")")
    .done(function(resp) {
        $("#bsTree").treeview({
            data: resp
        });
    })
    .fail(function(error) {
        console.log(error);
    });

简化节点类TreeNode旨在表示一个树节点,它是节点对象完整规范的很小一部分。由于无法在在线示例中看到除了‘+’和‘-’以外的任何图标,所以选择完全省略图标属性,以保持事情尽可能小而整洁。

TreeNode类

使用这种节点结构,TreeView的JSON响应可能如下所示:

[ { "text": "Folder1", "nodes": [] }, { "text": "Folder2", "nodes": [ { "text": "FolderB", "nodes": [ { "text": "FolderOne", "nodes": [] } ] } ] }, { "text": "Logs", "nodes": [] } ]

TreeView需要一个递归数据结构(JSON)来表示整个文件夹树,因为该控件不支持延迟加载或初始加载之外的任何Ajax。因此,它需要一次性获得所有数据。发现这令人不安,因为文件系统上的嵌套非常普遍,深度未知,构建和传输巨大的JSON文档只会损害性能。

控制器

以下是实现所需递归的控制器代码:

public class TreeViewController : Controller
{
    private FileTreeConfig _config;
    public TreeViewController(IOptions<FileTreeConfig> config)
    {
        _config = config.Value;
    }
    public IActionResult TreeData(string dir = "")
    {
        var browsingRoot = Path.Combine(_config.BaseDir, dir);
        var nodes = new List<TreeNode>();
        nodes.AddRange(RecurseDirectory(browsingRoot));
        return Json(nodes);
    }
    private List<TreeNode> RecurseDirectory(string directory)
    {
        var ret = new List<TreeNode>();
        var dirInfo = new DirectoryInfo(directory);
        try
        {
            var directories = dirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly);
             foreach (var dir in directories)
             {
                if (dir.FullName.ToLower() == dirInfo.FullName)
                    {
                       continue;
                      }
                 var thisNode = TreeNode.FromDirInfo(dir);
                 thisNode.Nodes.AddRange(RecurseDirectory(dir.FullName));
                 ret.Add(thisNode);
             }
        }
        catch (UnauthorizedAccessException ux)
        {
            // NB Log.
        }
        return ret;
    }

以上代码清晰地展示了如何递归地遍历目录结构,并将其转换为TreeNode对象的列表,然后返回JSON格式的数据。

浏览根目录

使用这种仅支持递归的treeview,不希望用户导航到文件系统的根目录,并让代码递归遍历所有内容。设置一个浏览根目录,限制用户不能浏览超出某个文件系统文件夹,是一个理想的做法。虽然他们可以使用相对路径,但检查这些路径的复杂性超出了这个简单练习的范围。

有一个名为BaseDir的配置设置,它是treeview必须开始的根目录的路径。控制器代码中的Path.Combine帮助建立这个根目录。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485