在window、mac、linux系统中,他们都有一个共同之处就是以文件夹的形式来组织文件的。并且都有各自的组织方式,以及都有如何查询和显示哪些文件给用户的方法。那么从现在开始我们来学习下如何使用Electron来构建文件浏览器这么一个应用。

注意:我也是通过看书,看资料来学习的。这不重要,重要的是我们学到东西。我们知道如何使用 electron 来做一个桌面型应用软件。有这些知识点后,以后我们做其他的桌面型应用软件会有基础。

那么既然是文件浏览器,那么我们可以给文件浏览器取一个名字,假如叫他为 FileBrowser. 那么该文件浏览器要具备如下功能:

1. 用户可以浏览文件夹和查找文件。
2. 用户可以使用默认的应用程序打开文件。

Electron应用它是以一个js文件作为入口文件的,所以呢我们需要和之前一篇文章讲的一样,我们需要看下有如下目录结构:

|------- FileBrowser
| |--- main.js
| |--- index.html
| |--- package.json

package.json 目前的代码如下:

{
"name": "electron-filebrowser",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

main.js 基本代码如下(和第一篇文章的实现hello world代码是一样的):

'use strict';

// 引入 全局模块的 electron模块
const electron = require('electron'); // 创建 electron应用对象的引用 const app = electron.app;
const BrowserWindow = electron.BrowserWindow; // 定义变量 对应用视窗的引用
let mainWindow = null; // 监听视窗关闭的事件(在Mac OS 系统下是不会触发该事件的)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
}); // 将index.html 载入应用视窗中
app.on('ready', () => {
/*
创建一个新的应用窗口,并将它赋值给 mainWindow变量。
*/
mainWindow = new BrowserWindow(); // 载入 index.html 文件
mainWindow.loadURL(`file://${__dirname}/index.html`); // 当应用被关闭的时候,释放 mainWindow变量的引用
mainWindow.on('closed', () => {
mainWindow = null;
});
});

然后我们的index.html 代码如下:

<html>
<head>
<title>FileBrowser</title>
</head>
<body>
<h1>welcome to FileBrowser</h1>
</body>
</html>

然后我们在项目的根目录下 运行 electron . 命运,即可打开应用窗口,如下所示:

现在我们需要实现如下这个样子的;如下所示:

1. 通过Node.js找到用户个人文件夹所在的路径

想要显示用户个人文件夹的路径,我们先得想办法获取到该路径,并且要支持window、mac、及linux系统。在mac系统中,用户个人文件夹在 /User/<username> , 这里的username是用户名(我这边是 /User/tugenhua), 在linux系统中,用户的个人文件夹位于 /home/<username>. 在window10中,则位于C盘的 /User/<username>. 因此不同的操作系统它处于的位置不同。

在Node.js 中有一个叫 osenv 模块即可解决如上不同位置的问题,有个函数 osenv.home()可以返回用户个人文件夹。
要使用该模块,我们可以先进行安装,当然我们也要安装fs模块,需要对文件操作,因此如下命令安装:

npm install osenv fs --save

因此我们现在需要在 main.js 中加上该模块的代码,最终main.js 变成如下代码:

'use strict';

// 引入 全局模块的 electron模块
const electron = require('electron'); // 在应用中加载node模块
const fs = require('fs');
const osenv = require('osenv'); function getUsersHomeFolder() {
return osenv.home();
}
// 使用 fs.readdir 来获取文件列表
function getFilesInFolder(folderPath, cb) {
fs.readdir(folderPath, cb);
}
/*
该函数的作用是:获取到用户个人文件夹的路径,并获取到该文件夹下的文件列表信息
*/
function main() {
const folderPath = getUsersHomeFolder();
getFilesInFolder(folderPath, (err, files) => {
if (err) {
console.log('对不起,您没有加载您的home folder');
}
files.forEach((file) => {
console.log(`${folderPath}/${file}`);
});
});
} main(); // 创建 electron应用对象的引用 const app = electron.app;
const BrowserWindow = electron.BrowserWindow; // 定义变量 对应用视窗的引用
let mainWindow = null; // 监听视窗关闭的事件(在Mac OS 系统下是不会触发该事件的)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
}); // 将index.html 载入应用视窗中
app.on('ready', () => {
/*
创建一个新的应用窗口,并将它赋值给 mainWindow变量。
*/
mainWindow = new BrowserWindow(); // 载入 index.html 文件
mainWindow.loadURL(`file://${__dirname}/index.html`); // 当应用被关闭的时候,释放 mainWindow变量的引用
mainWindow.on('closed', () => {
mainWindow = null;
});
});

然后我们继续在命令行中运行:electron . ,然后我们会看到如下效果:

现在我们已经知道了如何获取用户个人文件夹下的文件列表了。现在我们要考虑的问题是:如何获取文件名及文件类型(是文件还是文件夹)。并将他们以不同的图标在界面上显示出来。

如上代码我们已经获取到了文件列表,现在我们可以以文件列表作为参数,将它传递给Node.js文件系统的API中的另一个函数,
该函数要做的事情是:能够识别是文件还是文件夹以及他们的名字和完整的路径。要完成这些事情,我们要做如下三件事:

1. 使用 fs.stat函数。来读取文件状态。
2. 使用 async模块来处理调用一系列异步函数的情况并收集他们的结果。
3. 将结果列表传递给另一个函数将他们显示出来。

因此我们首先要安装 async 模块,安装命令如下:

npm install async --save

因此我们的main.js 继续添加代码,代码变成如下:

'use strict';

// 引入 全局模块的 electron模块
const electron = require('electron'); // 在应用中加载node模块
const fs = require('fs');
const osenv = require('osenv'); // 引入 aysnc模块
const async = require('async');
// 引入path模块
const path = require('path'); function getUsersHomeFolder() {
return osenv.home();
}
// 使用 fs.readdir 来获取文件列表
function getFilesInFolder(folderPath, cb) {
fs.readdir(folderPath, cb);
} function inspectAndDescribeFile(filePath, cb) {
let result = {
file: path.basename(filePath),
path: filePath,
type: ''
};
fs.stat(filePath, (err, stat) => {
if (err) {
cb(err);
} else {
if (stat.isFile()) { // 判断是否是文件
result.type = 'file';
}
if (stat.isDirectory()) { // 判断是否是目录
result.type = 'directory';
}
cb(err, result);
}
});
} function inspectAndDescribeFiles(folderPath, files, cb) {
// 使用 async 模块调用异步函数并收集结果
async.map(files, (file, asyncCB) => {
const resolveFilePath = path.resolve(folderPath, file);
inspectAndDescribeFile(resolveFilePath, asyncCB);
}, cb);
} // 该函数的作用是显示文件列表信息
function displayFiles(err, files) {
if (err) {
return alert('sorry, we could not display your files');
}
files.forEach((file) => {
console.log(file);
});
} /*
该函数的作用是:获取到用户个人文件夹的路径,并获取到该文件夹下的文件列表信息
*/
function main() {
const folderPath = getUsersHomeFolder();
getFilesInFolder(folderPath, (err, files) => {
if (err) {
console.log('对不起,您没有加载您的home folder');
}
/*
files.forEach((file) => {
console.log(`${folderPath}/${file}`);
});
*/
inspectAndDescribeFiles(folderPath, files, displayFiles);
});
} main(); // 创建 electron应用对象的引用 const app = electron.app;
const BrowserWindow = electron.BrowserWindow; // 定义变量 对应用视窗的引用
let mainWindow = null; // 监听视窗关闭的事件(在Mac OS 系统下是不会触发该事件的)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
}); // 将index.html 载入应用视窗中
app.on('ready', () => {
/*
创建一个新的应用窗口,并将它赋值给 mainWindow变量。
*/
mainWindow = new BrowserWindow(); // 载入 index.html 文件
mainWindow.loadURL(`file://${__dirname}/index.html`); // 当应用被关闭的时候,释放 mainWindow变量的引用
mainWindow.on('closed', () => {
mainWindow = null;
});
});

保存完该 main.js 后,我们接着运行 electron . 命令即可在命令行窗口打印出 对象 {file: '', path: '', type: '' }这样的了,如下所示:

2. 视觉上显示文件和文件夹

在如上main.js 代码中,我们在该文件中有个函数 displayFiles ,我们可以继续在该函数内部处理将文件名以及对应的图标展示在界面上。由于要显示的文件比较多,因此我们会将每个文件定义一套模板,然后为每个文件创建一个该模板的实列再渲染到界面上。

首先我们在index.html文件中添加html模板,模板中包含一个div元素,在其中包含了要显示的文件信息,因此index.html代码变成如下:

<html>
<head>
<title>FileBrowser</title>
<link rel="stylesheet" href="./app.css" />
</head>
<body>
<template id="item-template">
<div class="item">
<img class='icon' />
<div class="filename"></div>
</div>
</template>
<div id="toolbar">
<div id="current-folder">
</div>
</div>
<!-- 该div元素是用来放置要显示的文件列表信息-->
<div id="main-area"></div>
<script src="./app.js" type="text/javascript"></script>
</body>
</html>

如上代码 template模板元素的作用是:为每一个渲染的文件信息定义一套HTML模板,真正被渲染到 id为 main-area 元素上,它会将用户个人文件夹中的每个文件信息都显示出来。因此下面我们需要在我们的main.js中添加一些代码,用来创建模板实列并添加到界面上。为了把main.js 启动代码和业务代码分开,因此我们再新建一个app.js,app.js 代码如下:

'use strict';

// 在应用中加载node模块
const fs = require('fs');
const osenv = require('osenv'); // 引入 aysnc模块
const async = require('async');
// 引入path模块
const path = require('path'); function getUsersHomeFolder() {
return osenv.home();
}
// 使用 fs.readdir 来获取文件列表
function getFilesInFolder(folderPath, cb) {
fs.readdir(folderPath, cb);
} function inspectAndDescribeFile(filePath, cb) {
let result = {
file: path.basename(filePath),
path: filePath,
type: ''
};
fs.stat(filePath, (err, stat) => {
if (err) {
cb(err);
} else {
if (stat.isFile()) { // 判断是否是文件
result.type = 'file';
}
if (stat.isDirectory()) { // 判断是否是目录
result.type = 'directory';
}
cb(err, result);
}
});
} function inspectAndDescribeFiles(folderPath, files, cb) {
// 使用 async 模块调用异步函数并收集结果
async.map(files, (file, asyncCB) => {
const resolveFilePath = path.resolve(folderPath, file);
inspectAndDescribeFile(resolveFilePath, asyncCB);
}, cb);
} function displayFile(file) {
const mainArea = document.getElementById('main-area');
const template = document.querySelector('#item-template');
// 创建模板实列的副本
let clone = document.importNode(template.content, true); // 加入文件名及对应的图标
clone.querySelector('img').src = `images/${file.type}.svg`;
clone.querySelector('.filename').innerText = file.file; mainArea.appendChild(clone);
} // 该函数的作用是显示文件列表信息
function displayFiles(err, files) {
if (err) {
return alert('sorry, we could not display your files');
}
files.forEach(displayFile);
} /*
该函数的作用是:获取到用户个人文件夹的路径,并获取到该文件夹下的文件列表信息
*/
function main() {
const folderPath = getUsersHomeFolder(); getFilesInFolder(folderPath, (err, files) => {
if (err) {
console.log('对不起,您没有加载您的home folder');
}
console.log(files);
/*
files.forEach((file) => {
console.log(`${folderPath}/${file}`);
});
*/
inspectAndDescribeFiles(folderPath, files, displayFiles);
});
} window.onload = function() {
main();
};

然后main.js 代码如下:

'use strict';

// 引入 全局模块的 electron模块
const electron = require('electron'); // 创建 electron应用对象的引用 const app = electron.app;
const BrowserWindow = electron.BrowserWindow; // 定义变量 对应用视窗的引用
let mainWindow = null; // 监听视窗关闭的事件(在Mac OS 系统下是不会触发该事件的)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
}); // 将index.html 载入应用视窗中
app.on('ready', () => {
/*
创建一个新的应用窗口,并将它赋值给 mainWindow变量。
*/
mainWindow = new BrowserWindow({
webPreferences: {
nodeIntegration: true
}
}); // 添加如下代码 可以调试
mainWindow.webContents.openDevTools(); // 载入 index.html 文件
mainWindow.loadURL(`file://${__dirname}/index.html`); // 当应用被关闭的时候,释放 mainWindow变量的引用
mainWindow.on('closed', () => {
mainWindow = null;
});
});

如上代码是目前所有的代码了,我们运行下 electron . 命令后,可以看到如下所示:

如上图可以看到我们的代码有调试代码了,那是因为在main.js加上了如下这句代码:

// 添加如下代码 可以调试
mainWindow.webContents.openDevTools();

并且如果我们按照之前的代码,在main.js 实列化 BrowserWindow 的时候,如下实列化代码:

mainWindow = new BrowserWindow();

如下代码:

// 将index.html 载入应用视窗中
app.on('ready', () => {
/*
创建一个新的应用窗口,并将它赋值给 mainWindow变量。
*/
mainWindow = new BrowserWindow(); // 添加如下代码 可以调试
mainWindow.webContents.openDevTools(); // 载入 index.html 文件
mainWindow.loadURL(`file://${__dirname}/index.html`); // 当应用被关闭的时候,释放 mainWindow变量的引用
mainWindow.on('closed', () => {
mainWindow = null;
});
});

在控制台中会报如下的错:

解决的方案就是加上如下配置:

mainWindow = new BrowserWindow({
webPreferences: {
nodeIntegration: true
}
});

这是因为最新的electron@5.0系列中,这个nodeIntegration参数,默认改成false了。
而在以前版本的electron中,这个nodeIntegration参数,默认为true。

github源码查看

Electron构建一个文件浏览器应用(一)的更多相关文章

  1. Electron构建一个文件浏览器应用(二)

    在前一篇文章我们已经学习到了使用Electron来构建我们的文件浏览器了基础东西了,我们之前已经完成了界面功能和显示文件或文件夹的功能了,想看之前文章,请点击这个链接  .现在我们需要在之前的基础上来 ...

  2. 跟我一起使用electron搭建一个文件浏览器应用吧(二)

    这个文件浏览器应用可以具备以下两种功能噢- This file browser application can have the following two functions. 一:用户浏览文件夹和 ...

  3. 跟我一起使用electron搭建一个文件浏览器应用吧(四)

    在软件的世界里面,创建一个新项目很容易,但是坚持将他们开发完成并发布却并非易事.分发软件就是一个分水岭, 分水岭的一边是那些完成的被全世界用户在用的软件,而另外一边则是启动了无数项目却没有一个完成的. ...

  4. 跟我一起使用electron搭建一个文件浏览器应用吧(三)

    第二篇博客中我们可以看到我们构建的桌面应用会显示我们的文件及文件夹. In the second blog, we can see that the desktop application we bu ...

  5. 使用 AngularJS 和 Electron 构建桌面应用

    GitHub 的 Electron 框架(以前叫做 Atom Shell)允许你使用 HTML, CSS 和 JavaScript 编写跨平台的桌面应用.它是io.js 运行时的衍生,专注于桌面应用而 ...

  6. AngularJS 和 Electron 构建桌面应用

    译]使用 AngularJS 和 Electron 构建桌面应用 原文: Creating Desktop Applications With AngularJS and GitHub Electro ...

  7. 比nerdtree更好的文件浏览器:vimfiler

    通过:VimFilerExplorer来打开一个文件浏览器 h:收起 t:展开 -:close 回车:进入或展开 空格:收起

  8. php写的非常简单的文件浏览器

    php写的非常简单的一个文件浏览器,仅供参考. <?php /** * php文件浏览程序函数 showDir() * * $dirName 输入目录路径,默认php文件一级目录,不需输入: * ...

  9. [Swift通天遁地]七、数据与安全-(7)创建文件浏览器:以可视化的方式浏览沙箱文件

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

随机推荐

  1. 聊聊PROFINET与PROFIBUS

    1.PROFINET与PROFIBUS从狭义上比,没有可比性,因为他们的物理接口不同,电气特性,不同,波特率不同,电气介质特性不同等等.这样两者的协议是完全没有关联性的,唯一的关联性就是两者都是PI组 ...

  2. Android 4.0新增Space及GridLayout初谈

    Android 4.0的SDK已经发布,在众多的新增特性中,其中对开发者来说比较重要的特性之一,是新增的两种界面布局方式:Space和Gridlayout,它们跟以往Android版本的sdk有什么不 ...

  3. Java transient关键字【转】

    转自:http://www.blogjava.net/fhtdy2004/archive/2009/06/20/286112.htmlVolatile修饰的成员变量在每次被线程访问时,都强迫从主内存中 ...

  4. DDD实战9 经销商领域上下文

    1.创建Dealer.Domain 类库项目 2.创建实体和值对象 3.安装ef的包 4.创建上下文接口(IDealerContext)之所以要创建上下文接口,是为了可替换,在其他项目总使用接口,当需 ...

  5. 谷歌推出备份新工具:Google Drive将同步计算机文件

    Google 正在将云端硬盘 Drive 转变成更强大的文件备份工具.很快,Google Drive 将能监测并备份你电脑上的(几乎)所有文件,只要是你勾选的文档,Drive 就能同步至云端. 具体来 ...

  6. linq to entity DistinctBy && DefaultIfEmpty

    根据某属性去重 使用第三方库: https://github.com/morelinq/MoreLINQ Install-Package morelinq -Version 3.0.0 data.Di ...

  7. 【转载】如何使用docker部署c/c++程序

    原文地址:https://blog.csdn.net/len_yue_mo_fu/article/details/80189035 Docker介绍 Docker是一个开源的容器引擎,它有助于更快地交 ...

  8. VS中发布并调试IIS程序(非附加进程!!!)

    筒子们,你们不觉得发布到IIS再附加进程太烦了么???看了看网上全是这种方法,这不科学!VS已经提供了更好的方式了,少年们! 流程 1.打开你的IIS,创建一个站点示例中,我创建了一个端口号为5002 ...

  9. socket编程详解,转自http://www.sme-cn.com:82/archives/669

    一  Socket简介 Socket翻译过来是套接字,具体含义可自行百度,简言之就是IP:Port的组合,是网络通信的一个窗口,IP就是地址和门牌号(比如长沙市韶山北路81号),Port就是房间号(比 ...

  10. Qt程序打包发布方法(使用官方提供的windeployqt工具)

    Qt程序打包发布方法(使用官方提供的windeployqt工具) 转自:http://tieba.baidu.com/p/3730103947?qq-pf-to=pcqq.group Qt 官方开发环 ...