API
nsh/webview
nsh/webview 导出 WebView:由平台自带的浏览器引擎显示的网页(iOS 和 Mac Catalyst 上是 WKWebView,Android 上是 android.webkit.WebView)。它是一个和其他视图一样布局的原生视图,因此滚动、裁剪以及与其他视图的层叠都是正确的。
import { WebView, type WebViewNavigation, type WebViewProps } from "nsh/webview";
#WebView
const WebView: (props: WebViewProps) => YNode;
interface WebViewProps extends Omit<ViewProps, "children" | "ios">, WebViewHostProps {
source: string | { uri: string } | { html: string; baseUrl?: string };
ios?: IOSWebViewHostProps;
}
import { mount, signal, Text, View, type YNode } from "nsh";
import { WebView, type WebViewNavigation } from "nsh/webview";
function Browser() {
const nav = signal<WebViewNavigation | null>(null);
let web!: YNode;
return (
<View style={{ flex: 1 }}>
<View style={{ flexDirection: "row", gap: 16, padding: 12 }}>
<Text onPress={() => web.goBack()} style={{ opacity: nav()?.canGoBack ? 1 : 0.4 }}>Back</Text>
<Text onPress={() => web.reload()}>Reload</Text>
<Text numberOfLines={1} style={{ flex: 1 }}>{nav()?.title ?? ""}</Text>
</View>
<WebView ref={web} source="https://example.com" style={{ flex: 1 }} onNavigationStateChange={(n) => nav.set(n)} />
</View>
);
}
mount(Browser);
#属性
WebView 接受视图属性(样式、class、布局、无障碍、ref;不接受子元素),另外还有:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
source | string | { uri: string } | { html: string; baseUrl?: string } | (必填) | URL、{ uri },或内联 HTML 加上可选的基础 URL(用于解析相对链接)。 |
injectedJavaScript | string | 每个页面加载完成后运行。 | |
injectedJavaScriptBeforeContentLoaded | string | 在每个页面自身的脚本之前运行。 | |
userAgent | string | 平台默认 | 用户代理字符串。 |
scrollEnabled | boolean | true | 用户可以滚动页面。 |
javaScriptEnabled | boolean | true | 页面可以运行脚本。 |
ios | { allowsBackForwardNavigationGestures?: boolean } | 仅 iOS:从边缘轻扫以后退和前进。 |
#事件
| 事件 | 数据 | 时机 |
|---|---|---|
onLoadStart | WebViewNavigation | 页面开始加载。 |
onLoad | WebViewNavigation | 页面加载完成。 |
onError | { message: string } | 页面加载失败。 |
onNavigationStateChange | WebViewNavigation | URL、标题、加载状态或历史记录发生变化。 |
onMessage | { data: string } | 页面调用了 window.ReactNativeWebView.postMessage(data)。 |
interface WebViewNavigation {
url: string;
title: string;
loading: boolean;
canGoBack: boolean;
canGoForward: boolean;
}
#ref 方法
| 方法 | 说明 |
|---|---|
reload() | 重新加载页面。 |
goBack() | 在历史记录中后退。 |
goForward() | 在历史记录中前进。 |
stopLoading() | 停止加载。 |
injectJavaScript(script) | 在页面中运行 script。 |
postMessage(data) | 向页面发送 data(字符串):在 window 上触发 message 事件,event.data 即为 data。 |
#与页面通信
页面用 window.ReactNativeWebView.postMessage(…) 向应用发送字符串;应用用 ref.postMessage(…) 向页面发送字符串。结构化数据请用 JSON 传递。
const page = `<!doctype html><html><head><meta name="viewport" content="width=device-width"></head>
<body>
<button onclick="window.ReactNativeWebView.postMessage('hello from the page')">Post to the app</button>
<p id="got"></p>
<script>
window.addEventListener('message', (e) => { document.getElementById('got').textContent = e.data; });
</script>
</body></html>`;
let web!: YNode;
const message = signal("");
<WebView ref={web} source={{ html: page }} style={{ height: 200 }} onMessage={(e) => message.set(e.data)} />
<Text onPress={() => web.postMessage("hi from the app")}>Post to the page</Text>
#权限
如果应用在 nsh.json 中声明了 capabilities,网页视图只能显示和导航到 webview 下列出的主机;其他顶层导航会在原生侧被拒绝。没有 capabilities 键的应用可以显示任何内容。见沙箱与权限。
{
"capabilities": {
"webview": { "hosts": ["example.com", "*.example.com"] }
}
}