React Native WebView调用网页cancel函数无响应问题求助
React Native WebView 点击返回键无法触发网页端cancel函数的问题
我用React Native WebView加载了一个单页网页,网页执行搜索后会展示结果,重新搜索需要点击设备返回键回到搜索框。因为是单页应用,没法用goBack(),所以在网页端定义了cancel()函数用来清除搜索结果并回到搜索窗口,但现在点击设备返回键时,网页的cancel()函数根本没执行。
我的代码如下:
import React, { useRef, useEffect, useState } from 'react'; import { KeyboardAvoidingView, StatusBar, BackHandler } from 'react-native'; import { WebView } from 'react-native-webview'; export default function App() { const webviewRef = useRef(null); const [backTapping, setBackTapping] = useState(0); const backAction = () => { setBackTapping((prev) => prev += 1); webviewRef.current.injectJavaScript('window.cancel()') return true; } useEffect(() => { const timer = setInterval(() => { setBackTapping(0) }, 1000) return () => clearInterval(timer); }, []) useEffect(() => { const backHandler = BackHandler.addEventListener('hardwareBackPress',backAction); return () => backHandler.remove() }, []) useEffect(() => { if(backTapping >= 2){ BackHandler.exitApp(); } },[backTapping]) return ( <KeyboardAvoidingView style={{ flex: 1 }}> <StatusBar hidden /> <WebView ref={webviewRef} textZoom={100} originWhitelist={['*']} javaScriptEnabled={true} source={{ uri: 'myhome.com'}} startInLoadingState={true} /> </KeyboardAvoidingView> ); }
预期行为:点击返回键时执行cancel()函数,关闭结果窗口回到搜索窗口。
解决建议
1. 确保window.cancel全局可访问
网页端的cancel函数必须挂载到window对象上,且在WebView加载完成后可用。检查网页代码:
// 网页端代码示例 window.cancel = function() { // 清除搜索结果、返回搜索框的逻辑 console.log('cancel函数执行'); };
如果函数是在模块内部定义的,必须显式暴露到全局作用域,否则WebView无法通过window.cancel调用。
2. 用evaluateJavaScript替代injectJavaScript
injectJavaScript在新版react-native-webview中已被标记为过时,推荐使用evaluateJavaScript,它支持Promise,可捕获执行错误:
修改backAction函数:
const backAction = async () => { setBackTapping((prev) => prev + 1); try { if (webviewRef.current) { const result = await webviewRef.current.evaluateJavaScript('window.cancel()'); console.log('cancel函数执行结果:', result); } } catch (error) { console.error('执行cancel函数出错:', error); } return true; };
3. 等待网页完全加载后再执行函数
如果网页未加载完成就调用window.cancel,会因函数不存在而失败。通过onLoadEnd标记加载状态:
const [webLoaded, setWebLoaded] = useState(false); // ... <WebView ref={webviewRef} textZoom={100} originWhitelist={['*']} javaScriptEnabled={true} source={{ uri: 'myhome.com'}} startInLoadingState={true} onLoadEnd={() => setWebLoaded(true)} />
然后在backAction中判断:
const backAction = async () => { setBackTapping((prev) => prev + 1); if (!webLoaded) return true; try { await webviewRef.current.evaluateJavaScript('window.cancel()'); } catch (error) { console.error('执行失败:', error); } return true; };
4. 优化返回键重复触发逻辑
当前定时器逻辑可能导致不必要的循环,调整为点击后才启动定时器:
useEffect(() => { let timer; if (backTapping > 0) { timer = setTimeout(() => { setBackTapping(0); }, 1000); } return () => clearTimeout(timer); }, [backTapping]);
5. 检查网页CSP和WebView配置
确保WebView的javaScriptEnabled显式设为true,同时如果网页有内容安全策略(CSP),需允许执行内联脚本,否则注入的JS代码会被阻止。
内容的提问来源于stack exchange,提问作者EremesKim
相关产品推荐
相关产品推荐

