接着前几天写的博客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
,这样一个最初版的网页版代码编辑器就搞定了
其兼容性