前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >node快速搭建一个学习资料共享平台

node快速搭建一个学习资料共享平台

作者头像
lzugis
发布2023-10-23 09:28:35
1110
发布2023-10-23 09:28:35
举报

概述

本文要实现的功能比较简单:1、将想要共享的文件分文件夹的组织起来;2、别人可以通过界面进行搜索;3、可以在线预览或下载文件。基于这样的需求,本文分享通过node如何实现这样的功能。

实现效果

效果
效果

实现

1. node端服务

node端服务通过express实现,并通过递归,读取目录下的所有文件。实现代码如下:

代码语言:javascript
复制
const express = require('express');
const app = express();
const { listFiles } = require('./utils/file');

app.use(express.static('./www'));

app.get('/files', function (req, res) {
    res.send({
        code: 200,
        data: listFiles('./www/')
    });
});

app.listen(18888, () => {
    console.log('running at http://localhost:18888');
})

listFiles 的实现代码如下:

代码语言:javascript
复制
function listFiles(path, rootPath = "") {
  const items = fs.readdirSync(path);
  const result = [];
  items.forEach((item) => {
    const itemPath = `${path}/${item}`;
    const stat = fs.statSync(itemPath);
    if (stat.isDirectory()) {
      let data = {
        // 文件夹
        type: "folder",
        name: item,
      };
      let children = listFiles(
        itemPath,
        rootPath ? `${rootPath}/${item}` : item
      );
      if (children && children.length) {
        data.children = children;
      }
      result.push(data);
    } else {
      // 文件
      if (item.indexOf("index.html") === -1) {
        result.push({
          type: "file",
          name: item,
          url: rootPath ? `${rootPath}/${item}` : item,
        });
      }
    }
  });
  return result;
}

返回后的数据格式如下:

image.png
image.png

思考:这样的方式, 1. 文件上传不太方便,可以用网盘;2. 当文件数量比较多的时候创建结构树效率比较低。

2. 前端页面

前端页面简单使用VueElement实现,实现代码如下:

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <meta http-equiv="X-UA-Compatible" content="IE=edge" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <title>学习资料</title>
   <!-- 引入样式 -->
   <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
   <!-- 引入组件库 -->
   <script src="https://unpkg.com/vue@2/dist/vue.js"></script>
   <script src="https://unpkg.com/element-ui/lib/index.js"></script>
   <style>
     * {
       margin: 0;
       padding: 0;
     }
     body {
       font-size: 14px;
       overflow: hidden;
     }
     h1 {
       padding: 1rem;
       background-color: #0062ff;
       color: white;
       font-size: 1.2rem;
     }
     .file-tree {
       padding: 1rem;
     }
     .filter-tree {
       margin-top: 1rem;
       height: calc(100vh - 9rem);
       overflow-y: auto;
     }
     .el-tree-node__content {
       height: 2.4rem;
     }
     .tree-text {
       font-size: 0.98rem;
     }
     .slot-t-node-file:hover {
       text-decoration: underline;
     }
   </style>
 </head>
 <body>
   <div id="app" class="container">
     <h1>学习资料</h1>
     <div class="file-tree">
       <el-input
         placeholder="输入关键字进行过滤"
         v-model="filterText"
         clearable
       ></el-input>
       <el-tree
         class="filter-tree"
         :data="filteredFileData"
         default-expand-all
         @node-click="handleNodeClick"
         ref="tree"
       >
         <span slot-scope="{ node, data }" class="slot-t-node" :class="data.type === 'file' ? 'slot-t-node-file' : ''">
           <template>
             <i :class="getIcon(node, data)" class="tree-text"></i>
             <span class="tree-text">{{ data.name }}</span>
           </template>
         </span>
       </el-tree>
     </div>
   </div>
   <script>
     const app = new Vue({
       el: "#app",
       mounted() {
         this.getFileList();
       },
       computed: {
         filteredFileData() {
           const that = this
           if(that.filterText === '') return that.fileData;
           let filter = function (data) {
             let result = []
             data.forEach(d => {
               if(d.children) {
                 const res = filter(d.children)
                 if(res.length > 0) result.push({...d, children: res})
               } else {
                 if(d.name.toLowerCase().indexOf(that.filterText.toLowerCase()) !== -1) result.push(d)
               }
             })
             return result
           }
           return filter(that.fileData)
         },
       },
       data() {
         return {
           filterText: "",
           fileData: [],
         };
       },
       methods: {
         getIcon(node, data) {
           if (data.type === "file") {
             return "el-icon-document";
           } else {
             return node.expanded ? "el-icon-folder-opened" : "el-icon-folder";
           }
         },
         getFileList() {
           const url = `/files`;
           fetch(url)
             .then((res) => res.json())
             .then((res) => {
               this.fileData = res.data;
             });
         },
         handleNodeClick(data, node, component) {
           const { url } = data;
           if (url) window.open(url, "_blank");
         },
       },
     });
   </script>
 </body>
</html>
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-10-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 实现效果
  • 实现
    • 1. node端服务
      • 2. 前端页面
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档