用react和electron实现文件树组件(上)
目录
01.创建react和electron工程
02.实现打开文件夹的功能
03.实现mount前区分是文件夹还是文件
01.创建react和electron工程
创建一个文件夹file-tree-js,进入文件夹,打开终端,输入yarn init -y创建一个javascript项目,这里使用了yarn作为包管理工具,也可以使用nodejs默认安装时自带的npm来创建javascript项目。
输入yarn add react react-dom和yarn add electron -D,安装react和electron,-D表示作为开发依赖安装,开发依赖并不会打包到最终的生产环境中。这里还需要一个打包工具用于将写好的javascript模块进行打包。常见的打包工具有webpack,parcel,rollup等等,这里我使用parcel。
输入yarn add parcel -D安装parcel,同样,parcel作为开发依赖安装到项目中。
创建public和src文件夹,public文件夹用于存放静态资源,src存放js工程的源码。在public文件夹下创建一个index.html,内容如下:
<!DOCTYPE html>
<html lang="zh">
<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>Demo</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="../src/index.jsx"></script>
</body>
</html>
在src文件夹下创建一个index.jsx文件,该文件是该工程的入口文件,内容如下:
import React from 'react';
import ReactDOM from 'react-dom';
function App() {
return <div>hello world</div>;
}
ReactDOM.render(<App />, document.getElementById('root'));
修改package.json文件,内容如下:
{
"name": "file-tree-js",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"type": "module",
"devDependencies": {
"parcel": "^2.0.0",
"electron": "15.3.1"
},
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"scripts": {
"build": "parcel public/index.html"
}
}
然后,在终端中输入yarn build,这条命令对应package.json中scripts下的build语句,可以看到其实是使用了刚刚安装的打包工具对代码进行的打包。
如果一切都没有问题,终端会显示这样一条语句,Server running at http://localhost:1234,此时打开浏览器,在地址栏中输入http://localhost:1234,即可访问代码正在运行的页面,可以看到hello world,如下图所示。
02.实现打开文件夹的功能
在src目录下创建一个main.js文件,该文件用于保存electron部分的代码,如下所示:
const { app, BrowserWindow } = require("electron");
app.on("ready", function () {
let mainWindow = new BrowserWindow({
width: 1440,
height: 900,
minHeight: 270,
minWidth: 400,
show: false,
webPreferences: {
contextIsolation: false,
nodeIntegration: true,
},
});
mainWindow.loadURL("http://localhost:1234");
if (!app.isPackaged) {
mainWindow.webContents.openDevTools();
}
mainWindow.once("ready-to-show", () => {
mainWindow.show();
});
});
app.on("window-all-closed", function () {
app.quit();
});
在终端中输入 electron .,可以看到弹出一个窗口,显示的内容为hello world。
然后我们需要创建一个菜单,这个菜单里面有一个菜单项,用于打开文件夹:
const template= [
{
label: '打开工程',
click: (menuItem, browserWindow) => {
// let structure = {};
const dirPath = dialog.showOpenDialogSync(browserWindow, {
properties: ['openDirectory'],
});
if (dirPath) {
browserWindow.webContents.send('openFolder', dirPath[0]);
}
},
},
];
let menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
再次运行electron .可以看到窗口的菜单栏中有一个菜单。
点击该菜单,electron打开一个窗口,用于选择文件夹,点击确定后,electron进程会从主进程发送一条信息到渲染进程,渲染进程接收到主进程发来的信息后,便可着手准备之后的工作了。
03.实现mount前区分是文件夹还是文件
我们的组件需要知道它自己代表的是文件夹还是文件,这个动作需要在它被渲染到页面上之前就完成,所以我通过if else语句来判别组件是文件夹组件还是文件组件,如果是文件夹组件,该组件就有许多个子组件,子组件中又包括了文件夹组件和文件组件,并且点击该组件时还要渲染它的子组件;如果是文件组件,那么该组件只需要关心其本身就可以了。
我们可以通过nodejs的fs模块实现读取路径,并判断该路径是文件夹还是文件:
const fs = require(‘fs’);
let stats = fs.statsSync(dir);
If(stats.isDirectory()) {
} else if(stats.isFile()) {
}
这样就可以辨别是文件组件还是文件夹组件,并通过不同的节点渲染到页面上:
const TreeItem = ({ filePath }: { filePath: string }) => {
let fileStat = fs.statSync(filePath);
let isFolder = fileStat.isDirectory();
let isOpen = useRef<boolean>(false);
let folderDiv = useRef<HTMLDivElement>(null);
const [children, setChildren] = useState([]);
const [selected, setSelected] = useState<boolean>(false);
const itemRef = useRef<HTMLDivElement>(null);
if (isFolder) {
return (
<>
<div
title={filePath}
style={{ background: selected && '#6ab2fb' }}
ref={folderDiv}
className="folder tree-item"
onClick={(e) => {
e.stopPropagation();
if (!e.ctrlKey) {
mainStore.selection.forEach((func, k) => {
func(false);
});
mainStore.selection.clear();
if (isOpen.current) {
isOpen.current = false;
folderDiv.current.classList.remove('open');
} else {
let files = fs.readdirSync(filePath).filter((item) => {
let stat = fs.statSync(path.join(filePath, item));
return path.extname(item) === '.c' || stat.isDirectory();
});
setChildren(files);
isOpen.current = true;
folderDiv.current.classList.add('open');
}
}
if (!selected) {
setSelected(true);
mainStore.selection.set(filePath, setSelected);
} else {
setSelected(false);
mainStore.selection.delete(filePath);
}
}}>
{path.basename(filePath)}
</div>
<ul>
{children.length !== 0 &&
children.map((child) => {
let childPath = path.join(filePath, child);
return (
<li key={childPath}>
<TreeItem filePath={childPath} />
</li>
);
})}
</ul>
</>
);
} else {
return (
<div
className="tree-item"
ref={itemRef}
style={{ background: selected && '#6ab2fb' }}
data-extension={path.extname(filePath)}
title={filePath}
onClick={(e) => {
codeFileStore.setCurrentSelectedFile(filePath);
if (!e.ctrlKey) {
mainStore.selection.forEach((func, k) => {
func(false);
});
mainStore.selection.clear();
}
if (!selected) {
setSelected(true);
mainStore.selection.set(filePath, setSelected);
} else {
setSelected(false);
mainStore.selection.delete(filePath);
}
}}>
{path.basename(filePath)}
</div>
);
}
};
用react和electron实现文件树组件(上)相关推荐
- react 树形菜单_react使用antd组件递归实现左侧菜单导航树
/** 左侧导航组件*/import React, { Component }from 'react'import { Link, withRouter }from 'react-router-dom ...
- 学习使用React和Electron一次构建自己的桌面聊天应用程序
by Alex Booker 通过亚历克斯布克 学习使用React和Electron一次构建自己的桌面聊天应用程序 (Learn to build your own desktop chat app ...
- React简介、虚拟DOM、Diff算法、创建React项目、JSX语法、组件、组件声明方式、组件传值props和state、组件的生命周期
React简介: 前面只是简单介绍移动APP开发,后面还会继续深入介绍移动app开发:其中想要用ReactNative开发出更出色的应用,那么就得学好React,下面将介绍React: React 是 ...
- php easyui tree 结构,EasyUI Tree树组件无限循环的解决方法
在学习jquery easyui的tree组件的时候,在url为链接地址的时,发现如果最后一个节点的state为closed时,未节点显示为文件夹,单击会重新加载动态(Url:链接地址)形成无限循环. ...
- [react] 说说你对“在react中,一切都是组件”的理解
[react] 说说你对"在react中,一切都是组件"的理解 React采用组件化的思想,最小的组件单位就是原生HTML元素,采用JSX的语法声明组件的调用 React的虚拟DO ...
- react实现异步插件_React-loadable实现组件进行异步加载
React 项目打包时,如果不进行异步组件的处理,那么所有页面所需要的 js 都在同一文件中(bundle.js),整个js文件很大,从而导致首屏加载时间过长.所有,可以对组件进行异步加载处理,可以使 ...
- HT for Web的HTML5树组件延迟加载技术实现
HT for Web的HTML5树组件有延迟加载的功能,这个功能对于那些需要从服务器读取具有层级依赖关系数据时非常有用,需要获取数据的时候再向服务器发起请求,这样可减轻服务器压力,同时也减少了浏览器的 ...
- 组件分享之后端组件——用于将日志写入滚动文件的组件包lumberjack
组件分享之后端组件--用于将日志写入滚动文件的组件包lumberjack 背景 近期正在探索前端.后端.系统端各类常用组件与工具,对其一些常见的组件进行再次整理一下,形成标准化组件专题,后续该专题将包 ...
- web前端高级React - React从入门到进阶之组件的懒加载及上下文Context
第二部分:React进阶 系列文章目录 第一章:React从入门到进阶之初识React 第一章:React从入门到进阶之JSX简介 第三章:React从入门到进阶之元素渲染 第四章:React从入门到 ...
最新文章
- r语言ggplot怎么把多个维度数据合并在一个图中表示_R语言作图——Histogram
- JavaScript的格式--从格式做起,做最严谨的工程师
- 【Leetcode | 02】二叉树、线性表目录
- javamail发送邮件的简单实例
- GNS3桥接modem拨号and QOS限速
- Jenkins配置MSBuild时使用环境变量
- kali linux 数据源,kali Linux msf5 连接数据库 No database support
- SpringCloud学习笔记029---在SpringCloud项目中使用Zuul实现基本的网关统一处理
- Checkpointing
- 写一个方法,用一个for循环打印九九乘法表
- 布局文件是如何被解析的?
- spring mvc 页面跳转 携带数据的两种方式
- 设计模式-第七篇之门面模式
- springboot分页展示功能_SpringBoot实战项目(三)用户列表以及分页功能实现
- 《现代控制系统》第五章——反馈控制系统性能分析 5.4 二阶系统里面极点以及零点带来的影响
- Matlab图例legend换行
- 个性时钟屏保=冷高轮时间麻将时钟电脑屏幕保护
- opencv学习十三:图像金字塔和图像梯度
- 腾讯云函数转华为云函数
- 伯努利分布、二项分布和多项分布
热门文章
- qt 进程打开excel_Python干货:多进程与多线程!
- faspeed是什么意思_speed是什么意思_speed的翻译_音标_读音_用法_例句_爱词霸在线词典...
- python垃圾回收 循环引用_在做 Python 循环引用垃圾回收实验中的一个小问题, Python3 的 print 是线程安全的吗?...
- 泛函分析——步尚全老师第四章课后题答案往年题
- uinty粒子系统子物体变大_新Unity 最新粒子系统如何用代码改变参数
- usb升级linux固件,Linux USB驱动(4)---CY68013固件加载驱动
- java输出重定向gui_Java – 将system.out.println重定向到JLabel
- ArcGIS GeoDataBase GeoDataset dataset
- endnote一打开就自动关闭_【EndNote文献管理】5分钟快速上手Endnote
- 角度控制_手机拍剪影,选择拍摄角度,还要控制画面亮度