使用“stringByEvaluatingJavaScriptFromString”单击 UIWebView 中的链接

Posted

技术标签:

【中文标题】使用“stringByEvaluatingJavaScriptFromString”单击 UIWebView 中的链接【英文标题】:Click on a link in UIWebView using "stringByEvaluatingJavaScriptFromString" 【发布时间】:2011-12-03 19:35:18 【问题描述】:

如何在 UIWebView 中使用 stringByEvaluatingjavascriptFromString 方法单击链接?实际的超链接本身每次都不同,但测试代码中的措辞(“测试”)始终相同。

我该怎么做呢?我有一个建议做以下事情(这不起作用,也没有做任何事情):

var fonts = document.getElementsByTagName('font');
for(i=0;i<fonts.length;i++) 
  if (fonts[i].innerhtml == 'Test') 
  fonts[i].parentNode.childNodes[0].click();
  break;
 
 

【问题讨论】:

您要点击链接还是要在链接的 URL 处加载页面? 看到这个***.com/questions/6157929/… 问题是,我无权编辑页面,也没有任何 ID 或任何东西。我需要在网页中找到文本,然后点击与该文本关联的链接... SO 链接向您展示了如何单击链接。无需编辑页面 - 所有代码都进入您传递给 stringByEvaluatingJavaScriptFromString 的字符串中。如果您的问题还在于找到链接..这本身就是一个不同的问题。它将涉及迭代页面上的所有链接,就像您在问题中所做的那样。 好吧,它说'getElementById',但我的链接没有ID......这就是问题所在。如何在页面上搜索文本,例如“测试”,然后点击与之关联的超链接? 【参考方案1】:

看起来你有一个答案,包括你需要的 Objective-C 代码,但我想对于 javascript,你可以简单地触发链接的 onclick 内容或导航到适当的 url,而不是经历模拟的麻烦鼠标点击。诚然,我还没有在 ios 应用程序中测试过,但请随意试一试:

var links = document.getElementsByTagName('a');
for(i=0;i<links.length;i++) 
  if (links[i].innerHTML.indexOf('Test') != -1) 
  clickLink(links[i]);
  break;
 
 

function clickLink(linkobj) 
 var onclickHandler = linkobj.getAttribute('onclick');
 if (onclickHandler == null) window.location = linkobj.getAttribute('href').replace(/^\s\s*/, '').replace(/\s\s*$/, '');
 else eval(onclickHandler(linkobj));

顺便说一句,这段代码中有一个 eval 将运行 onclick 处理程序的内容。这可能是不安全的。如果您只需要导航到链接指定的位置,那么您可能需要删除处理 onclick 的部分。

下面打印了一个更简单的版本(因为您的示例代码似乎不需要处理 onclick),它可能更易于使用。在这种情况下,我会在 1 秒延迟后调用它,但实际上,由于此代码似乎响应 iOS 端的触发器(按钮单击?)而运行,因此您不应使用延迟,而只需等待启用触发器直到加载完成 - webViewDidFinishLoad

function clickLink() 
    var links = document.getElementsByTagName('a');
    for (i = 0; i < links.length; i++) 
        if (links[i].innerHTML.indexOf('Prev') != -1) 
            window.location = links[i].getAttribute('href').replace(/^\s\s*/, '').replace(/\s\s*$/, '');
            break;
        
    


setTimeout(clickLink, 1000);

jsFiddle 使用您的示例代码演示了这一点:http://jsfiddle.net/fzKL7/5/

【讨论】:

不幸的是,您的代码对我不起作用。它只是停留在同一页面上? @pixelbitlabs 您能否发布一些包含您尝试单击的链接之一的 HTML 源代码?我发布的代码应该可以工作,但是如果没有看到任何代码,很难确切地知道你的情况。 只是要注意(我知道这听起来很明显)我不想同时单击它们。我刚在“前一天”尝试过,最初进行了测试,但没有成功。 @pixelbitlabs 你有错误吗?有什么吗?如果将 js 替换为 alert('Hello World!'); 会起作用吗? alert(links.length); 怎么样? alert(links[i]);?无关,代码中的最后一个 stringWithFormat 是不必要的。 @pixelbitlabs 我很乐意为您提供进一步的帮助,但我不知所措 - 根据您提供的示例数据,我的 Javascript 工作正常。我们还从另一个用户那里得到验证,它可以在 iOS 应用程序的上下文中运行,并且通过设置警报,您可以自己看到 Javascript 正在您的应用程序中执行。如果没有坐在你的代码前,我不确定我还能为你做什么。如果您只是执行window.location = 'http://apple.com/'; 和/或window.location = 您的URL 之一怎么办?可能有助于缩小范围。【参考方案2】:

我创建了一个示例应用程序,其中包含 hooleyhoop 在 cmets 中提到的另一个 SO 问题中的功能。

这就是我最终的结果:

- (void)webViewDidFinishLoad:(UIWebView *)wv 
    // Called when the website has finished loading and triggers the JS code
    NSString *javascript = @"function simulate(element, eventName) \
     \
        var options = extend(defaultOptions, arguments[2] || ); \
        var oEvent, eventType = null; \
        for (var name in eventMatchers) \
         \
            if (eventMatchers[name].test(eventName))  \
                eventType = name; break; \
             \
         \
        if (!eventType)  \
            alert('Only HTMLEvents and MouseEvents interfaces are supported'); \
         \
        if (document.createEvent) \
         \
            oEvent = document.createEvent(eventType); \
            if (eventType == 'HTMLEvents') \
             \
                oEvent.initEvent(eventName, options.bubbles, options.cancelable); \
             \
            else \
             \
            oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView, options.button, options.pointerX, options.pointerY, options.pointerX, options.pointerY, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element); \
             \
            element.dispatchEvent(oEvent); \
         \
        else \
         \
            options.clientX = options.pointerX; \
            options.clientY = options.pointerY; \
            var evt = document.createEventObject(); \
            oEvent = extend(evt, options); \
            element.fireEvent('on' + eventName, oEvent); \
         \
        return element; \
     \
    function extend(destination, source)  \
        for (var property in source) \
            destination[property] = source[property]; \
        \
        return destination; \
     \
    var eventMatchers =  \
        'HTMLEvents': /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/, \
        'MouseEvents': /^(?:click|dblclick|mouse(?:down|up|over|move|out))$/ \
    ; \
    var defaultOptions =  \
        pointerX: 0, \
        pointerY: 0, \
        button: 0, \
        ctrlKey: false, \
        altKey: false, \
        shiftKey: false, \
        metaKey: false, \
        bubbles: true, \
        cancelable: true \
    ; \
    window.setTimeout(function()  \
        var links = document.getElementsByTagName('a'); \
        for(var i in links)  \
            if(links[i].innerHTML == 'Test')  \
                simulate(links[i], 'click'); \
             \
         \
    ,1);";
    // Execute JS
    [webView stringByEvaluatingJavaScriptFromString:javascript];

测试 HTML

<html>
    <head>
        <title>Testpage</title>
    </head>
    <body>
        <a href="http://www.google.com">I'm linking to google.com</a><br />
        <a href="http://www.***.com">Test</a>
    </body>
</html>

- (void)webViewDidFinishLoad:(UIWebView *)wv

这是 UIWebView 的委托函数,它会在 Web 视图完成加载网站后立即调用。

NSString *javascript = @"..."

这就是我构建 JS 代码的地方,一开始,触发点击的另一个 SO 问题的函数。最后,我设置了一个超时,执行查找所有“a”标签的部分,循环遍历它们,检查它的 innerHTML 文本是否为“Test”,如果是这种情况,它使用 a 元素调用 simulate 函数作为第一个参数,事件类型作为第二个参数。砰,链接被点击了。

我使用了超时,因为它导致直接执行 JS 出现问题,似乎 UIWebView 需要一些时间才能模拟功能可用。

干杯, 比约恩

【讨论】:

感谢您的回答!如果链接文本没有 ID 或任何内容,只有纯文本,这会起作用吗? :-) 是的,我将用于测试的 HTML 代码添加到我的答案中。 你也可以用 David 的 JS 代码代替我的,它更小而且做同样的事情 ;-)

以上是关于使用“stringByEvaluatingJavaScriptFromString”单击 UIWebView 中的链接的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)