Czy w JavaScript jest coś podobnego do @import
CSS, co pozwala na dołączenie pliku JavaScript do innego pliku JavaScript?
script
tagów?
Czy w JavaScript jest coś podobnego do @import
CSS, co pozwala na dołączenie pliku JavaScript do innego pliku JavaScript?
script
tagów?
Odpowiedzi:
Stare wersje JavaScript nie importowały, nie zawierały ani nie wymagały, dlatego opracowano wiele różnych podejść do tego problemu.
Ale od 2015 r. (ES6) JavaScript ma standard modułów ES6 do importowania modułów w Node.js, który jest również obsługiwany przez większość nowoczesnych przeglądarek .
W celu zapewnienia zgodności ze starszymi przeglądarkami można używać narzędzi do budowania, takich jak Webpack i Rollup, i / lub narzędzi do transpozycji, takich jak Babel .
Moduły ECMAScript (ES6) są obsługiwane w Node.js od wersji 8.5, z --experimental-modules
flagą, i od co najmniej Node.js wersji 13.8.0 bez flagi. Aby włączyć „ESM” (w porównaniu z poprzednim systemie modułu CommonJS stylu node.js za [ „CJS”]) użyć albo "type": "module"
w package.json
lub dać pliki z rozszerzeniem .mjs
. (Podobnie moduły napisane przy użyciu poprzedniego modułu CJS Node.js można nazwać, .cjs
jeśli domyślnym jest ESM.)
Używanie package.json
:
{
"type": "module"
}
Następnie module.js
:
export function hello() {
return "Hello";
}
Następnie main.js
:
import { hello } from './module.js';
let val = hello(); // val is "Hello";
Używając .mjs
będziesz miał module.mjs
:
export function hello() {
return "Hello";
}
Następnie main.mjs
:
import { hello } from './module.mjs';
let val = hello(); // val is "Hello";
Przeglądarki mają obsługę bezpośredniego ładowania modułów ECMAScript (nie są wymagane żadne narzędzia, takie jak Webpack) od Safari 10.1, Chrome 61, Firefox 60 i Edge 16. Sprawdź bieżącą obsługę w caniuse . Nie ma potrzeby używania .mjs
rozszerzenia Node.js ; przeglądarki całkowicie ignorują rozszerzenia plików w modułach / skryptach.
<script type="module">
import { hello } from './hello.mjs'; // Or it could be simply `hello.js`
hello('world');
</script>
// hello.mjs -- or it could be simply `hello.js`
export function hello(text) {
const div = document.createElement('div');
div.textContent = `Hello ${text}`;
document.body.appendChild(div);
}
Czytaj więcej na https://jakearchibald.com/2017/es-modules-in-browsers/
Dynamiczne importowanie pozwala skryptowi ładować inne skrypty w razie potrzeby:
<script type="module">
import('hello.mjs').then(module => {
module.hello('world');
});
</script>
Czytaj więcej na https://developers.google.com/web/updates/2017/11/dynamic-import
Starszym stylem modułu CJS, wciąż szeroko stosowanym w Node.js, jest module.exports
/require
system.
// mymodule.js
module.exports = {
hello: function() {
return "Hello";
}
}
// server.js
const myModule = require('./mymodule');
let val = myModule.hello(); // val is "Hello"
Istnieją inne sposoby włączania przez JavaScript zewnętrznych treści JavaScript w przeglądarkach, które nie wymagają wstępnego przetwarzania.
Możesz załadować dodatkowy skrypt z wywołaniem AJAX, a następnie użyć go eval
do uruchomienia. Jest to najprostszy sposób, ale jest ograniczony do Twojej domeny ze względu na model bezpieczeństwa piaskownicy JavaScript. Korzystanie eval
również otwiera drzwi do błędów, włamań i problemów bezpieczeństwa.
Podobnie jak w przypadku dynamicznych importów, możesz załadować jeden lub wiele skryptów z fetch
wywołaniem, używając obietnic do kontrolowania kolejności wykonywania zależności skryptów za pomocą biblioteki Fetch Inject :
fetchInject([
'https://cdn.jsdelivr.net/momentjs/2.17.1/moment.min.js'
]).then(() => {
console.log(`Finish in less than ${moment().endOf('year').fromNow(true)}`)
})
JQuery biblioteki zapewnia funkcjonalność ładowania w jednej linii :
$.getScript("my_lovely_script.js", function() {
alert("Script loaded but not necessarily executed.");
});
Możesz dodać tag HTML ze skryptu URL do HTML. Jest to idealne rozwiązanie, aby uniknąć narzutów związanych z jQuery.
Skrypt może nawet znajdować się na innym serwerze. Ponadto przeglądarka ocenia kod. <script>
Znacznik może być wstrzykiwany do każdej strony internetowej <head>
, lub włożona tuż przed zamykającym </body>
tagiem.
Oto przykład, jak to może działać:
function dynamicallyLoadScript(url) {
var script = document.createElement("script"); // create a script DOM node
script.src = url; // set its src to the provided URL
document.head.appendChild(script); // add it to the end of the head section of the page (could change 'head' to 'body' to add it to the end of the body section instead)
}
Ta funkcja doda nowy <script>
znacznik na końcu sekcji nagłówka strony, gdzie src
atrybut jest ustawiony na adres URL podany funkcji jako pierwszy parametr.
Oba te rozwiązania zostały omówione i zilustrowane w JavaScript Madness: Dynamic Script Loading .
Teraz jest duży problem, o którym musisz wiedzieć. Oznacza to, że zdalnie ładujesz kod . Nowoczesne przeglądarki internetowe załadują plik i wykonają bieżący skrypt, ponieważ ładują wszystko asynchronicznie, aby poprawić wydajność. (Dotyczy to zarówno metody jQuery, jak i metody ręcznego dynamicznego ładowania skryptów.)
Oznacza to, że jeśli użyjesz tych sztuczek bezpośrednio, nie będziesz mógł użyć nowo załadowanego kodu w następnym wierszu po tym, jak poprosiłeś o jego załadowanie , ponieważ nadal będzie się ładował .
Na przykład: my_lovely_script.js
zawiera MySuperObject
:
var js = document.createElement("script");
js.type = "text/javascript";
js.src = jsFilePath;
document.body.appendChild(js);
var s = new MySuperObject();
Error : MySuperObject is undefined
Następnie ponownie ładujesz uderzanie strony F5. I to działa! Zagmatwane...
Co z tym zrobić?
Możesz użyć hacka, który autor sugeruje w linku, który ci podałem. Podsumowując, dla osób, którym się spieszy, używa zdarzenia do uruchomienia funkcji zwrotnej po załadowaniu skryptu. Możesz więc umieścić cały kod za pomocą biblioteki zdalnej w funkcji wywołania zwrotnego. Na przykład:
function loadScript(url, callback)
{
// Adding the script tag to the head as suggested before
var head = document.head;
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
// Then bind the event to the callback function.
// There are several events for cross browser compatibility.
script.onreadystatechange = callback;
script.onload = callback;
// Fire the loading
head.appendChild(script);
}
Następnie piszesz kod, którego chcesz użyć PO załadowaniu skryptu do funkcji lambda :
var myPrettyCode = function() {
// Here, do whatever you want
};
Następnie wykonujesz to wszystko:
loadScript("my_lovely_script.js", myPrettyCode);
Zauważ, że skrypt może zostać wykonany po załadowaniu DOM lub wcześniej, w zależności od przeglądarki i tego, czy podałeś wiersz script.async = false;
. Ogólnie jest świetny artykuł na temat ładowania Javascript .
Jak wspomniano na początku tej odpowiedzi, wielu programistów używa w swoich projektach narzędzi do kompilacji / transpilacji, takich jak Parcel, Webpack lub Babel, co pozwala im korzystać z nadchodzącej składni JavaScript, zapewniać zgodność wsteczną dla starszych przeglądarek, łączyć pliki, minimalizować, wykonać dzielenie kodu itp.
onreadystatechange
zdarzenia i readyState
właściwości). Ponadto dynamiczne ładowanie skryptów nie korzysta ze skanerów wstępnego ładowania przeglądarki. Poleć ten artykuł HTML5Rocks: html5rocks.com/en/tutorials/speed/script-loading
Jeśli ktoś szuka czegoś bardziej zaawansowanego, wypróbuj RequireJS . Dostaniesz dodatkowe korzyści, takie jak zarządzanie zależnościami, lepsza współbieżność i unikanie powielania (czyli pobierania skryptu więcej niż jeden raz).
Możesz pisać pliki JavaScript w „modułach”, a następnie określać je jako zależności w innych skryptach. Lub możesz użyć RequireJS jako prostego rozwiązania „idź dostać ten skrypt”.
Przykład:
Zdefiniuj zależności jako moduły:
some-dependency.js
define(['lib/dependency1', 'lib/dependency2'], function (d1, d2) {
//Your actual script goes here.
//The dependent scripts will be fetched if necessary.
return libraryObject; //For example, jQuery object
});
Implementacja.js to „główny” plik JavaScript, który zależy od pliku dependence.js
require(['some-dependency'], function(dependency) {
//Your script goes here
//some-dependency.js is fetched.
//Then your script is executed
});
Fragment GITHub README:
RequireJS ładuje zwykłe pliki JavaScript, a także bardziej zdefiniowane moduły. Jest zoptymalizowany do użytku w przeglądarce, w tym w Web Worker, ale może być używany w innych środowiskach JavaScript, takich jak Rhino i Node. Implementuje interfejs API modułu asynchronicznego.
RequireJS używa prostych tagów skryptowych do ładowania modułów / plików, więc powinno to umożliwić łatwe debugowanie. Można go użyć do załadowania istniejących plików JavaScript, dzięki czemu można dodać go do istniejącego projektu bez konieczności ponownego zapisywania plików JavaScript.
...
Tam faktycznie jest to sposób, aby załadować plik JavaScript nie asynchronicznie, więc można korzystać z funkcji zawartych w nowo załadowanej właściwy plik po załadowaniu go i myślę, że to działa we wszystkich przeglądarkach.
Trzeba użyć jQuery.append()
na <head>
elemencie strony, to jest:
$("head").append('<script type="text/javascript" src="' + script + '"></script>');
Jednak ta metoda ma również problem: jeśli wystąpi błąd w importowanym pliku JavaScript, Firebug (a także konsola błędów Firefox i narzędzia programistyczne Chrome ) niepoprawnie zgłosi swoje miejsce, co jest dużym problemem, jeśli używasz Firebug do śledzenia Błędy JavaScript w dół dużo (robię). Firebug po prostu nie wie o nowo załadowanym pliku z jakiegoś powodu, więc jeśli wystąpi błąd w tym pliku, zgłasza, że wystąpił w głównym pliku HTML , i będziesz miał problemy ze znalezieniem prawdziwej przyczyny błędu.
Ale jeśli nie jest to dla ciebie problemem, ta metoda powinna działać.
Napisałem wtyczkę jQuery o nazwie $ .import_js (), która używa tej metody:
(function($)
{
/*
* $.import_js() helper (for JavaScript importing within JavaScript code).
*/
var import_js_imported = [];
$.extend(true,
{
import_js : function(script)
{
var found = false;
for (var i = 0; i < import_js_imported.length; i++)
if (import_js_imported[i] == script) {
found = true;
break;
}
if (found == false) {
$("head").append('<script type="text/javascript" src="' + script + '"></script>');
import_js_imported.push(script);
}
}
});
})(jQuery);
Wszystko, co musisz zrobić, aby zaimportować JavaScript, to:
$.import_js('/path_to_project/scripts/somefunctions.js');
Zrobiłem też prosty test w tym przykładzie .
Zawiera main.js
plik w głównym HTML, a następnie skrypt main.js
używa $.import_js()
do importowania dodatkowego pliku o nazwie included.js
, który definiuje tę funkcję:
function hello()
{
alert("Hello world!");
}
I zaraz po tym included.js
, hello()
funkcja jest wywoływana, a otrzymasz powiadomienie.
(Ta odpowiedź jest odpowiedzią na komentarz e-satis).
jQuery.getScript
, dzięki czemu nie musisz się martwić pisaniem wtyczki ...
script
elementu head
spowoduje, że będzie on działał asynchronicznie, chyba że async
jest to specjalnie ustawione false
.
"
, kod się
Innym sposobem, który moim zdaniem jest znacznie czystszy, jest utworzenie synchronicznego żądania Ajax zamiast użycia <script>
tagu. Tak też obejmuje Node.js.
Oto przykład użycia jQuery:
function require(script) {
$.ajax({
url: script,
dataType: "script",
async: false, // <-- This is the key
success: function () {
// all good...
},
error: function () {
throw new Error("Could not load script " + script);
}
});
}
Następnie możesz użyć go w kodzie, ponieważ zwykle używasz dołączenia:
require("/scripts/subscript.js");
I być w stanie wywołać funkcję z wymaganego skryptu w następnym wierszu:
subscript.doSomethingCool();
async: false
podobno jest przestarzały. Nie jest! Jak podaje cytat, tylko rzeczy związane z jqXHR są.
To dla ciebie dobra wiadomość. Już wkrótce będziesz mógł łatwo załadować kod JavaScript. Stanie się standardowym sposobem importowania modułów kodu JavaScript i będzie częścią samego jądra JavaScript.
Musisz po prostu napisać, import cond from 'cond.js';
aby załadować makro o nazwie cond
z pliku cond.js
.
Nie musisz więc polegać na żadnej strukturze JavaScript ani jawnie wykonywać połączeń Ajax .
Odnosić się do:
Możliwe jest dynamiczne generowanie znacznika JavaScript i dołączanie go do dokumentu HTML z innego kodu JavaScript. Spowoduje to załadowanie ukierunkowanego pliku JavaScript.
function includeJs(jsFilePath) {
var js = document.createElement("script");
js.type = "text/javascript";
js.src = jsFilePath;
document.body.appendChild(js);
}
includeJs("/path/to/some/file.js");
js.onload = callback;
Oświadczenie import
znajduje się w ECMAScript 6.
Składnia
import name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import name , { member [ , [...] ] } from "module-name";
import "module-name" as name;
Może możesz użyć tej funkcji, którą znalazłem na tej stronie Jak dołączyć plik JavaScript do pliku JavaScript? :
function include(filename)
{
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = filename;
script.type = 'text/javascript';
head.appendChild(script)
}
script.onload = callback;
var
zmienna będzie globalna?
Oto wersja synchroniczna bez jQuery :
function myRequire( url ) {
var ajax = new XMLHttpRequest();
ajax.open( 'GET', url, false ); // <-- the 'false' makes it synchronous
ajax.onreadystatechange = function () {
var script = ajax.response || ajax.responseText;
if (ajax.readyState === 4) {
switch( ajax.status) {
case 200:
eval.apply( window, [script] );
console.log("script loaded: ", url);
break;
default:
console.log("ERROR: script not loaded: ", url);
}
}
};
ajax.send(null);
}
Pamiętaj, że aby uzyskać działającą między domenami, serwer będzie musiał ustawić allow-origin
nagłówek w swojej odpowiedzi.
http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js
)
<script>
znacznika, a nie za pośrednictwem XMLHttpRequest
.
const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
Właśnie napisałem ten kod JavaScript (używając Prototypu do manipulacji DOM ):
var require = (function() {
var _required = {};
return (function(url, callback) {
if (typeof url == 'object') {
// We've (hopefully) got an array: time to chain!
if (url.length > 1) {
// Load the nth file as soon as everything up to the
// n-1th one is done.
require(url.slice(0, url.length - 1), function() {
require(url[url.length - 1], callback);
});
} else if (url.length == 1) {
require(url[0], callback);
}
return;
}
if (typeof _required[url] == 'undefined') {
// Haven't loaded this URL yet; gogogo!
_required[url] = [];
var script = new Element('script', {
src: url,
type: 'text/javascript'
});
script.observe('load', function() {
console.log("script " + url + " loaded.");
_required[url].each(function(cb) {
cb.call(); // TODO: does this execute in the right context?
});
_required[url] = true;
});
$$('head')[0].insert(script);
} else if (typeof _required[url] == 'boolean') {
// We already loaded the thing, so go ahead.
if (callback) {
callback.call();
}
return;
}
if (callback) {
_required[url].push(callback);
}
});
})();
Stosowanie:
<script src="prototype.js"></script>
<script src="require.js"></script>
<script>
require(['foo.js','bar.js'], function () {
/* Use foo.js and bar.js here */
});
</script>
Gist: http://gist.github.com/284442 .
Oto uogólniona wersja tego, jak Facebook robi to z ich wszechobecnym przyciskiem Like:
<script>
var firstScript = document.getElementsByTagName('script')[0],
js = document.createElement('script');
js.src = 'https://cdnjs.cloudflare.com/ajax/libs/Snowstorm/20131208/snowstorm-min.js';
js.onload = function () {
// do stuff with your dynamically loaded script
snowStorm.snowColor = '#99ccff';
};
firstScript.parentNode.insertBefore(js, firstScript);
</script>
Jeśli działa na Facebooku, będzie działał dla Ciebie.
Powodem, dla którego szukamy pierwszego script
elementu zamiast head
lub body
jest to, że niektóre przeglądarki nie tworzą go, jeśli go brakuje, ale na pewno mamy script
element - ten. Przeczytaj więcej na http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/ .
Jeśli chcesz w czystym JavaScript, możesz użyć document.write
.
document.write('<script src="myscript.js" type="text/javascript"></script>');
Jeśli korzystasz z biblioteki jQuery, możesz użyć tej $.getScript
metody.
$.getScript("another_script.js");
Możesz także składać skrypty za pomocą PHP :
Plik main.js.php
:
<?php
header('Content-type:text/javascript; charset=utf-8');
include_once("foo.js.php");
include_once("bar.js.php");
?>
// Main JavaScript code goes here
Większość przedstawionych tu rozwiązań zakłada obciążenie dynamiczne. Zamiast tego szukałem kompilatora, który składałby wszystkie zależne pliki w jeden plik wyjściowy. Tak samo jak preprocesory Less / Sass zajmują się CSS@import
zasadą . Ponieważ nie znalazłem nic przyzwoitego tego rodzaju, napisałem proste narzędzie do rozwiązania tego problemu.
Oto kompilator https://github.com/dsheiko/jsic , który bezpiecznie zastępuje $import("file-path")
żądaną zawartość pliku. Oto odpowiednia wtyczka Grunt : https://github.com/dsheiko/grunt-jsic .
W gałęzi master jQuery łączą po prostu atomowe pliki źródłowe w jeden, zaczynając od intro.js
i kończąc na outtro.js
. Nie odpowiada mi to, ponieważ nie zapewnia elastyczności w projektowaniu kodu źródłowego. Sprawdź, jak to działa z jsic:
src / main.js
var foo = $import("./Form/Input/Tel");
src / Form / Input / Tel.js
function() {
return {
prop: "",
method: function(){}
}
}
Teraz możemy uruchomić kompilator:
node jsic.js src/main.js build/mail.js
I pobierz połączony plik
build / main.js
var foo = function() {
return {
prop: "",
method: function(){}
}
};
Jeśli zamierzasz załadować plik JavaScript, korzystasz z funkcji z importowanego / dołączonego pliku , możesz również zdefiniować obiekt globalny i ustawić funkcje jako elementy obiektu. Na przykład:
A = {};
A.func1 = function() {
console.log("func1");
}
A.func2 = function() {
console.log("func2");
}
A.func1();
A.func2();
Musisz tylko zachować ostrożność, dołączając skrypty do pliku HTML. Kolejność powinna wyglądać jak poniżej:
<head>
<script type="text/javascript" src="global.js"></script>
<script type="text/javascript" src="file1.js"></script>
<script type="text/javascript" src="file2.js"></script>
<script type="text/javascript" src="main.js"></script>
</head>
To powinno zrobić:
xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);
eval
to co się dzieje z nim. Od Crockforda „ eval
jest zła. Na eval
funkcja jest najbardziej nadużywane cechą JavaScript. Uniknąć. eval
Ma aliasów. Nie należy używać Function
konstruktora. Nie przechodzą ciągi setTimeout
lub setInterval
”. Jeśli nie przeczytałeś jego „JavaScript: The Good Parts”, wyjdź i zrób to teraz. Państwo będzie nie pożałujesz.
http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js
)
Lub zamiast włączać go w czasie wykonywania, użyj skryptu do konkatenacji przed przesłaniem.
Używam zębatek (nie wiem, czy są inne). Tworzysz swój kod JavaScript w osobnych plikach i dołączasz komentarze, które są przetwarzane przez silnik Sprockets. W celu programowania można dołączać pliki sekwencyjnie, a następnie w celu ich scalenia w środowisku produkcyjnym ...
Zobacz też:
Miałem prosty problem, ale zaskoczyły mnie odpowiedzi na to pytanie.
Musiałem użyć zmiennej (myVar1) zdefiniowanej w jednym pliku JavaScript (myvariables.js) w innym pliku JavaScript (main.js).
Zrobiłem to w następujący sposób:
Załadowałem kod JavaScript do pliku HTML, w odpowiedniej kolejności, najpierw myvariables.js, a następnie main.js:
<html>
<body onload="bodyReady();" >
<script src="myvariables.js" > </script>
<script src="main.js" > </script>
<!-- Some other code -->
</body>
</html>
Plik: myvariables.js
var myVar1 = "I am variable from myvariables.js";
Plik: main.js
// ...
function bodyReady() {
// ...
alert (myVar1); // This shows "I am variable from myvariables.js", which I needed
// ...
}
// ...
Jak widzieliście, użyłem zmiennej w jednym pliku JavaScript w innym pliku JavaScript, ale nie musiałem uwzględniać jednej w innym. Musiałem tylko upewnić się, że pierwszy plik JavaScript załadowany przed drugim plikiem JavaScript oraz zmienne pierwszego pliku JavaScript są automatycznie dostępne w drugim pliku JavaScript.
To uratowało mi dzień. Mam nadzieję, że to pomoże.
import
. Potrzebujesz pliku HTML, aby przenieść rzeczy z jednego pliku js do drugiego.
<script>
znacznik. Może to pomóc w organizacji. Ta odpowiedź po prostu nie jest pytaniem i nie jest idealna w tym kontekście.
Jeśli używasz pracowników sieci Web i chcesz uwzględnić dodatkowe skrypty w zakresie pracownika, inne odpowiedzi na temat dodawania skryptów dohead
znacznika itp. Nie będą działać.
Na szczęście pracownicy sieci mają swoją własną importScripts
funkcję, która jest funkcją globalną w zakresie pracownika sieci, natywną dla samej przeglądarki, ponieważ jest częścią specyfikacji .
Alternatywnie, ponieważ wyróżnia się druga najwyżej oceniona odpowiedź na twoje pytanie , RequireJS może również obsługiwać dołączanie skryptów wewnątrz procesu roboczego (prawdopodobnie wywołuje importScripts
się, ale z kilkoma innymi przydatnymi funkcjami).
W nowoczesnym języku ze sprawdzeniem, czy skrypt został już załadowany, byłoby to:
function loadJs(url){
return new Promise( (resolve, reject) => {
if (document.querySelector(`head > script[src="${src}"]`) !== null) return resolve()
const script = document.createElement("script")
script.src = url
script.onload = resolve
script.onerror = reject
document.head.appendChild(script)
});
}
Użycie (asynchronizacja / oczekiwanie):
try { await loadJs("https://.../script.js") }
catch(error) {console.log(error)}
lub
await loadJs("https://.../script.js").catch(err => {})
Zastosowanie (obietnica):
loadJs("https://.../script.js").then(res => {}).catch(err => {})
var pi = 3.14
. wywołaj funkcję loadJS () przezloadJs("pi.js").then(function(){ console.log(pi); });
@import
Składni CSS dla osiągnięcia podobnego JavaScript importowanie jest możliwe przy użyciu narzędzia takiego jak mieszanka poprzez ich szczególny .mix
typ pliku (patrz tutaj ). Wyobrażam sobie, że aplikacja po prostu korzysta z jednej z wyżej wymienionych metod, chociaż nie wiem.
Z dokumentacji Mixture dotyczącej .mix
plików:
Pliki mix to po prostu pliki .js lub .css z .mix. w nazwie pliku. Plik mieszany po prostu rozszerza funkcjonalność zwykłego pliku stylu lub skryptu i umożliwia importowanie i łączenie.
Oto przykładowy .mix
plik, który łączy wiele .js
plików w jeden:
// scripts-global.mix.js
// Plugins - Global
@import "global-plugins/headroom.js";
@import "global-plugins/retina-1.1.0.js";
@import "global-plugins/isotope.js";
@import "global-plugins/jquery.fitvids.js";
Mikstura generuje to jako, scripts-global.js
a także jako wersja zminimalizowana (scripts-global.min.js
).
Uwaga: nie jestem w żaden sposób związany z Mixture, poza wykorzystywaniem go jako narzędzia programistycznego front-end. Natknąłem się na to pytanie, widząc.mix
plik JavaScript w akcji (w jednym z bojlerów Mixture) i byłem przez to nieco zdezorientowany („możesz to zrobić?” Pomyślałem sobie). Potem zdałem sobie sprawę, że był to plik specyficzny dla aplikacji (nieco rozczarowujący, zgodził się). Niemniej jednak doszedł do wniosku, że wiedza ta może być pomocna dla innych.
AKTUALIZACJA : Mieszanina jest teraz darmowa (offline).
AKTUALIZACJA : Mieszanina jest teraz wycofana. Stare wersje mieszanin są nadal dostępne
var js = document.createElement("script");
js.type = "text/javascript";
js.src = jsFilePath;
document.body.appendChild(js);
body
jeszcze nie istnieje lub nie można go modyfikować. Pomaga także wyjaśnić odpowiedzi.
Moją zwykłą metodą jest:
var require = function (src, cb) {
cb = cb || function () {};
var newScriptTag = document.createElement('script'),
firstScriptTag = document.getElementsByTagName('script')[0];
newScriptTag.src = src;
newScriptTag.async = true;
newScriptTag.onload = newScriptTag.onreadystatechange = function () {
(!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') && (cb());
};
firstScriptTag.parentNode.insertBefore(newScriptTag, firstScriptTag);
}
Działa świetnie i nie używa dla mnie przeładowywania stron. Próbowałem metody AJAX (jedna z pozostałych odpowiedzi), ale nie wydaje mi się, aby działała tak ładnie.
Oto wyjaśnienie, w jaki sposób działa kod dla tych, którzy są ciekawi: zasadniczo tworzy nowy znacznik skryptu (po pierwszym) adresu URL. Ustawia go w tryb asynchroniczny, aby nie blokował reszty kodu, ale wywołuje wywołanie zwrotne, gdy readyState (stan treści do załadowania) zmieni się na „załadowany”.
Chociaż te odpowiedzi są świetne, istnieje proste „rozwiązanie”, które istniało od czasu załadowania skryptu i obejmie 99,999% przypadków użycia większości ludzi. Wystarczy dołączyć skrypt, którego potrzebujesz, przed skryptem, który tego wymaga. W przypadku większości projektów ustalenie, które skrypty są potrzebne i w jakiej kolejności, nie zajmuje dużo czasu.
<!DOCTYPE HTML>
<html>
<head>
<script src="script1.js"></script>
<script src="script2.js"></script>
</head>
<body></body>
</html>
Jeśli skrypt2 wymaga skryptu 1, jest to naprawdę najłatwiejszy sposób na zrobienie czegoś takiego. Jestem bardzo zaskoczony, że nikt tego nie podniósł, ponieważ jest to najbardziej oczywista i najprostsza odpowiedź, która będzie obowiązywać w prawie każdym przypadku.
Napisałem prosty moduł, który automatyzuje zadanie importowania / włączania skryptów modułów w JavaScript. Szczegółowe objaśnienie kodu znajduje się w blogu JavaScript wymagają / importu / włączenia modułów .
// ----- USAGE -----
require('ivar.util.string');
require('ivar.net.*');
require('ivar/util/array.js');
require('http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js');
ready(function(){
//Do something when required scripts are loaded
});
//--------------------
var _rmod = _rmod || {}; //Require module namespace
_rmod.LOADED = false;
_rmod.on_ready_fn_stack = [];
_rmod.libpath = '';
_rmod.imported = {};
_rmod.loading = {
scripts: {},
length: 0
};
_rmod.findScriptPath = function(script_name) {
var script_elems = document.getElementsByTagName('script');
for (var i = 0; i < script_elems.length; i++) {
if (script_elems[i].src.endsWith(script_name)) {
var href = window.location.href;
href = href.substring(0, href.lastIndexOf('/'));
var url = script_elems[i].src.substring(0, script_elems[i].length - script_name.length);
return url.substring(href.length+1, url.length);
}
}
return '';
};
_rmod.libpath = _rmod.findScriptPath('script.js'); //Path of your main script used to mark
//the root directory of your library, any library.
_rmod.injectScript = function(script_name, uri, callback, prepare) {
if(!prepare)
prepare(script_name, uri);
var script_elem = document.createElement('script');
script_elem.type = 'text/javascript';
script_elem.title = script_name;
script_elem.src = uri;
script_elem.async = true;
script_elem.defer = false;
if(!callback)
script_elem.onload = function() {
callback(script_name, uri);
};
document.getElementsByTagName('head')[0].appendChild(script_elem);
};
_rmod.requirePrepare = function(script_name, uri) {
_rmod.loading.scripts[script_name] = uri;
_rmod.loading.length++;
};
_rmod.requireCallback = function(script_name, uri) {
_rmod.loading.length--;
delete _rmod.loading.scripts[script_name];
_rmod.imported[script_name] = uri;
if(_rmod.loading.length == 0)
_rmod.onReady();
};
_rmod.onReady = function() {
if (!_rmod.LOADED) {
for (var i = 0; i < _rmod.on_ready_fn_stack.length; i++){
_rmod.on_ready_fn_stack[i]();
});
_rmod.LOADED = true;
}
};
_.rmod = namespaceToUri = function(script_name, url) {
var np = script_name.split('.');
if (np.getLast() === '*') {
np.pop();
np.push('_all');
}
if(!url)
url = '';
script_name = np.join('.');
return url + np.join('/')+'.js';
};
//You can rename based on your liking. I chose require, but it
//can be called include or anything else that is easy for you
//to remember or write, except "import", because it is reserved
//for future use.
var require = function(script_name) {
var uri = '';
if (script_name.indexOf('/') > -1) {
uri = script_name;
var lastSlash = uri.lastIndexOf('/');
script_name = uri.substring(lastSlash+1, uri.length);
}
else {
uri = _rmod.namespaceToUri(script_name, ivar._private.libpath);
}
if (!_rmod.loading.scripts.hasOwnProperty(script_name)
&& !_rmod.imported.hasOwnProperty(script_name)) {
_rmod.injectScript(script_name, uri,
_rmod.requireCallback,
_rmod.requirePrepare);
}
};
var ready = function(fn) {
_rmod.on_ready_fn_stack.push(fn);
};
Ten skrypt doda plik JavaScript do góry dowolnego innego <script>
tagu:
(function () {
var li = document.createElement('script');
li.type = 'text/javascript';
li.src= "http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js";
li.async=true;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(li, s);
})();
Istnieje również Head.js . Bardzo łatwo jest poradzić sobie z:
head.load("js/jquery.min.js",
"js/jquery.someplugin.js",
"js/jquery.someplugin.css", function() {
alert("Everything is ok!");
});
Jak widać, jest to łatwiejsze niż Require.js i tak wygodne jak $.getScript
metoda jQuery . Ma również kilka zaawansowanych funkcji, takich jak ładowanie warunkowe, wykrywanie funkcji i wiele innych .
Istnieje wiele potencjalnych odpowiedzi na to pytanie. Moja odpowiedź opiera się oczywiście na wielu z nich. Właśnie z tym skończyłem po przeczytaniu wszystkich odpowiedzi.
Problem z $.getScript
jakimkolwiek innym rozwiązaniem, które wymaga oddzwonienia po zakończeniu ładowania, polega na tym, że jeśli masz wiele plików, które go używają i są od siebie zależne, nie możesz już wiedzieć, kiedy wszystkie skrypty zostały załadowane (po zagnieżdżeniu w wielu plikach).
plik3.js
var f3obj = "file3";
// Define other stuff
plik2.js:
var f2obj = "file2";
$.getScript("file3.js", function(){
alert(f3obj);
// Use anything defined in file3.
});
plik1.js:
$.getScript("file2.js", function(){
alert(f3obj); //This will probably fail because file3 is only guaranteed to have loaded inside the callback in file2.
alert(f2obj);
// Use anything defined in the loaded script...
});
Masz rację, gdy mówisz, że możesz określić, że Ajax ma działać synchronicznie lub użyć XMLHttpRequest , ale wydaje się, że obecnym trendem jest wycofywanie synchronicznych żądań, więc możesz nie uzyskać pełnej obsługi przeglądarki teraz lub w przyszłości.
Możesz spróbować $.when
sprawdzić tablicę odroczonych obiektów, ale teraz robisz to w każdym pliku, a plik2 zostanie uznany za załadowany, gdy tylko $.when
zostanie wykonany, a nie po wywołaniu zwrotnym, więc plik1 nadal kontynuuje wykonywanie przed załadowaniem pliku3 . To naprawdę ma ten sam problem.
Postanowiłem wrócić do tyłu zamiast do przodu. Dziękuję document.writeln
. Wiem, że jest to tabu, ale dopóki jest właściwie używane, działa dobrze. Otrzymujesz kod, który można łatwo debugować, wyświetla poprawnie w DOM i może zapewnić porządek, w jaki zależności są ładowane poprawnie.
Oczywiście możesz użyć $ („body”). Append (), ale wtedy nie możesz już poprawnie debugować.
UWAGA: Musisz użyć tego tylko podczas ładowania strony, w przeciwnym razie pojawi się pusty ekran. Innymi słowy, zawsze umieszczaj to przed / poza dokumentem . Już . Nie testowałem tego przy użyciu po załadowaniu strony w zdarzeniu kliknięcia itp., Ale jestem pewien, że to się nie powiedzie.
Podobał mi się pomysł rozszerzenia jQuery, ale oczywiście nie musisz.
Przed wywołaniem document.writeln
sprawdza, czy skrypt nie został już załadowany, oceniając wszystkie elementy skryptu.
Zakładam, że skrypt nie jest w pełni wykonany, dopóki document.ready
nie zostanie wykonane jego zdarzenie. (Wiem, że używanie document.ready
nie jest wymagane, ale wiele osób korzysta z niego, a obchodzenie się z tym jest zabezpieczeniem).
Po załadowaniu dodatkowych plików document.ready
wywołania zwrotne zostaną wykonane w niewłaściwej kolejności. Aby rozwiązać ten problem, gdy skrypt jest rzeczywiście ładowany, skrypt, który go zaimportował, jest ponownie importowany i wykonywanie jest zatrzymywane. Powoduje to, że plik źródłowy ma teraz document.ready
wywołanie zwrotne po dowolnym z importowanych skryptów.
Zamiast tego podejścia można było spróbować zmodyfikować jQuery readyList
, ale wydawało się to gorszym rozwiązaniem.
Rozwiązanie:
$.extend(true,
{
import_js : function(scriptpath, reAddLast)
{
if (typeof reAddLast === "undefined" || reAddLast === null)
{
reAddLast = true; // Default this value to true. It is not used by the end user, only to facilitate recursion correctly.
}
var found = false;
if (reAddLast == true) // If we are re-adding the originating script we do not care if it has already been added.
{
found = $('script').filter(function () {
return ($(this).attr('src') == scriptpath);
}).length != 0; // jQuery to check if the script already exists. (replace it with straight JavaScript if you don't like jQuery.
}
if (found == false) {
var callingScriptPath = $('script').last().attr("src"); // Get the script that is currently loading. Again this creates a limitation where this should not be used in a button, and only before document.ready.
document.writeln("<script type='text/javascript' src='" + scriptpath + "'></script>"); // Add the script to the document using writeln
if (reAddLast)
{
$.import_js(callingScriptPath, false); // Call itself with the originating script to fix the order.
throw 'Readding script to correct order: ' + scriptpath + ' < ' + callingScriptPath; // This halts execution of the originating script since it is getting reloaded. If you put a try / catch around the call to $.import_js you results will vary.
}
return true;
}
return false;
}
});
Stosowanie:
Plik 3:
var f3obj = "file3";
// Define other stuff
$(function(){
f3obj = "file3docready";
});
Plik2:
$.import_js('js/file3.js');
var f2obj = "file2";
$(function(){
f2obj = "file2docready";
});
Plik 1:
$.import_js('js/file2.js');
// Use objects from file2 or file3
alert(f3obj); // "file3"
alert(f2obj); // "file2"
$(function(){
// Use objects from file2 or file3 some more.
alert(f3obj); //"file3docready"
alert(f2obj); //"file2docready"
});
Istnieje kilka sposobów implementacji modułów w Javascript, oto 2 najpopularniejsze:
Przeglądarki nie obsługują jeszcze tego systemu modulowania, więc aby skorzystać z tej składni, musisz użyć programu pakującego, takiego jak webpack. Korzystanie z pakietu jest i tak lepsze, ponieważ może łączyć wszystkie różne pliki w jeden (lub kilka powiązanych) plików. Pozwoli to szybciej przesyłać pliki z serwera do klienta, ponieważ do każdego żądania HTTP jest przypisany jakiś narzut. W ten sposób zmniejszając ogólne żądanie HTTP, poprawiamy wydajność. Oto przykład modułów ES6:
// main.js file
export function add (a, b) {
return a + b;
}
export default function multiply (a, b) {
return a * b;
}
// test.js file
import {add}, multiply from './main'; // for named exports between curly braces {export1, export2}
// for default exports without {}
console.log(multiply(2, 2)); // logs 4
console.log(add(1, 2)); // logs 3
Ten system modulacji jest używany w NodeJS. Zasadniczo dodajesz swój eksport do obiektu, który jest nazywany module.exports
. Następnie możesz uzyskać dostęp do tego obiektu za pomocą require('modulePath')
. Ważne jest, aby zdać sobie sprawę, że te moduły są buforowane, więc jeśli require()
dany moduł zostanie dwukrotnie, zwróci on już utworzony moduł.
// main.js file
function add (a, b) {
return a + b;
}
module.exports = add; // here we add our add function to the exports object
// test.js file
const add = require('./main');
console.log(add(1,2)); // logs 3
Przyszedłem do tego pytania, ponieważ szukałem prostego sposobu na utrzymanie kolekcji przydatnych wtyczek JavaScript. Po obejrzeniu niektórych rozwiązań tutaj wymyśliłem:
Skonfiguruj plik o nazwie „plugins.js” (lub extensions.js lub cokolwiek chcesz). Zachowaj pliki wtyczek razem z tym jednym plikiem głównym.
plugins.js będzie miał tablicę o nazwie pluginNames[]
, którą będziemy iterować each()
, a następnie doda <script>
tag do nagłówka dla każdej wtyczki
//set array to be updated when we add or remove plugin files
var pluginNames = ["lettering", "fittext", "butterjam", etc.];
//one script tag for each plugin
$.each(pluginNames, function(){
$('head').append('<script src="js/plugins/' + this + '.js"></script>');
});
<script src="js/plugins/plugins.js"></script>
ALE:
Mimo że wszystkie wtyczki są upuszczane do tagu head tak, jak powinny, nie zawsze są uruchamiane przez przeglądarkę po kliknięciu na stronę lub odświeżeniu.
Odkryłem, że bardziej niezawodne jest pisanie tagów skryptowych w PHP. Musisz go napisać tylko raz, a to tyle samo pracy, co wywołanie wtyczki za pomocą JavaScript.