Извините за эссе, не могу найти краткий способ объяснить это: (
Context
В настоящее время я создаю WebPart для Office 365, который во многом напоминает клиентское приложение, которое пользователи могут добавлять на свою страницу и настраивать с помощью пользовательского интерфейса.
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 WebParts, загружающих разные скрипты, поэтому я должен избегать конфликтов пространства имен любой ценой.
У кого-нибудь есть идея получше?
Спасибо!