跟我一起使用electron搭建一个文件浏览器应用吧(三)
第二篇博客中我们可以看到我们构建的桌面应用会显示我们的文件及文件夹。
In the second blog, we can see that the desktop application we built will display our files and folders.
但是有一点就是它不能进行点击查看里面的内容,接下来我们继续改造我们的项目吧~
But one thing is that it can't Click to see the contents. Next, let's continue to transform our project.
第一步重构代码,将代码进行逻辑分组
The first step is to refactor the code and group it logically.
fileSystem.js
'use strict';
const async = require('async');
const fs = require('fs');
const osenv = require('osenv');
const path = require('path');
let shell;
if (process.versions.electron) {
shell = require('electron').shell;
} else {
shell = window.require('nw.gui').Shell;
}
function getUsersHomeFolder() {
return osenv.home();
}
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.map(files, (file, asyncCb) => {
let resolvedFilePath = path.resolve(folderPath, file);
inspectAndDescribeFile(resolvedFilePath, asyncCb);
}, cb);
}
function openFile(filePath) {
shell.openItem(filePath);
}
module.exports = {
getUsersHomeFolder,
getFilesInFolder,
inspectAndDescribeFiles,
openFile
};
userInterface.js
'use strict';
let document;
const fileSystem = require('./fileSystem');
const search = require('./search');
const path = require('path');
function displayFolderPath(folderPath) {
document.getElementById('current-folder')
.innerHTML = convertFolderPathIntoLinks(folderPath);
bindCurrentFolderPath();
}
function clearView() {
const mainArea = document.getElementById('main-area');
let firstChild = mainArea.firstChild;
while (firstChild) {
mainArea.removeChild(firstChild);
firstChild = mainArea.firstChild;
}
}
function loadDirectory(folderPath) {
return function (window) {
if (!document) document = window.document;
search.resetIndex();
displayFolderPath(folderPath);
fileSystem.getFilesInFolder(folderPath, (err, files) => {
clearView();
if (err) {
return alert('Sorry, we could not load your folder');
}
fileSystem.inspectAndDescribeFiles(folderPath, files, displayFiles);
});
};
}
function displayFile(file) {
const mainArea = document.getElementById('main-area');
const template = document.querySelector('#item-template');
let clone = document.importNode(template.content, true);
search.addToIndex(file);
clone.querySelector('img').src = `images/${file.type}.svg`;
clone.querySelector('img').setAttribute('data-filePath', file.path);
if (file.type === 'directory') {
clone.querySelector('img')
.addEventListener('dblclick', () => {
loadDirectory(file.path)();
}, false);
} else {
clone.querySelector('img')
.addEventListener('dblclick', () => {
fileSystem.openFile(file.path);
},
false);
}
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 bindDocument (window) {
if (!document) {
document = window.document;
}
}
function bindSearchField(cb) {
document.getElementById('search').addEventListener('keyup', cb, false);
}
function filterResults(results) {
const validFilePaths = results.map((result) => { return result.ref; });
const items = document.getElementsByClassName('item');
for (var i = 0; i < items.length; i++) {
let item = items[i];
let filePath = item.getElementsByTagName('img')[0]
.getAttribute('data-filepath');
if (validFilePaths.indexOf(filePath) !== -1) {
item.style = null;
} else {
item.style = 'display:none;';
}
}
}
function resetFilter() {
const items = document.getElementsByClassName('item');
for (var i = 0; i < items.length; i++) {
items[i].style = null;
}
}
function convertFolderPathIntoLinks (folderPath) {
const folders = folderPath.split(path.sep);
const contents = [];
let pathAtFolder = '';
folders.forEach((folder) => {
pathAtFolder += folder + path.sep;
contents.push(`<span class="path" data-path="${pathAtFolder.slice(0,-1)}">${folder}</span>`);
});
return contents.join(path.sep).toString();
}
function bindCurrentFolderPath() {
const load = (event) => {
const folderPath = event.target.getAttribute('data-path');
loadDirectory(folderPath)();
};
const paths = document.getElementsByClassName('path');
for (var i = 0; i < paths.length; i++) {
paths[i].addEventListener('click', load, false);
}
}
module.exports = { bindDocument, displayFiles, loadDirectory, bindSearchField, filterResults, resetFilter };
app.js
'use strict';
const fileSystem = require('./fileSystem');
const userInterface = require('./userInterface');
const search = require('./search');
function main() {
userInterface.bindDocument(window);
let folderPath = fileSystem.getUsersHomeFolder();
userInterface.loadDirectory(folderPath)(window);
userInterface.bindSearchField((event) => {
const query = event.target.value;
if (query === '') {
userInterface.resetFilter();
} else {
search.find(query, userInterface.filterResults);
}
});
}
window.onload = main;
app.css
body {
padding: 0;
margin: 0;
font-family: 'Helvetica','Arial','sans';
}
#toolbar {
top: 0px;
position: fixed;
background: red;
width: 100%;
z-index: 2;
}
#current-folder {
float: left;
color: white;
background: rgba(0,0,0,0.2);
padding: 0.5em 1em;
min-width: 10em;
border-radius: 0.2em;
margin: 1em;
}
#main-area {
clear: both;
margin: 2em;
margin-top: 3em;
z-index: 1;
}
.item {
position: relative;
float: left;
padding: 1em;
margin: 1em;
width: 6em;
height: 6em;
text-align: center;
}
.item .filename {
padding-top: 1em;
font-size: 10pt;
}
#search {
float: right;
padding: 0.5em;
min-width: 10em;
border-radius: 3em;
margin: 2em 1em;
border: none;
outline: none;
}
span.path:hover, img:hover {
opacity: 0.7;
cursor: pointer;
}
index.html
<html>
<head>
<title>Lorikeet</title>
<link rel="stylesheet" href="app.css" />
<script src="app.js"></script>
</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>
<input type="search" id="search" results="5" placeholder="Search" />
</div>
<div id="main-area"></div>
</body>
</html>
search.js
'use strict';
const lunr = require('lunr');
let index;
function resetIndex() {
index = lunr(function () {
this.field('file');
this.field('type');
this.ref('path');
});
}
function addToIndex(file) {
index.add(file);
}
function find(query, cb) {
if (!index) {
resetIndex();
}
const results = index.search(query);
cb(results);
}
module.exports = { addToIndex, find, resetIndex };
安装lunr.js他支持对文件夹和文件的搜索
Install lunr. js, which supports searching for folders and files
cnpm install lunr --save
这个lunr的版本号最好为0.7.2,不用最新的。
The lunr version number is best 0.7.2, not the latest.
运行项目我们可以看到效果为
We can see the effect of running the project is as follows

本文的例子学习自 <<跨平台桌面应用开发基于Electron与NW.js>>这本书
跟我一起使用electron搭建一个文件浏览器应用吧(三)的更多相关文章
- 跟我一起使用electron搭建一个文件浏览器应用吧(二)
这个文件浏览器应用可以具备以下两种功能噢- This file browser application can have the following two functions. 一:用户浏览文件夹和 ...
- 跟我一起使用electron搭建一个文件浏览器应用吧(四)
在软件的世界里面,创建一个新项目很容易,但是坚持将他们开发完成并发布却并非易事.分发软件就是一个分水岭, 分水岭的一边是那些完成的被全世界用户在用的软件,而另外一边则是启动了无数项目却没有一个完成的. ...
- Electron构建一个文件浏览器应用(一)
在window.mac.linux系统中,他们都有一个共同之处就是以文件夹的形式来组织文件的.并且都有各自的组织方式,以及都有如何查询和显示哪些文件给用户的方法.那么从现在开始我们来学习下如何使用El ...
- Electron构建一个文件浏览器应用(二)
在前一篇文章我们已经学习到了使用Electron来构建我们的文件浏览器了基础东西了,我们之前已经完成了界面功能和显示文件或文件夹的功能了,想看之前文章,请点击这个链接 .现在我们需要在之前的基础上来 ...
- Electron为文件浏览器创建图标(三)
在前面的文章中,请看之前文章,我们已经完成了使用 electron做文件浏览器这么一个应用,现在我们需要为应用创建图标操作.为应用创建图标以后,我们就可以从计算机中与其他应用区分开来,如果我们自己会做 ...
- django 搭建一个投票类网站(三)
之前修改index的视图的代码,工作原理是先试用loader方法加载视图,然后HTTPResponse方法初始化一个HTTPResponse对象并返回给浏览器.对于很多django视图来说,他们的工作 ...
- 如何搭建一个WEB服务器项目(三)—— 实现安卓端联网登录
安卓端调用服务器登录函数进行验证登录 观前提示:本系列文章有关服务器以及后端程序这些概念,我写的全是自己的理解,并不一定正确,希望不要误人子弟.欢迎各位大佬来评论区提出问题或者是指出错误,分享宝贵经验 ...
- 比nerdtree更好的文件浏览器:vimfiler
通过:VimFilerExplorer来打开一个文件浏览器 h:收起 t:展开 -:close 回车:进入或展开 空格:收起
- php写的非常简单的文件浏览器
php写的非常简单的一个文件浏览器,仅供参考. <?php /** * php文件浏览程序函数 showDir() * * $dirName 输入目录路径,默认php文件一级目录,不需输入: * ...
随机推荐
- 手机APP自动化之uiautomator2 +python3 UI自动化
题记: 之前一直用APPium直到用安卓9.0 发现uiautomatorviewer不支持安卓 9.0,点击截屏按钮 一直报错,百度很久解决方法都不可以,偶然间看见有人推荐:uiautomator ...
- 以太坊remix-ide本地环境搭建
remix-ide简介 remix-ide是一款以太坊官方solisity语言的在线IDE,可用于智能合约的编写.测试与部署,不过某些时候可能是在离线环境下工作或者受限于网速原因,使用在线remi ...
- 《Linux内核分析》第四周学习总结
<Linux内核分析>第四周学习总结 ——扒开系统调用的三层皮 姓名:王玮怡 学号:20135116 理论总结部分: 第一节 用户态.内核 ...
- 20135337——Linux内核分析:第十七章 模块与设备
第17章 模块与设备 设备类型:在所有 Unix 系统中为了统一普通设备的操作所采用的分类. 模块: Linux 内核中用于按需加载和卸载目标码的机制. 内核对象:内核数据结构中支持面向对象的简单操作 ...
- java中字符串的排序(1)
按照前段时间在快速.冒泡等排序的评论中提到是否可以进行字符串的排序,由于最近有考试,时间比较紧,所以今天才实现此功能.此功能是针对一串字符川进行的实现,运行后的结果如下所示: 具体的程序相对较为简单, ...
- 小学四则运算APP 第二次冲刺-第二天
团队成员:陈淑筠.杨家安.陈曦 团队选题:小学四则运算APP 第二次冲刺阶段时间:11.29~12.09 本次发布的判断题功能界面的设置: activity_panduan_set.xml: < ...
- MySQL基础~~表结构操作
登录数据库服务器 mysql -h127.0.0.1 -uroot -p123456 创建数据库 create database test; 显示所有数据库 show databases; 指定要操作 ...
- the confilict between validation and readonly in jquery
How can I disable jquery validation on readonly fields? http://stackoverflow.com/questions/10803294/ ...
- 面象对象设计原则之三:里氏替换原则(The Liskov Substitution Principle,LSP)
里氏代换原则由2008年图灵奖得主.美国第一位计算机科学女博士Barbara Liskov教授和卡内基·梅隆大学Jeannette Wing教授于1994年提出.其严格表述如下:如果对每一个类型为S的 ...
- taskService 流程任务组件
act_ru_task:任务表act_ru_identitylink:权限表(流程定义和用户组(用户)之间的权限数据)act_ru_variable:参数表act_hi_attachment:任务附件 ...