Создание модулей

Проектирование компонентов для Qu.js

Способы организации кода

Qu рекомендует три способа организации кода в зависимости от задач:

  • Object Literal — простые утилиты и хелперы.
  • Singleton — модули на одном экземпляре.
  • Class — компоненты с множеством экземпляров.

Все способы регистрируются через Qu.lib() и получают доступ к ядру Qu.

Именование классов и атрибутов

Рекомендуемый префикс для data аттрибутов data-qu-{moduleName}-{attribute}. Стандартные аттрибуты и анимации предусмотрены просто с префиксом data-qu-{attribute}.

  • data-qu-opening — появление элемента.
  • data-qu-closing — закрытие элемента.
  • data-qu-animation-open="{effect}" — анимация для появления элемента.
  • data-qu-animation-close="{effect}" — анимация для закрытия элемента.
  • data-qu-loading="{true/false}" — анимация для эффекта загрущающегося элемента.
[data-qu-animation-open="fade"] { transform: translateY(-20px) scale(0.95); }
[data-qu-animation-open="fade"][data-qu-opening] { transform: translateY(0) scale(1); }
[data-qu-animation-close="fade"][data-qu-closing] { transform: translateY(-20px) scale(0.95); }

// vars можно перезадать к конкретным элементам
.element[data-qu-loading] {
  --qu-loading-bg: rgba(255, 255, 255, 0.7);
  --qu-loading-color: black;
  --qu-loading-size: 32px;
  --qu-loading-zindex: 1300000000;
}

Шаблон Object Literal (объектный литерал)

Самый простой способ. Подходит для утилит и простых модулей.

/*!
 * LibExample_literal (Object Literal version)
 * Component for Qu
 *
 * @package LibExample_literal
 * @author Serge Galich 
 * @copyright 2025
 * @license MIT
 * @website http://qujs.ru/how-to-create-module/
 * 
 * @requires Qu
 */
 Que(() => {
    // Пример регистрации модуля через переменную
    Qu.lib('LibExample_literal', {
        name: 'LibExample_literal',
        version: '1.0',
        
        loaded: function(quInstance) {
            // Вызывается сразу после регистрации
            console.log('Модуль LibExample_literal загружен');
        },
        
        init: function(quInstance, params) {
            // Инициализация модуля
            console.log('Модуль LibExample_literal инициализирован', params);
        },
        
        test: function() {
            Qu.debug('test');
        }
    });
     
    // Использование после регистрации
    Qu.LibExample_literal.test();
});

Шаблон Singleton (на одном объекте)

Один экземпляр на весь компонент в отдельном файле.

/*!
 * LibExample_Singleton (Object version)
 * Component for Qu
 *
 * @package LibExample_Singleton
 * @author Serge Galich 
 * @copyright 2025
 * @license MIT
 * @website http://qujs.ru/how-to-create-module/
 * 
 * @requires Qu
 */
(function(global) {
    'use strict';
    const LIB_NAME = 'LibExample_Singleton';

    if (global.Qu && global.Qu[LIB_NAME]) {
        global.Qu.debug(`⚠️ [${LIB_NAME}] Already registered, skipping duplicate`);
        return;
    }

    var Qu = null;
    var Module = {
        name: LIB_NAME,
        version: '1.0',
        _initOnce: false,

        _config: {
            assets_url: '/assets/',
        },

        config: function(options) {
            Object.assign(this._config, options);
            return this;
        }, 

        debug: function(...args) {
            Qu.debug(...args);
        },

        use: function (fn) {
            if (typeof fn === 'function') {
                fn(this, Qu);
            }
        },

        extend: function () {
            if (Array.isArray(global[LIB_NAME + 'Extend'])) {
              global[LIB_NAME + 'Extend'].forEach((fn) => {
                this.use(fn);
              });
              global[LIB_NAME + 'Extend'] = [];
            }
        },

        loaded: function(quInstance) {
            Qu = quInstance;
            this.extend();
            console.log('ONLOAD LibExample_Singleton')
        },

        initOnce: function(params = {}) {
            if(this._initOnce === true) { return; }
            this._initOnce = true;
        },

        init: function(quInstance, params = {}) {
            this.initOnce(params);
            this.config(params);
            this._init();
        },

        test: function(wtf) {
            Qu.debug(wtf);
        },

        _init: function() {
            console.log(`${LIB_NAME} initialized`);
            if (Qu && Qu.Frame) {
                Qu.Frame.test('LibExample_Singleton init');
            }
        },

        // Другие методы тоже могут использовать Qu
        someMethod: function() {
            if (Qu) {
                Qu.test('Using Qu from method');
            }
        }
    };

    if (global.Qu) {
        global.Qu.lib(LIB_NAME, Module);
    } else {
        global._QuLibs = global._QuLibs || [];
        global._QuLibs.push({ name: LIB_NAME, instance: Module });
    }

})(typeof window !== 'undefined' ? window : global);

Применение

Шаблон Class (мультиэкземплярный)

Множество независимых экземпляров.

/*!
 * LibExample_class (Object-Class version)
 * Component for Qu
 *
 * @package LibExample_class
 * @author Serge Galich 
 * @copyright 2025
 * @license MIT
 * @website http://qujs.ru/how-to-create-module/
 * 
 * @requires Qu
 */

(function(global) {
    'use strict';
    const LIB_NAME = 'LibExample_class';

    if (global.Qu && global.Qu[LIB_NAME]) {
        global.Qu.debug(`⚠️ [${LIB_NAME}] Already registered, skipping duplicate`);
        return;
    }

    let Qu = null;
    
    function Constructor(params = {}) {
        this.id = Date.now() + '_' + Math.random().toString(36).substr(2);
        this.version = '1.0';
        this.params = params;
        console.log(`NEW ${LIB_NAME}`, this.id);
    }

    Constructor.debug = function(...args) {
        Qu.debug(...args);
    },

    Constructor.use = function (fn) {
        if (typeof fn === 'function') {
          fn(Constructor, Qu);
        }
    };

    Constructor.extend = function () {
        if (Array.isArray(global[LIB_NAME + 'Extend'])) {
          global[LIB_NAME + 'Extend'].forEach((fn) => {
            Constructor.use(fn);
          });
          global[LIB_NAME + 'Extend'] = [];
        }
    };

    // ✅ Методы через контейнер
    Constructor.loaded = function(quInstance) {
        console.log(`${LIB_NAME}.loaded`);
        Qu = quInstance;
        Constructor.extend();
    };

    Constructor.sen = function(mes) {
        console.log(`${LIB_NAME}: ${mes}`);
    };

    // функционал экземпляра
    Constructor.prototype = {
        constructor: Constructor,
        
        tester: function() {
            console.log('wtf', Qu, LIB_NAME);
        }
    };

    if (global.Qu) {
        global.Qu.lib(LIB_NAME, Constructor);
    } else {
        global._QuLibs = global._QuLibs || [];
        global._QuLibs.push({ name: LIB_NAME, instance: Constructor });
    }

})(typeof window !== 'undefined' ? window : global);

Применение