Заставить импортированный код запускаться только на определенной странице [Module Pattern + ES6]

Я разрабатываю структуру кода с импортом/экспортом из ES6, используя шаблон модуля. Итак, в файле у меня есть:

// Product.js

const Product = (function product() {
   const productJson = skuJson;
   const productTabs = document.querySelectorAll('.js-product-tab');
   const handleClickProductTab = (evt) => {...};
   const init = () => {
     [...productTabs].forEach((tab) => {
       tab.addEventListener('click', handleClickProductTab);
     });
   };
   return {
     init,
   };
}());

export default Product;

А в другом файле я импортирую этот JS-файл Product для дальнейшего использования.

import Product from './product/product';

(function init() {
  document.addEventListener('DOMContentLoaded', () => {
    Product.init();
  });
}());

Я понимаю, что код запускается из-за IIFE, и даже если удалить Product.init();, переменные все равно будут созданы. Но в том то и дело, что у меня со страниц вылетают ошибки, что те модули не должны читаться.

Как я могу сделать так, чтобы эти переменные, созданные в каждом модуле, создавались только при вызове метода init(), но эти переменные по-прежнему были доступны для остальной части модуля?


person ricardogoldstein    schedule 20.06.2018    source источник
comment
Что вы пытаетесь сделать? Первая проблема, которую я вижу -> const productTabs = document.querySelectorAll('.js-product-tab'); Это будет вызвано еще до загрузки DOM.   -  person Keith    schedule 21.06.2018
comment
это проблема. Должен ли я изменить эти переменные, чтобы они были созданы внутри функций, которые их используют?   -  person ricardogoldstein    schedule 21.06.2018
comment
Я бы просто переместил ваши константы в ваш init.. видно, что init вызывается, когда DOM готов.   -  person Keith    schedule 21.06.2018
comment
Я не могу этого сделать, потому что в модуле Product больше функций, которые используют эти константы. Будет неопределенным, если я перемещу их   -  person ricardogoldstein    schedule 21.06.2018
comment
Вам действительно не нужны IIFE при использовании шаблона модуля. Смысл IIFE в том, чтобы не загрязнять глобальную область видимости, но модули имеют свою собственную область видимости, и вы можете повлиять на глобальную область видимости, только преднамеренно отключив window (или global в NodeJS).   -  person Duncan Thacker    schedule 21.06.2018
comment
Спасибо за ваш ответ @DuncanThacker. Даже если удалить эти IFFE, весь код будет работать с ошибками в этих переменных, верно? Как я могу предотвратить это?   -  person ricardogoldstein    schedule 21.06.2018


Ответы (1)


Часто лучше экспортировать функции, которые можно инициализировать по запросу, а не автоматически запускать функцию каждого модуля при загрузке страницы. есть один, надеюсь, вы сможете его создать), а не первоначальные действия, разбросанные по вашим сценариям.

Например, вы можете экспортировать функцию makeProduct, которая при запуске создает Product:

// makeProduct.js

const makeProduct = () => {
   const productJson = skuJson;
   const productTabs = document.querySelectorAll('.js-product-tab');
   const handleClickProductTab = (evt) => {...};
   const init = () => {
     [...productTabs].forEach((tab) => {
       tab.addEventListener('click', handleClickProductTab);
     });
   };
   return {
     init,
   };
};

export default makeProduct;

А потом

import makeProduct from './product/makeProduct';

(function init() {
  const product = makeProduct();
  document.addEventListener('DOMContentLoaded', () => {
    product.init();
  });
})();

(конечно, если инициализация product зависит от DOMContentLoaded, создайте ее внутри прослушивателя DOMContentLoaded)

person CertainPerformance    schedule 20.06.2018
comment
Я думаю, вы хотите product.init() внутри обработчика DOMContentLoaded...? - person Heretic Monkey; 21.06.2018
comment
Я не получил эту часть that way, initial flow control can lie entirely with an entry point (if you don't have one, hopefully you can create one),. Можешь объяснить? Спасибо за ответ. - person ricardogoldstein; 21.06.2018
comment
Да. Но я хочу, чтобы модуль продукта запускался только на определенной странице, но когда я импортирую модуль, создаются эти переменные и все остальное. - person ricardogoldstein; 21.06.2018
comment
@ricardogoldstein То есть ваш скрипт в идеале должен иметь единственную точку входа, которая может импортировать и вызывать все остальное по мере необходимости. Например, ваш модуль init может быть вашей точкой входа здесь — вы можете заставить его вызывать makeProduct и другие модули по мере необходимости, при этом все эффекты распространяются наружу из исходного модуля init. - person CertainPerformance; 21.06.2018
comment
О, я понял. У меня есть index.js, куда я импортирую все свои модули и запускаю их. Моя проблема в том, что переменные создаются, когда я импортирую свои модули. Должен ли я загружать их внутри функций, которые их используют? - person ricardogoldstein; 21.06.2018
comment
@ricardogoldstein Да, определенно! Импортируйте функции и затем вызывайте их всякий раз, когда это возможно, а не импортируйте модули, которые запускают код самостоятельно при импорте, и управлять потоком управления вашего скрипта станет намного проще. Например. в вашем index.js вы можете проверить страницу, на которой вы находитесь, и вызвать другие функции модуля по мере необходимости (например, if (onProductPage) initProduct(), где initProduct — это модуль с init - person CertainPerformance; 21.06.2018
comment
спасибо @CertainPerformance! Я новичок, структурирую весь проект и использую шаблоны проектирования. - person ricardogoldstein; 21.06.2018