Javascript:定义的命名空间中的Eval外部脚本

问题描述 投票:0回答:2

对不起文章,找不到一个简短的方法来解释这个:(

上下文

我目前正在为Office 365构建一个WebPart,它非常像用户可以添加到其页面并通过UI进行配置的客户端应用程序。

WebPart呈现一些内容,我希望用户能够提供可在渲染过程之后运行的外部脚本。到目前为止,这很简单,我可以在WebPart代码中执行类似的操作:

// Render the WebPart
this.render();

// Load external script
this.loadExternalScript(this.props.externalScriptUrl);

问题是我希望外部脚本像回调一样,我的WebPart可以调用它来为它提供一些上下文。

解决方案1

我发现的第一个解决方案是为用户提供如何使用基于文件名的特定命名空间创建外部脚本的指导,以及一个精确的函数,以便我的WebPart可以:

  • 给予
  • 加载外部脚本(将填充该特定命名空间)
  • 检索外部脚本的命名空间(基于文件名)
  • 使用命名空间调用外部脚本回调并提供上下文

这很好用,它看起来像这样:

MyExternalScript.js

MyNamespace.ExternalScripts.MyExternalScript = {

    onPostRender: function(wpContext) {
        console.log(wpContext);
    }
}

卷筒纸

// Render the WebPart
this.render();

// Load external script
this.loadExternalScript(this.props.externalScriptUrl);

// Calls the script callback if available
var scriptNamespace = MyNamespace.ExternalScripts.MyExternalScript;
var scriptCallback = scriptNamespace  ? scriptNamespace.onPostRender : null;

if(scriptCallback) {
    scriptCallback(this.wpContext);
}

这很好但是根据文件的名称构建命名空间是一个非常粗略的事情要求用户这样做,我很想找到比这个hacky解决方案更直接的东西。

解决方案2

我想到的另一个解决方案是执行以下操作:

  • 从外部脚本中删除时髦的命名空间并保留定义的函数签名
  • 将脚本内容加载为字符串
  • 让WebPart为该特定脚本动态创建唯一的命名空间名称
  • 使用命名空间预先添加脚本内容
  • eval()整个事情
  • 拨打回叫

这将是这样的:

MyExternalScript.js

onPostRender: function(wpContext) {
    console.log(wpContext);
}

卷筒纸

// Render the WebPart
this.render();

// Load external script content
$scriptContent = this.readExternalScript(this.props.externalScriptUrl);

// Append unique namespace
$scriptContent = "MyNamespace.ExternalScripts.MyExternalScript = {" + $scriptContent + "}";

// Eval everything within that namespace
eval($scriptContent);

// Calls the script callback if available
var scriptNamespace = MyNamespace.ExternalScripts.MyExternalScript;
var scriptCallback = scriptNamespace  ? scriptNamespace.onPostRender : null;

if(scriptCallback) {
    scriptCallback(this.wpContext);
}

我做了一些快速测试,看起来它正在工作,WebPart动态生成命名空间的事实比要求用户遵守复杂的命名空间更好,但是我不确定是否有比使用eval更好的解决方案( )。

我在一天结束时所需要的只是找到一种方法让我的WebPart“了解”它需要调用的回调。我还必须确保命名空间是WebPart唯一且脚本唯一的,因为在同一页面上可能有4个WebPart,加载不同的脚本,因此我必须不惜一切代价避免命名空间冲突。

谁有更好的主意?

谢谢!

javascript namespaces eval javascript-namespaces
2个回答
0
投票

我不太明白这里的上下文,但是如何将post渲染函数作为回调传递?

var runExternalScript = Function('onPostRender', `
// your external script
  console.log('rendering...');
  console.log('rendering finished');
  if (onPostRender) onPostRender();
`)

function postCallback(){ console.log('finished!') }

runExternalScript(postCallback)

0
投票

因此,正如我的评论中所解释的那样,主要目标是能够执行一个外部脚本,该脚本可以访问WebPart提供的“魔术”变量“wpContext”。

外部脚本被调用/评估的时间并不重要,因为WebPart决定何时调用它。

按照你的例子,我认为它看起来更像是这样的:

卷筒纸

// Render the WebPart
this.render();

// Load the external script
var runExternalScript = Function('wpContext', `
  // External script content
  console.log('External script is able to use the WebPart context!');
  console.log(wpContext);
`);

// Run the external script while providing the current WebPart's context
runExternalScript(this.wpcontext)

这比我的eval()更优雅,因为我没有任何命名空间来生成,并且外部脚本甚至不必遵守特定的函数签名,以便WebPart检索它,它可以简单地使用“wpContext”变量直接在其内容中。

所以,即使这看起来像是一个更好的解决方案,我还缺少另一个不需要使用eval / Function的解决方案,或者这几乎是要走的路?

谢谢!

© www.soinside.com 2019 - 2024. All rights reserved.