Javascript:已定义名称空间中的评估外部脚本

时间:2019-03-27 01:48:29

标签: javascript namespaces eval javascript-namespaces

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

上下文

我目前正在为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);
    }
}

WebPart

// 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);
}

这很好,但是基于文件名构建名称空间是要求用户做的一件很粗略的事情,我很想找到比这种棘手的解决方案更直接的方法。

解决方案2

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

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

遵循这些原则:

MyExternalScript.js

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

WebPart

// 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,它们加载了不同的脚本,所以我必须不惜一切代价避免名称空间冲突。

有人有更好的主意吗?

谢谢!

2 个答案:

答案 0 :(得分:0)

我在这里不太了解上下文,但是如何将post render函数作为回调传递呢?

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

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

runExternalScript(postCallback)

答案 1 :(得分:0)

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

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

按照您的示例,我认为它看起来像这样:

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的解决方案,或者这几乎是可行的方法?

谢谢!