(Gatsby) 在我刷新页面之前,Datawrapper iframe 没有显示

(Gatsby) Datawrapper iframes aren't displaying before I've refreshed the page

我正在使用 Datawrapper 在我的网站上将图表显示为 iframe。

我最近刚从 Remark 迁移到 MDX。使用新设置后,我的 Datawrapper 图表不会在允许以“传统”方式加载包含图表的页面之前加载(即点击刷新或直接关注包含图表的页面)。

因此,如果您遵循此 link,图表显示良好:kolstadmagnus.no/ekspert-mener-a-ha-svaret-bak-krfs-stortingssmell

但是,如果您转到主页 (kolstadmagnus.no),然后点击 link(第二顶 post),图表将不会显示。


一些上下文

Datawrapper iframe 使用此脚本,以便 iframe 响应:

!function(){"use strict";window.addEventListener("message",(function(e){if(void 0!==e.data["datawrapper-height"]){var t=document.querySelectorAll("iframe");for(var a in e.data["datawrapper-height"])for(var r=0;r<t.length;r++){if(t[r].contentWindow===e.source)t[r].style.height=e.data["datawrapper-height"][a]+"px"}}}))}();

由于 Gatsby 按照它的方式工作(不是“传统地”加载每个页面——抱歉,我不知道这个功能叫什么),我不得不把这个脚本放在 html.js 文件中,像这样:

<body {...props.bodyAttributes}>
  {props.preBodyComponents}
  <div
    key={`body`}
    id="___gatsby"
    dangerouslySetInnerHTML={{ __html: props.body }}
  />
  {props.postBodyComponents}
  <script
    dangerouslySetInnerHTML={{
      __html: `
            !function(){"use strict";window.addEventListener("message",(function(e){if(void 0!==e.data["datawrapper-height"]){var t=document.querySelectorAll("iframe");for(var a in e.data["datawrapper-height"])for(var r=0;r<t.length;r++){if(t[r].contentWindow===e.source)t[r].style.height=e.data["datawrapper-height"][a]+"px"}}}))}(); `
    }}
  />
</body>;

这会导致脚本针对整个网站执行,而不仅仅是针对单个页面执行,从而解决了在使用 iframe 进入页面后需要点击刷新的问题。


虽然使用 MDX,问题又回来了。但是现在iframe根本不显示了。

我该如何解决这个问题?

Gatsby 从 @reach/router 扩展了它的导航和它的“加载页面”,所以从 React。

我非常不鼓励在 html.js 的某些页面中嵌入需要呈现的自定义脚本,因为正如您指出的那样,它将在全球范围内加载。您可以通过 运行 在本地或雾化它来实现相同的效果。

您面临的问题是脚本直接指向 DOM(因为使用了 window.addEventListener),而在 React 中(因此使用 Gatsby)您创建并操作了一个虚拟DOM (vDOM)。播放和操纵两者可能会导致误导行为,因为一个人不知道另一个人何时发生变化,反之亦然,从而破坏水合作用和再水化过程(这就是为什么你在刷新时看到结果:因为水合作用永远不会发生)。

也就是说,理想的解决方案是使用基于 React 的 Datawrapper 模块,例如 react-datawrapper-chart 或使用其他自定义解决方案。使脚本响应不是什么大事,您可以使用基于 React 的代码进行相同的计算。

或者,按照您的“工作”方法,您可以使用特定页面上的 Helmet 组件加载自定义脚本:

const SomeSpecificPage = () =>{

return <>
   <Helmet>
    <script
       dangerouslySetInnerHTML={{
         __html: `
               !function(){"use strict";window.addEventListener("message", 
  (function(e){if(void 0!==e.data["datawrapper-height"]){var 
t=document.querySelectorAll("iframe");for(var a in e.data["datawrapper-height"])for(var r=0;r<t.length;r++){if(t[r].contentWindow===e.source)t[r].style.height=e.data["datawrapper-height"][a]+"px"}}}))}(); `
    }}
  />
   </Helmet>
</>

}