API

nsh/webview

nsh/webview 导出 WebView:由平台自带的浏览器引擎显示的网页(iOS 和 Mac Catalyst 上是 WKWebView,Android 上是 android.webkit.WebView)。它是一个和其他视图一样布局的原生视图,因此滚动、裁剪以及与其他视图的层叠都是正确的。

import { WebView, type WebViewNavigation, type WebViewProps } from "nsh/webview";

教程见网页视图与视频,属性见 <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;不接受子元素),另外还有:

属性类型默认值说明
sourcestring | { uri: string } | { html: string; baseUrl?: string }(必填)URL、{ uri },或内联 HTML 加上可选的基础 URL(用于解析相对链接)。
injectedJavaScriptstring每个页面加载完成后运行。
injectedJavaScriptBeforeContentLoadedstring在每个页面自身的脚本之前运行。
userAgentstring平台默认用户代理字符串。
scrollEnabledbooleantrue用户可以滚动页面。
javaScriptEnabledbooleantrue页面可以运行脚本。
ios{ allowsBackForwardNavigationGestures?: boolean }仅 iOS:从边缘轻扫以后退和前进。

#事件

事件数据时机
onLoadStartWebViewNavigation页面开始加载。
onLoadWebViewNavigation页面加载完成。
onError{ message: string }页面加载失败。
onNavigationStateChangeWebViewNavigationURL、标题、加载状态或历史记录发生变化。
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"] }
  }
}