Использование SPFx Webpart с IE11, SharePoint 2016 и Pannellum
Мне нужны некоторые экспертные знания о веб-частях SPFx в сочетании с SharePoint 2016 и InternetExplorer 11. Идея заключается в создании веб-части, которая использует Pannellum для отображения изображений. В 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)
В инструментах разработчика я вижу, что изображение было загружено. Но так как код веб-части пытается вызвать createObjectURL
с изображением в качестве объекта BLOB-объекта он падает.
Веб-часть была создана с Yeoman (3.1.0) и протестирована с Gulp. Выполнить сценарий для Pannellum в веб-части. Я использую функцию executeScript из этого репозитория: https://github.com/SharePoint/sp-dev-fx-webparts/blob/dev/samples/react-script-editor/src/webparts/scriptEditor/ScriptEditorWebPart.ts
Я думаю, моя проблема связана с этим: IE + XMLHttp + CreateObjectURL Ошибка.
Кто-нибудь сталкивался с этим?
Вот пример кода:
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]();
}
}
}
2 ответа
IE не поддерживает URLSearchParams . Добавьте приведенный ниже фрагмент в ваш код (Polyfill), предпочтительно в constructor():
(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);
Я не нашел никакого решения для этой проблемы. Даже другие средства просмотра панорамы, которые работали как автономное решение в IE11, не работали в сочетании с IE11, SharePoint 2016 и SPFx Webpart.
Каждый раз это работало в Sharepoint с iframe. После развертывания на SharePoint он перестал работать из-за исключений. Большинство исключений были связаны с безопасностью.
Наиболее многообещающим подходом был просмотрщик сфер фотографий как iframe. Проблема заключалась в том, что образ должен был находиться в каталоге CDN с другими js- и HTML-файлами. В противном случае произошло исключение из-за безопасности и CORS (Cross-Origin Resource Sharing).