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


    概述

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

    实现效果

    效果

    实现

    1. node端服务

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

    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');
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    listFiles 的实现代码如下:

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    返回后的数据格式如下:
    image.png

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

    2. 前端页面

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

    <!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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
  • 相关阅读:
    太顶了,腾讯 T4 资深架构师梳理的 Java 核心宝典(框架 + 原理 + 笔记)
    WordPress供求插件API文档:用户登录
    ES中SQL查询详解
    tmux 命令快速入门
    LNMP网站框架搭建(编译安装的方式)
    特性介绍 | MySQL 测试框架 MTR 系列教程(一):入门篇
    Svn常见问题分析及解决方案
    java毕业生设计养老院信息管理计算机源码+系统+mysql+调试部署+lw
    【chat】3: ubutnu 安装mysql-8
    AI市场的资本谜团与流向
  • 原文地址:https://blog.csdn.net/GISShiXiSheng/article/details/133965463