web-dev-qa-db-fra.com

Appel de méthodes dans les modules RequireJs à partir d'éléments HTML tels que les gestionnaires onclick

Je change un projet d'une "ancienne" structure de module de style navigateur à un "nouveau" navigateur - ou - côté serveur -javascript structure du module avec require.js .

Sur le client, j'utilise un jQuery hébergé hors site, donc je suis parti de l'exemple qu'ils donnent dans la technique "use priority config" du 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>

Cela fonctionne vraiment bien. Mais j'aimerais exporter des fonctionnalités du principal vers la page Web HTML elle-même. Par exemple:

<a class="button" href="#" onclick="MyApi.foo();">
    <img src="foo.png" alt="foo" />Click for: <b>Foo!</b>
</a>

Avant de m'intégrer dans le modèle de module AMD, j'avais exposé les fonctionnalités de mes différents fichiers en créant un objet dictionnaire dans l'espace global:

// main.js

var MyApi = {};

jQuery(document).ready(function($) {
    // ...unexported code goes here...

    // export function via MyApi
    MyApi.foo = function() {
        alert("Foo!");
    };
});

Mais je ne sais pas quelle est la bonne approche dans require.js. Est-il correct de mettre dans le code HTML plus d'instructions require à l'intérieur des balises <script>, Puis de nommer les modules afin qu'ils puissent être utilisés à partir de la page Web? Ou cela devrait-il toujours être fait dynamiquement à l'intérieur de main.js, comme $('#foobutton').click(...)?

34
HostileFork

L'un des avantages de l'utilisation d'AMD est de supprimer le besoin d'espaces de noms. Essayer de les recréer avec RequireJS ira à l'encontre des modèles promus par AMD.

En ce qui concerne l'utilisation de main.js, cela n'est vraiment approprié que si vous avez une application d'une seule page et que tout votre code est référencé à partir d'un seul endroit. Vous êtes libre de faire des appels supplémentaires pour exiger et charger d'autres modules selon vos besoins.

En utilisant votre exemple ci-dessus, vous pouvez l'approcher de cette façon:

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

});

Ensuite, dans votre page, demandez le fichier page.js avec require.

En utilisant votre exemple ci-dessus:

require({
    // config stuff here
}, [ 'page' ]);

Ou en le chargeant dans la page plus bas:

<script>
    require(['page']);
</script>

Quelques points supplémentaires

  • En utilisant le modèle ci-dessus, page.js pourrait facilement nécessiter de nombreux autres modules pour charger d'autres fonctionnalités liées à la page.

  • Là où auparavant vous attacheriez des membres à votre espace de noms global, vous divisez maintenant ce code en modules distincts qui peuvent être réutilisés sur n'importe quelle page. Le tout sans dépendre d'un objet global.

  • L'utilisation de cette méthode pour attacher des événements à vos éléments DOM sera très probablement s'appuyer sur le module DOM Ready fourni par RequireJS

31
Simon Smith

Vous pouvez également définir la référence sur la classe de fenêtre de javascript.

Au bas du module d'application window.MyApi = MyApi;

<a class="button" href="#" onclick="MyApi.foo();"></a>

16
jonperl

Une autre solution consiste simplement à utiliser du code comme ça (bien sûr requirejs doit être ajouté à la page):

<input type="button" onclick="(function() { require('mymodule').do_work() })()"/>
2
feeeper