接着前几天写的博客https://blog.csdn.net/woyebuzhidao321/article/details/131495855,提到了涉及vscode网页版工作区创建的api,这两天一时兴起,搞了一个网页版的代码编辑器,如果在2020年10月之前,实现一个网页版代码编辑器可能是天方夜谭,由于网页端操作本地文件的困难,很难搞得出,直到
File System Access API
的出现,打破了原来的瓶颈。
2020年10月 Chrome 86 重要更新
Chrome 86 在2020年10月推出了稳定版,现已全面应用于Android、Chrome OS、Linux、macOS 和 Windows等平台,我们一起来看下这次的重要更新。
若要看全部更新,请移步(https://www.chromestatus.com/features#milestone=86)。
新增稳定功能
文件系统访问
还记得Chrome 83中的本地文件系统吗,当时的试验功能,现已稳定。通过调用 showOpenFilePicker
方法,你可以唤起文件选择窗口,进而通过返回的文件句柄对文件进行读写。代码如下:
const pickerOpts = {
types: [
{
description: "Images",
accept: {
"image/*": [".png", ".gif", ".jpeg", ".jpg"],
},
},
],
excludeAcceptAllOption: true,
multiple: false,
};
// create a reference for our file handle
let fileHandle;
async function getFile() {
// open file picker, destructure the one element returned array
[fileHandle] = await window.showOpenFilePicker(pickerOpts);
// run code with our fileHandle
}
官方文档地址:
https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker
vscode网页版
也是在此之后出现的。https://insiders.vscode.dev/
于是我照着大框实现了一个demo
Demo效果图
基于文件的增、删、改、查。读写速度很nice
打开文件夹
首先打开一个代码目录
$('#openFolderBtn')[0].addEventListener('click', async () => {
try {
// // 得到异步迭代器
dirHandle = await window.showDirectoryPicker();
const createTree = async () => {
const root = await createTreeModel(dirHandle);
fileArr = root;
treeInit();
}
createTree();
} catch (err) {
console.log(err)
}
})
这是会弹出一个文件弹窗
window.showDirectoryPicker
是异步的 返回一个文件句柄,选中文件之后会出现提示
创建树的数据结构
读取文件
// 读取文件
async function reader() {
if (fileHandle) {
let file = await fileHandle.getFile();
fileName.innerText = file.name;
let reader = new FileReader();
reader.onload = function (event) {
let contents = escapeHtml(event.target.result);
$("#textbox")[0].innerHTML = `<pre><code id="code">${contents}</code></pre>`;
// hljs.highlightAll();
hljs.highlightBlock($("#code")[0])
};
reader.readAsText(file);
}
}
fileHandle
是对应的文件句柄,通过调用getFile
方法拿到文件,然后通过FileReader
构造函数去读取文件内容并作展示
打开文件
如何单独打开一个本地文件
$('#openfile')[0].addEventListener('click', async () => {
try {
const openFileHandle = await window.showOpenFilePicker({
types: [{
accept: {
"text/plain": [".txt"]
}
}],
multiple: false
});
fileHandle = openFileHandle[0];
reader();
} catch (err) {
console.log(err);
}
})
选取一个文件并打开
如何创建一个文件夹
$("#createFolder")[0].addEventListener('click', async (e) => {
const folderName = prompt('请输入文件夹名称');
if (folderName) {
await dirHandle.getDirectoryHandle(folderName, { create: true });
console.log('文件夹创建成功');
fileArrFlat = [];
fileArr = await createTreeModel(dirHandle);
treeInit();
}
})
dirHandle是window.showDirectoryPicker
返回的文件句柄,通过调用getDirectoryHandle
方法创建。
创建一个文件
// 创建文件
$("#createFile")[0].addEventListener('click', async (e) => {
const fileName = prompt('请输入文件名称');
if (fileName) {
try {
if (!(await dirHandle.queryPermission()) === 'granted') {
alert('文件不允许读写!');
return;
}
const targetFile = await dirHandle.getFileHandle(fileName, { create: true });
fileArrFlat = [];
fileArr = await createTreeModel(dirHandle);
treeInit();
} catch (err) {
console.log(err)
}
}
})
另存为文件并写入内容
// 另存为文件
$("#textbox")[0].addEventListener('keydown', async (e) => {
if (e.ctrlKey && e.which == 83) {
e.preventDefault;
console.log('文件另存为', $("#textbox")[0].innerText)
try {
fileHandle = await window.showSaveFilePicker({
types: [{
accept: {
"text/plain": [".txt"]
}
}],
multiple: false
});
const w$ = await fileHandle.createWritable();
await w$.write($("#textbox")[0].innerText);
await w$.close();
} catch (err) {
console.log(err);
}
return false;
}
}, false)
fileHandle文件句柄 提供了createWritable方法,对文件进行写入内容。
代码高亮部分使用的是highLight.js
,这样一个最初版的网页版代码编辑器就搞定了
其兼容性