将 SPFx Webpart 与 IE11、SharePoint 2016 和 Pannellum 一起使用
Posted
技术标签:
【中文标题】将 SPFx Webpart 与 IE11、SharePoint 2016 和 Pannellum 一起使用【英文标题】:Using SPFx Webpart with IE11, SharePoint 2016 and Pannellum 【发布时间】:2019-11-22 01:44:53 【问题描述】:我需要一些有关 SPFx Web 部件以及 SharePoint 2016 和 InternetExplorer 11 的专业知识。
这个想法是创建一个使用 Pannellum 来显示图像的 Web 部件。在 Firefox 中它已经可以工作了。但是,对于 IE11,错误消息会出现在控制台中:SCRIPT5022: TypeMismatchError
BaseURL.ts (16,7)
SCRIPT5007: Die Eigenschaft "toString" eines undefinierten oder Nullverweises kann nicht abgerufen werden.
英文留言:The "toString" property of an undefined or null reference cannot be retrieved.
LogEvent.js (26,1)
在开发人员工具中,我可以看到图像已下载。但是当 webpart 的代码尝试调用 createObjectURL
并将图像作为 blob 对象时,它会崩溃。
Webpart 已使用 Yeoman (3.1.0) 创建并使用 Gulp 进行了测试。 在 webpart 中执行 Pannellum 的脚本我使用了这个 repo 中的 executeScript 函数:https://github.com/SharePoint/sp-dev-fx-webparts/blob/dev/samples/react-script-editor/src/webparts/scriptEditor/ScriptEditorWebPart.ts
我想我的问题与此有关:IE + XMLHttp + CreateObjectURL Error。
有人有这方面的经验吗?
这里有一些示例代码:
import Version from '@microsoft/sp-core-library';
import
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField
from '@microsoft/sp-webpart-base';
import escape from '@microsoft/sp-lodash-subset';
import SPComponentLoader from '@microsoft/sp-loader';
import styles from './TestWebPart.module.scss';
import * as strings from 'TestWebPartStrings';
require('../../../node_modules/pannellum/build/pannellum.css');
require('../../../node_modules/pannellum/build/pannellum.js');
export default class TestWebPart extends BaseClientSideWebPart<ITestWebPartProps>
public render(): void
let innerhtml: string = `
<script src="http://localhost:4321/node_modules/pannellum/build/pannellum.js"></script>
<script>
pannellum.viewer('panorama',
"type": "equirectangular",
"panorama": "test2.jpg",
"autoLoad": true
);
</script>
<style>
#panorama
width: 600px;
height: 400px;
</style>
<div id="panorama"></div>
`;
this.domElement.innerHTML = innerHTML;
this.executeScript(this.domElement);
private evalScript(elem)
const data = (elem.text || elem.textContent || elem.innerHTML || '');
const headTag = document.getElementsByTagName('head')[0] || document.documentElement;
const scriptTag = document.createElement('script');
scriptTag.type = 'text/javascript';
if (elem.src && elem.src.length > 0)
return;
if (elem.onload && elem.onload.length > 0)
scriptTag.onload = elem.onload;
try
// doesn't work on ie...
scriptTag.appendChild(document.createTextNode(data));
catch (e)
// IE has funky script nodes
scriptTag.text = data;
headTag.insertBefore(scriptTag, headTag.firstChild);
headTag.removeChild(scriptTag);
private nodeName(elem, name)
return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
// Finds and executes scripts in a newly added element's body.
// Needed since innerHTML does not run scripts.
//
// Argument element is an element in the dom.
private async executeScript(element: HTMLElement)
// Define global name to tack scripts on in case script to be loaded is not AMD/UMD
if (!window['_spPageContextInfo'])
window['_spPageContextInfo'] = this.context.pageContext.legacyPageContext;
(<any>window).ScriptGlobal = ;
// main section of function
const scripts = [];
const childrenNodes = element.childNodes;
for (let i: number = 0; childrenNodes[i]; i++)
const child: any = childrenNodes[i];
if (this.nodeName(child, 'script') &&
(!child.type || child.type.toLowerCase() === 'text/javascript'))
scripts.push(child);
const urls = [];
const onLoads = [];
for (let i: number = 0; scripts[i]; i++)
const scriptTag = scripts[i];
if (scriptTag.src && scriptTag.src.length > 0)
urls.push(scriptTag.src);
if (scriptTag.onload && scriptTag.onload.length > 0)
onLoads.push(scriptTag.onload);
let oldamd = undefined;
if (window['define'] && window['define'].amd)
oldamd = window['define'].amd;
window['define'].amd = undefined;
for (let i: number = 0; i < urls.length; i++)
try
let scriptUrl = urls[i];
const prefix = scriptUrl.indexOf('?') === -1 ? '?' : '&';
scriptUrl += prefix + 'cow=' + new Date().getTime();
await SPComponentLoader.loadScript(scriptUrl, globalExportsName: 'ScriptGlobal' );
catch (error)
if (console.error)
console.error(error);
if (oldamd)
window['define'].amd = oldamd;
for (let i: number = 0; scripts[i]; i++)
const scriptTag = scripts[i];
if (scriptTag.parentNode) scriptTag.parentNode.removeChild(scriptTag);
this.evalScript(scripts[i]);
// execute any onload people have added
for (let i: number = 0; onLoads[i]; i++)
onLoads[i]();
【问题讨论】:
您能否提供一些小的示例代码,我们可以尝试使用 IE 11 和其他浏览器进行测试以检查结果?它可以帮助我们了解这个问题。代码图像不会帮助我们找到问题。 我添加了一个示例代码。我希望它有所帮助。 IE 不能很好地支持 URL.createObjectURL()。最好使用window.navigator.msSaveOrOpenBlob,对于非ie,我们可以使用URL.createObjectURL() Ref: ***.com/questions/24007073/… and developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL 非常感谢您的提示。你知道我必须修改哪个文件吗?很难找到这方面的细节。 您需要找到所有使用 URL.createObjectURL() 的位置,并且需要在那里使用 window.navigator.msSaveOrOpenBlob。您可以尝试使用JS代码识别浏览器,并尝试针对特定浏览器执行特定代码。 【参考方案1】:我还没有找到任何解决这个问题的方法。即使是在 IE11 中作为独立解决方案工作的其他全景查看器,也无法在 IE11、SharePoint 2016 和 SPFx Webpart 的组合中工作。
每次它在带有 iframe 的 Sharepoint 中工作。将其部署到 SharePoint 后,由于异常而停止工作。大多数例外都与安全有关。
最有前途的方法是将 Photo Sphere Viewer 作为 iframe。问题是图像必须与其他 js 和 HTML 文件一起进入 CDN 目录。否则会因为安全性和 CORS(跨域资源共享)而出现异常。
【讨论】:
【参考方案2】:IE 不支持 URLSearchParams 。在您的代码(Polyfill)中添加以下 sn-p,最好在构造函数()中:
(function (w)
w.URLSearchParams = w.URLSearchParams || function (searchString)
var self = this;
self.searchString = searchString;
self.get = function (name)
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(self.searchString);
if (results == null)
return null;
else
return decodeURI(results[1]) || 0;
;
self.has = function (name)
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
if (results == null)
return false;
else
return true;
)(window);
【讨论】:
以上是关于将 SPFx Webpart 与 IE11、SharePoint 2016 和 Pannellum 一起使用的主要内容,如果未能解决你的问题,请参考以下文章
无法通过 App Catalog 将 SPFx webpart 部署到 sharepoint 2019
使用 ngrok 将 SPFX WebPart 隧道传输到 BrowserStack
在现代站点中添加 SPFx webpart 时的 Javascript