D.C*_*.C. 6 javascript iphone cocoa-touch uiwebview uikit
我试图在UIWebView中的内容上执行一些Javascript.也许我对Javascript运行时的知识缺乏,但我对以下示例感到困惑.有关详细信息,请参阅源代码和注释:
NSString *html = [NSString stringWithFormat:@"<html><head><script type='text/javascript'>var content='the initial content';function myFunc(){return 'value of content: ' + content;}myFunc();</script></head><body>Hello blank</body></html>"];
// I would expect after this call that the variable content exists, as well as the function myFunc()
[self.webView loadHTMLString:html baseURL:nil];
// However, it appears not to. The following call returns nothing
NSString *result = [self.webView stringByEvaluatingJavaScriptFromString:@"myFunc();"];
NSLog(@"result: %@", result);
// Inserting the Javascript at this point seems to work as expected
result = [self.webView stringByEvaluatingJavaScriptFromString:@"var content='the new content';function myFunc(){return 'value of content: ' + content;}myFunc();"];
NSLog(@"result: %@", result);
// And calling myFunc() at this point is successful
result = [self.webView stringByEvaluatingJavaScriptFromString:@"myFunc();"];
NSLog(@"result: %@", result);
Run Code Online (Sandbox Code Playgroud)
总而言之,我希望我加载html时创建的Javascript全局变量和函数可用于以后的javascript调用.令人惊讶的是,它似乎没有,并且所有javascript的东西必须在以后添加.它是否正确?
谢谢你提前帮助.
-----更新-----我应该补充说,在这种情况下,self.view是一个WebView.此外,我已经尝试将脚本标记放在HTML文档的头部和正文中,而不会改变行为.
小智 3
mclin 的答案是正确的,因为 UIWebView 在后台执行加载。如果您加载的所有内容都是纯 html 并且没有标签具有 src="..." 类型内容,那么您可以合理地确定 webViewDidFinishLoad (UIWebViewDelegate 协议方法)将仅被调用一次,并且您可以在该委托中执行您的 javascript方法。
然而,UIWebView 在加载初始 HTML 后将开始加载任何图像、javascript、音频、视频等,并且 webViewDidFinishLoad 将在每个后续加载完成时被调用。我想如果你在 iPhone 上观察 Safari 上的进度条,你就能看到这种行为。进度条在初始页面加载后大约前进一半,然后随着图像或您所加载的内容一次前进一点。
我尝试了几种技术来在页面加载完成后运行 javascript。更简单的方法是让 webViewDidFinishLoad 在短暂延迟后执行另一个选择器,并检查 webView 的加载属性。您在这里承担了一点风险,因为我们将“时间”和“线程”结合在一起,但是嘿......如果您想要简单(更确切地说)。
-(void) checkIfLoadDone:(UIWebView *) webView {
if (webView.loading) { return; }
// run your javascript here
}
-(void) webViewDidFinishLoad:(UIWebView *) webView {
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(checkIfLoadDone:)
object:webView];
[self performSelector:@selector(checkIfLoadDone:)
withObject:webView
afterDelay:0.5];
}
-(void) webViewDidStartLoad:(UIWebView *)webView {
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(checkIfLoadDone:)
object:webView];
}
- (void) webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
// ooops ... probably should deal with the error, but lets just run checkIfLoadDone
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(checkIfLoadDone:)
object:webView];
[self performSelector:@selector(checkIfLoadDone:)
withObject:webView
afterDelay:0.5];
}
Run Code Online (Sandbox Code Playgroud)
更复杂的技术是单独跟踪负载并维护计数器。当计数器返回到 0 时,您可以运行 JavaScript。在这种情况下,您需要实现委托方法
- (BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType != UIWebViewNavigationTypeOther) {
self.outStandingLoads = 0;
}
return YES;
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以让 webViewDidStartLoad: 递增 outStandingLoads 并让 webViewDidFinishLoad: 和 webView:didFailLoadWithError: 递减并检查 outStandingLoads。我会在整个代码中对 outStandingLoads 使用原子 NSInteger 属性,以解决可能存在多个线程执行加载的情况。
我认为这两种方法都会相当有效。我选择了后一种方法,但这只是因为我需要解决 webViewDelegate 调用中的其他问题。我决定扩展 UIWebView 并使其成为自己的委托,其中我的扩展实现了委托方法。然后,我利用 NSNotification 模型发布“WebPageLoadBegan”和“WebPageLoadComplete”等通知,以与我的用户界面代码进行通信。当我使用两组不同的 UI 代码(iPad 和 iPhone)时,这对我来说似乎是一个更简单的模型。
我希望这有帮助。
| 归档时间: |
|
| 查看次数: |
2427 次 |
| 最近记录: |