javascript - 通过Chrome Extension内容脚本在iFrame中激活Zurb Foundation的Joyride

标签 javascript iframe google-chrome-extension zurb-foundation zurb-joyride

我正在构建一个Chrome扩展程序,该扩展程序可以在任何HTML页面(即在浏览器窗口中查看的任何页面)内创建iFrame。

Chrome扩展程序的内容脚本将iFrame“注入”到HTML页面中。生成的HTML如下所示:

<html>
  <head>..</head>
  <body>..</body>
  <iframe id="myIframe">...</iframe>
</html>


在内容脚本将iFrame添加到主页的DOM之后,它继续通过操作其自己的DOM在iframe中填充内容。我使用Zurb CSS设置iframe内容的样式。

这一切都很好。

我现在正在尝试将Zurb Joyride添加到iframe的内容中,而这正是我无法工作的原因。

我清单的content_scripts声明如下所示:

"content_scripts": [{
    "matches":    ["*://*/*"],
    "js":         ["js/externalJS/jquery-2.1.4.min.js",
                   "js/externalJS/foundation.min.js",
                   "js/content_script.js"],
    "run_at":     "document_end"
}],


我怀疑iframe本身需要访问Zurb脚本,因此作为清单的一部分由清单清单加载Foundation.min.js,我的内容脚本还在iframe中添加了相关标签(通过操作DOM) )。我的理解是iframe中的关键元素是:


 Zurb JS文件的标签
将操纵杆附加到(id =“ testjoyride”)的对象
喜乐内容本身
对Foundation()的初始化调用


因此,考虑到这一点,我使清单的web_accessible_resources声明看起来像这样:

"web_accessible_resources": [

    "js/externalJS/jquery-2.1.4.min.js",
    "js/externalJS/vendor/modernizr.js",
    "js/externalJS/vendor/fastclick.js",
    "js/externalJS/foundation.min.js",
    "css/foundation.css",
    "css/app.css"
],


然后使用内容脚本在iframe中构建以下HTML:

<iframe id="myIframe">
  <html>
    <head>

      <!-- the foundation style sheet (which works fine already) -->
      <link type="text/css" rel="stylesheet" href="chrome-extension://extension_id/css/foundation.css">

      <!-- the first two scripts -->
      <script src="chrome-extension://extension_id/js/externalJS/vendor/modernizr.js"></script>
      <script src="chrome-extension://extension_id/js/externalJS/jquery-2.1.4.min.js"></script>

    </head>

    <body>

      <!-- a test object to attach the joyride too -->
      <input type="submit" id="testjoyride">

      <!-- now the rest of the iframe content -->
      ... content ...

      <!-- the other two scripts -->
      <script src="chrome-extension://extension_id/js/externalJS/vendor/fastclick.js"></script>
      <script src="chrome-extension://extension_id/js/externalJS/foundation.min.js"></script>

      <!-- default joyride code from foundation.zurb.com -->
      <ol class="joyride-list" data-joyride="">  
        <li data-id="testjoyride" data-class="custom so-awesome" data-text="Next" data-prev-text="Prev">    
         <h4>Stop #1</h4>    
        </li>
        <li data-button="end" data-prev-text="Prev">
          <h4>Stop #3</h4>
        </li>
      </ol>

    </body>
  </html>
</iframe>


然后,最后,当上述所有内容都附加到iframe(并且iframe当然也附加到父页面的DOM)时,我从content_script调用foundation()。

我想我应该这样称呼它:
    $(window.frames.myIframe.contentWindow.document).foundation('joyride','start');

即传入iframe的文档对象,而不是父页面**

所以我做了所有这些,没有任何反应。没有出现操纵杆,也没有将HTML转换为自动生成的输出(如here所述)。

我已经在一个简单的HTML页面中创建了一个测试用例,并且工作正常,我试图将测试页面移至iframe中,并且Joyride停止工作。因此,尽管没有太多信心,但我怀疑问题出在iframe,而不是Chrome扩展。

**注意,我将此调用直接放在所有DOM操作的末尾。在将新创建的HTML添加到iframe的DOM之后,以及在创建所有侦听器之后,等等。因此,我有信心在那时脚本和操纵杆应位于“那里”。但是,如果我刚好在调用Foundation('joyride','start')之前粘贴了alert(),则该警告显示后会带有一个空的iframe,并且只有在我关闭该警告之后,iframe才会填充。这是重要的还是警报的奇怪效​​果,我不知道。

最佳答案

多亏了一些有用的评论,我设法使这项工作奏效。完全相同的解决方案也可以正常工作。因此,这是以下解决方案:


第三方javascript程序包(特别是JQuery,Foundation Zurb Joyride和QTip2)...
...由Chrome扩展程序以编程方式注入...
...放入iFrame-Chrome扩展程序本身已将其注入用户的当前网页


我将尽力在下面进行描述。我是自学成才的人,仍然是新手,因此对任何令人困惑的术语或与最佳实践的差异表示歉意。

解决方案概述

我最终将Chrome扩展程序分为三个级别:


一个控制扩展的后台脚本(与该特定问题无关紧要,但出于完整性考虑,值得一提)。
内容脚本从后台脚本接收命令,并以编程方式将iframe,iframe HTML内容和第3部分JS程序包注入用户的网页。
“ iframe脚本”,这是一个自定义JS脚本,与第3方程序包一起注入了iframe。该iframe脚本可以向内容脚本发送消息/从内容脚本接收消息,同时可以访问第三方JS程序包-Zurb Joyride和QTips


清单

尽管内容脚本(content_script.js)控制着所有注入,但它实际上从未运行任何第三方JS包本身。它们由用户的网页运行。因此,清单的content_scripts声明如下所示:

"content_scripts": [{
        "matches":    ["*://*/*"],
        "js":         ["js/content_script.js"],
        "run_at":     "document_end"
    }],


由于该网页需要访问第三方脚本,因此必须被授予权限。它还需要访问我们的自定义iframe脚本:

"web_accessible_resources": [
        "js/iframe_script.js",

        "js/externalJS/jquery-2.1.4.min.js",
        "js/externalJS/jquery.qtip.min.js",
        "js/externalJS/vendor/modernizr.js",
        "js/externalJS/vendor/fastclick.js",
        "js/externalJS/foundation.min.js",
        "css/foundation.css",
        "css/jquery.qtip.min.css"
    ],


内容脚本:将Joyride HTML注入iframe

内容脚本创建一个iframe元素(id =“ myIframe”)并将其附加到用户的网页。然后继续以编程方式将其填充内容。

其中一些内容将成为joyride的基础:ID设置为joyrideStop1,joyrideStop2等的HTML元素:

iframeContentHTML += <i class="fi-info brandSpielIcon" id="joyrideStop1"></i>


内容脚本还根据iaa主体底部的QTip2建立了Joyride HTML。

joyrideHTML += '<ol class="joyride-list" data-joyride>';
joyrideHTML += '  <li data-id="joyrideStop1" data-text="Next (1 of 5)" data-prev-text="Prev" class="customJoyride">';
joyrideHTML += '    <h4>Title</h4>';
joyrideHTML += '    <p>Content</p>';
joyrideHTML += '  </li>';
... 


我的自定义CSS类很简单:

.customJoyRide .joyride-nub {
    visibility: hidden;
}


这使Joyride工具提示上的小尖箭头消失了。尝试使操纵杆在小型iframe中很好地显示时,我遇到了重大问题。理想情况下,我希望它们锚定到iframe中的元素,但要显示为好像它们是主页的一部分。最后,这似乎太难了或不可能,所以我只是删除了小块并回避了这个问题。这是一个显示问题,仅是小型iframe的问题,因此不是此解决方案的核心部分。

内容脚本:将JS注入iframe

为了使Joyride正常工作,我们需要将第3方脚本和自定义iframe_script.js注入到iframe中。这是来自content_script.js的第三方脚本之一的代码示例:

// Inject foundation script into iframe body
var foundationScript = document.createElement('script');
foundationScript.src = chrome.extension.getURL('js/externalJS/foundation.min.js');
window.frames.myIframe.contentWindow.document.body.appendChild(foundationScript);


注意解决方案的这一部分纠正了我的原始错误之一。如果仅将文本附加到innerHTML上,脚本似乎就不会初始化:body.innerHTML += '<script src=".."></script>;'

因此,我对所有脚本重复以上代码。在iframe头中,我输入了:


jquery.qtipmin.css
modernizr.js
jquery-2.1.4.min.js


然后在iframe主体的底部放置:


fastclick.js
foundation.min.js
jquery.qtip.min.js
iframe_script.js。


以该顺序。

iframe脚本:初始化

当iframe_script.js初始化时,我立即获得它以添加消息侦听器(以便内容脚本可以与之通信),然后向内容脚本发送一条消息以告知它已准备就绪(内容脚本已经设置了自己的消息侦听器) ,此处未详细说明其代码):

(function initialise(){

    // Listen for messages from the content script
    window.addEventListener("message", contentScriptMessage_listener, false);

    // Tell the content script we're ready to go
    window.parent.postMessage({sender:  'iframe_script',
                               subject: 'iframeScriptHasInitialised'}, '*');
})();


注意在我的content_script将其第一条消息发送到iframe之前,我很难确保已设置iframe的侦听器。最后,该解决方案(等待从iframe返回消息)似乎效果最好,尽管我怀疑可能会有更好的方法

内容脚本:告诉iframe激活操纵杆

现在,内容脚本知道iframe侦听器已准备就绪,可以告诉它激活Zurb joyride(和/或QTips)。我是通过将消息发送回iframe来实现的。

window.frames.myIframe.contentWindow.postMessage({
    sender:  'content_script', 
    subject: 'pleaseActivateJoyride'}, '*');


显然,直接从iframe脚本激活Joyride会更简单,而不会使所有这些消息来回跳动。但这就是重点:内容脚本知道是否应显示操纵杆,更不用说所有其他配置详细信息了。使用内容脚本(最终使用后台脚本)进行控制,可以使整体实现更为整洁。

iframe脚本:激活Joyride

我的iframe脚本的消息处理程序从内容脚本接收消息并调用此函数:

function activateJoyride(){

    $(document).foundation({
        joyride: {
            ... configuration ...
        }
    });

    $(document).foundation('joyride', 'start');
}


注意我这里有一个悬而未决的问题。这有时可以在加载JQuery之前运行,从而导致错误(“未声明$”)。为了解决这个问题,我玩过window.setTimeout,它几乎一直都在工作...但是不是100%

就是这样!

QTips有一个匹配的激活功能,之前已将适当的内容注入到iframe中。就像使用Joyride一样,我在小型iframe中尝试渲染Qtips时也很费劲。 QTip2功能更强大,文档建议其中有Zurb docs

关于javascript - 通过Chrome Extension内容脚本在iFrame中激活Zurb Foundation的Joyride,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32439431/

相关文章:

JavaScript。如何禁止对象属性创建

javascript - JavaScript 中对象的 "internal slot"是什么?

javascript - 合并两个代码片段?将用户输入的 Youtube url 转换为嵌入 url,然后用转换后的 url 替换 iframe src

google-chrome-extension - 如何从 chrome 扩展程序的上下文菜单中打开默认弹出窗口

javascript - 从城市名称获取 WOEID?

javascript - 为什么 delete 运算符返回 true 即使属性没有从对象中删除

javascript - 数值数组排序()

javascript - 如何使用 ReactJS 监听 iframe keydown 事件

javascript - 最初隐藏 iframe 时,Vimeo Javascript API 不起作用

javascript - 通过 WebExtensions 获取 Firefox 中 browser.storage.local 的大小