Vue.js компонент vue-select на Drupal 8

Батор Кореев
Drupal&frontend-разработчик

Создание нового модуля

Модуль создадим любым известным/удобным для вас способом, а кто имеет опыт работы с CLI то воспользуемся командой drupal gm назовем наш модуль my_vue_component

Создание формы настроек

drupal vuejs form

Создаем форму настроек, надеюсь у вас не будет никаких затруднений, тут ничего сложного. CLI drupal gfc

  • В поле "Elements" будем хранить css-селекторы наших элементов, которые будут "заменены"/использованы для нашего Вью компонента 

Создаем файл библиотек нашего модуля с названием my_vue_component.libraries.yml

#our files
main:
  js:
    assets/js/my_vue_component.js: {}
#include lib vue.js from vuejs module
  dependencies:
    - vuejs/vue
    - core/drupal
    - core/drupalSettings

Имплементируем хук для подключения наших файлов/библиотек и выведем/отправим наши данные из  поля "Elements" 

/**
 * Implements hook_page_attachments_alter().
 */
function my_vue_component_page_attachments_alter(array &$attachments) {
  $elems = \Drupal::config('my_vue_component.settings')->get('elems');
  $elems = array_filter(explode("\r\n", $elems));

  $attachments['#attached']['drupalSettings']['myVueComponent']['elems'] = $elems;
  $attachments['#attached']['library'][] = 'my_vue_component/main';
}

В заключении нам остается только создать файл assets/js/my_vue_component.js и подключить vue и необходимый компонент

(function (Drupal, drupalSettings) {
  Drupal.behaviors.MyVueComponent = {
    attach(context) {
      let elems = drupalSettings.myVueComponent.elems;
      if (elems.length) {
        this.buildMyVueCmpnt.includeVSelect('https://unpkg.com/vue-select@latest', () => {
          Vue.component('v-select', VueSelect.VueSelect);
          elems.forEach(elem => {
            let ce = document.querySelectorAll(elem);
            this.buildMyVueCmpnt.build(ce);
          })
        });
      }
    },
    buildMyVueCmpnt: {
      build: function (elem) {
        if (elem.length) {
          elem.forEach(ce => {
            ce.setAttribute('v-model', 'selected');
            let ceo = this.getOptions(ce.options);
            this.createComponent(ce, ceo);
          })
        }
      },
      createComponent: (element, values) => {
        let selement = element.options[element.selectedIndex].removeAttribute('selected');
        let parent = element.parentElement;
        element.style.display = 'none';
        let VueCmpnt = document.createElement('v-select');
        VueCmpnt.setAttribute('v-model', 'tmpSelected');
        VueCmpnt.setAttribute(':options', 'options');
        VueCmpnt.setAttribute('label', 'text');
        parent.appendChild(VueCmpnt);

        new Vue({
          el: '.' + parent.className.split(' ').join('.'),
          data: {
            selected: values[0].value,
            tmpSelected: values[0].value,
            options: values
          },
          watch: {
            tmpSelected: function (value) {
              this.selected = value ? value.value : ''
            }
          }
        });
      },
      getOptions: options => {
        let output = [];
        for (i = 0; i < options.length; i++) {
          output.push({
            value: options[i].value,
            text: options[i].text
          });
        }
        return output;
      },
      includeVSelect: (url, callback) => {
        let script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = url;

        script.onreadystatechange = callback;
        script.onload = callback;
        document.getElementsByTagName('head')[0].appendChild(script);
      }
    }
  };

}(Drupal, drupalSettings));

Результат

drupal vuejs result