Вызов методов в модулях RequireJs из элементов HTML, таких как обработчики onclick
Я изменяю проект со "старой" структуры модуля в стиле браузера на "новую" структуру модуля javascript на стороне браузера или сервера с помощью require.js.
На клиентском компьютере я использую размещенный на хосте jQuery, поэтому я начал с примера, который они приводят в методе "использовать приоритет конфигурации" README:
<title>My Page</title>
<script src="scripts/require.js"></script>
<script>
require({
baseUrl: 'scripts',
paths: {
jquery: 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min',
jqueryui: ...,
...
... // bunch more paths here
},
priority: ['jquery']
}, [ 'main' ]);
</script>
Это на самом деле работает хорошо. Но я бы хотел экспортировать функциональность с главной на саму веб-страницу HTML. Например:
<a class="button" href="#" onclick="MyApi.foo();">
<img src="foo.png" alt="foo" />Click for: <b>Foo!</b>
</a>
Прежде чем вписаться в шаблон модуля AMD, я раскрыл функциональность своих различных файлов, создав объект словаря в глобальном пространстве:
// main.js
var MyApi = {};
jQuery(document).ready(function($) {
// ...unexported code goes here...
// export function via MyApi
MyApi.foo = function() {
alert("Foo!");
};
});
Но я не знаю, каков правильный подход в require.js. Это нормально, чтобы положить в HTML больше require
заявления внутри <script>
теги, а затем назовите модули, чтобы их можно было использовать на веб-странице? Или это всегда должно выполняться динамически внутри main.js, например $('#foobutton').click(...)
?
4 ответа
Одним из преимуществ использования AMD является отказ от использования пространств имен. Попытка создать их снова с RequireJS будет идти вразрез с паттернами, продвигаемыми AMD.
Что касается использования main.js
это действительно уместно только тогда, когда у вас есть одностраничное приложение и весь ваш код будет ссылаться из одного места. Вы можете совершать дополнительные звонки по требованию и загружать другие модули по мере необходимости.
Используя ваш пример сверху, вы можете подойти к нему так:
foo.js
define(['jquery'], function($) {
// Some set up
// code here
// Return module with methods
return {
bar: function() {
}
}
});
page.js
require(['foo'], function(foo) {
// jQuery loaded by foo module so free to use it
$('.button').on('click', function(e) {
foo.bar();
e.preventDefault();
});
});
Затем на вашей странице запросите файл page.js с помощью require.
Используя ваш пример выше:
require({
// config stuff here
}, [ 'page' ]);
Или загрузите его на странице ниже:
<script>
require(['page']);
</script>
Некоторые дополнительные очки
Используя шаблон выше, page.js может легко потребовать много других модулей для загрузки других функций, связанных со страницей.
Если раньше вы присоединяли членов к своему глобальному пространству имен, теперь вы разбили этот код на отдельные модули, которые можно повторно использовать на любой странице. Все без опоры на глобальный объект.
Использование require таким способом для прикрепления событий к вашим элементам DOM, скорее всего, будет зависеть от модуля DOM Ready, предоставленного RequireJS.
Вы также можете установить ссылку на класс окна javascript.
В нижней части модуля приложения window.MyApi = MyApi;
<a class="button" href="#" onclick="MyApi.foo();"></a>
Сдачи onclick=""
внутри вашей разметки кажется грязным - смешивая презентацию с контентом. Я бы порекомендовал вам добавить <script>
заблокировать и поставить require
в нем, и однажды внутри обратного вызова, и внутри другого внутреннего $(document).ready()
при необходимости подключите обработчики событий обычным способом: $('#node').click(...)
, Если вы можете сделать это достаточно обобщенно, чтобы это применимо к нескольким страницам, поместите его во внешний файл, который будет свернут, объединен и кэширован. Но, как правило, эти вещи в конечном итоге специфичны для каждой страницы, поэтому <script>
Тег внизу страницы - это хорошее решение, чтобы избежать еще одного запроса внешнего ресурса.
Другое решение - просто использовать такой код (конечно, requirejs
необходимо добавить на страницу):
<input type="button" onclick="(function() { require('mymodule').do_work() })()"/>