app.webview - WebView API
在独立窗口中显示网页或 HTML 内容,支持 JavaScript 交互。
权限: 需在 manifest 中声明
webview(L2 sensitive)
方法
app.webview.open(opts)
打开 WebView 窗口。
参数:
opts(table):url(string, 可选) - 要加载的 URL(与html二选一)html(string, 可选) - 要显示的 HTML 内容(与url二选一)title(string, 可选) - 窗口标题width(number, 可选) - 窗口宽度(默认 800)height(number, 可选) - 窗口高度(默认 600)x(number, 可选) - 窗口 X 位置y(number, 可选) - 窗口 Y 位置resizable(boolean, 可选) - 是否可调整大小(默认 true)closable(boolean, 可选) - 是否可关闭(默认 true)onClose(function, 可选) - 窗口关闭回调function(id)
返回值: string, error - WebView ID
-- 加载 URL
local id, err = app.webview.open({
url = "https://example.com",
title = "预览",
width = 1024,
height = 768
})
-- 加载 HTML
local id, err = app.webview.open({
html = "<h1>Hello</h1><p>This is a webview.</p>",
title = "自定义页面",
width = 400,
height = 300
})
-- 带关闭回调
local id, err = app.webview.open({
url = "https://example.com",
onClose = function(id)
app.log.info("WebView 已关闭: " .. id)
end
})
app.webview.close(id)
关闭指定 WebView 窗口。
参数:
id(string) - WebView ID
返回值: boolean, error
local ok, err = app.webview.close(webviewId)
app.webview.closeAll()
关闭所有 WebView 窗口。
返回值: boolean
app.webview.closeAll()
app.webview.eval(id, js)
在 WebView 中执行 JavaScript 代码。
参数:
id(string) - WebView IDjs(string) - JavaScript 代码
返回值: string|nil, error - JavaScript 执行结果(JSON 字符串)
-- 获取页面标题
local title, err = app.webview.eval(id, "document.title")
-- 获取表单数据
local data, err = app.webview.eval(id, [[
JSON.stringify({
name: document.getElementById('name').value,
email: document.getElementById('email').value
})
]])
if data then
local result = app.json.parse(data)
end
-- 修改页面内容
app.webview.eval(id, "document.body.style.backgroundColor = '#f0f0f0'")
app.webview.loadURL(id, url)
在已有 WebView 中加载新 URL。
参数:
id(string) - WebView IDurl(string) - 要加载的 URL
返回值: boolean, error
local ok, err = app.webview.loadURL(id, "https://other-page.com")
app.webview.loadHTML(id, html)
在已有 WebView 中加载新 HTML 内容。
参数:
id(string) - WebView IDhtml(string) - HTML 内容
返回值: boolean, error
local ok, err = app.webview.loadHTML(id, "<h1>Updated Content</h1>")
示例
Markdown 预览
function MyPlugin:handlePreview(context)
local file = context.selectedFiles[1]
if not file then return end
local content = app.file.read(file)
if not content then return end
local html = string.format([[
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: -apple-system; padding: 20px; max-width: 800px; margin: 0 auto; }
pre { background: #f5f5f5; padding: 12px; border-radius: 6px; overflow-x: auto; }
code { font-family: 'SF Mono', monospace; }
</style>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
</head>
<body>
<div id="content"></div>
<script>
document.getElementById('content').innerHTML = marked.parse(%s);
</script>
</body>
</html>
]], app.json.stringify(content))
app.webview.open({
html = html,
title = app.path.basename(file),
width = 900,
height = 700
})
end
自定义设置界面
function MyPlugin:handleSettings(context)
local settings = app.settings.getAll()
local html = string.format([[
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: -apple-system; padding: 20px; }
.field { margin: 12px 0; }
label { display: block; margin-bottom: 4px; font-weight: 600; }
input, select { width: 100%%; padding: 6px; border: 1px solid #ccc; border-radius: 4px; }
button { padding: 8px 16px; background: #007AFF; color: white; border: none; border-radius: 6px; cursor: pointer; }
</style>
</head>
<body>
<h2>插件设置</h2>
<div class="field">
<label>API Key</label>
<input id="apiKey" value="%s">
</div>
<div class="field">
<label>输出格式</label>
<select id="format">
<option value="json">JSON</option>
<option value="csv">CSV</option>
</select>
</div>
<button onclick="save()">保存</button>
<script>
function save() {
window.__result = JSON.stringify({
apiKey: document.getElementById('apiKey').value,
format: document.getElementById('format').value
});
}
</script>
</body>
</html>
]], settings.apiKey or "")
local id, err = app.webview.open({
html = html,
title = "设置",
width = 400,
height = 300,
resizable = false,
onClose = function(wvId)
local result = app.webview.eval(wvId, "window.__result || null")
if result and result ~= "null" then
local data = app.json.parse(result)
if data then
app.settings.set("apiKey", data.apiKey)
app.settings.set("format", data.format)
end
end
end
})
end
数据可视化
function MyPlugin:handleVisualize(context)
local files = context.selectedFiles
local sizes = {}
for _, file in ipairs(files) do
table.insert(sizes, {
name = app.path.basename(file),
size = app.file.size(file) or 0
})
end
local html = string.format([[
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>body { padding: 20px; }</style>
</head>
<body>
<canvas id="chart"></canvas>
<script>
var data = %s;
new Chart(document.getElementById('chart'), {
type: 'bar',
data: {
labels: data.map(d => d.name),
datasets: [{
label: '文件大小 (bytes)',
data: data.map(d => d.size),
backgroundColor: '#007AFF'
}]
}
});
</script>
</body>
</html>
]], app.json.stringify(sizes))
app.webview.open({
html = html,
title = "文件大小分析",
width = 800,
height = 500
})
end
注意事项
- 窗口数限制:每个插件最多 5 个 WebView 窗口
- JavaScript 结果:
eval()返回的是 JSON 字符串格式的结果 - 关闭回调:窗口关闭时自动触发
onClose - 资源清理:插件卸载时自动关闭所有 WebView 窗口
- 网络访问:WebView 可以加载外部 URL,但受 App Transport Security 限制