前言
VS Code网页版支持访问并展示文件夹,https://vscode.dev/?vscode-lang=zh-cn,下面研究一下是如何实现的。

问题点
- 如何打开并选择文件夹
- 如何得到文件夹中的内容
- 如何读到某个文件的内容
- 如何高亮显示代码
实现
1. 打开并选择文件夹
通过showDirectoryPicker
打开文件夹,该方法是异步的。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">选择文件夹</button>
<script>
btn.onclick = async function () {
try {
const handle = await showDirectoryPicker()
console.log(handle);
} catch (e) {
// 用户拒绝浏览器访问文件
}
}
</script>
</body>
</html>
允许浏览器查看文件
showDirectoryPicker
会返回一个文件夹的处理句柄

2. 打开并选择文件夹
调用文件夹处理句柄
的entries
方法可以拿到异步迭代器,对此进行循环即可拿到下一个文件的处理句柄
。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">选择文件夹</button>
<script>
btn.onclick = async function () {
try {
const handle = await showDirectoryPicker()
processHandle(handle)
} catch (e) {
// 用户拒绝浏览器访问文件
}
}
async function processHandle(handle) {
// 得到异步迭代器
const iter = handle.entries()
for await (const item of iter) {
console.log(item);
}
}
</script>
</body>
</html>

递归处理,得到根句柄
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">选择文件夹</button>
<script>
btn.onclick = async function () {
try {
const handle = await showDirectoryPicker()
const root = await processHandle(handle)
console.log(root);
} catch (e) {
// 用户拒绝浏览器访问文件
}
}
async function processHandle(handle) {
if (handle.kind === 'file') {
return handle
}
handle.children = []
// 得到异步迭代器
const iter = handle.entries()
for await (const item of iter) {
handle.children.push(await processHandle(item[1])) // 递归确保是文件
}
return handle
}
</script>
</body>
</html>

3. 读取文件内容
通过getFile
得到文件内容
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">选择文件夹</button>
<script>
btn.onclick = async function () {
try {
const handle = await showDirectoryPicker()
const root = await processHandle(handle)
const file = await root.children[0].getFile()
const reader = new FileReader()
reader.onload = function (e) {
console.log(e.target.result);
}
reader.readAsText(file, 'utf-8')
} catch (e) {
// 用户拒绝浏览器访问文件
console.log(e);
}
}
async function processHandle(handle) {
if (handle.kind === 'file') {
return handle
}
handle.children = []
// 得到异步迭代器
const iter = handle.entries()
for await (const item of iter) {
handle.children.push(await processHandle(item[1])) // 递归确保是文件
}
return handle
}
</script>
</body>
</html>
4. 高亮显示代码
三方库:highlight.js