Vue не может зарегистрировать компонент, если файл JS загружен извне

Я использую vue в обычных файлах js (не .vue) и встроенных шаблонах. У меня есть несколько загружаемых компонентов в зависимости от подстраницы. Что я хотел сделать, так это загрузить некоторые глобальные переменные vue и компоненты vue, а затем динамически, используя jQuery, загрузить дополнительный скрипт компонентов vue, если некоторый контейнер (например, #blog) имеет длину> 0.

Проблема в том, что Vue выдает ошибку, заключающуюся в том, что он нашел теги Vue, но не смог зарегистрировать компонент.

Есть ли способ динамически загружать файлы JS? У меня действительно большой веб-сайт с множеством js-файлов, которые я хочу загружать только на определенных подстраницах. Он отлично работает для всех библиотек jQuery, но, к сожалению, не для компонентов Vue.

Пример компонента ниже:

Vue.component('blog-entries', {
    name: "blog-entries",
    template: require('js/vue/home/blog/blog.html').template,
    data: function () {
        return {
            blog_entries: [

            ]
        }
    }
});

и ошибка:

[Предупреждение Vue]: Неизвестный пользовательский элемент: - Вы правильно зарегистрировали компонент? Для рекурсивных компонентов обязательно укажите параметр «имя».

(найти в )

загрузить скрипт:

function loadScript(scriptName, callback) {

    if (!_arr[scriptName]) {
        _arr[scriptName] = true;

        var body        = document.getElementsByTagName('body')[0];
        var script      = document.createElement('script');
        script.type     = 'text/javascript';
        script.src      = scriptName;

        // 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
        body.appendChild(script);

    } else if (callback) {

        callback();

    }

};

person susanoo    schedule 23.08.2017    source источник


Ответы (1)


var vapp = new Vue({
  el: '#app',
  data: function() {
    return {
      componentName: ''
    }
  },
  computed: {
    currentComponent: function() {
      var vm = this;
      if (!vm.componentName) return;

      if (!vm.$options.components[vm.componentName] //if not registered locally
          && !Vue.options.components[vm.componentName]) {//nor globally yet

        //load the component async'ly
        Vue.component(vm.componentName, function(resolve) {
          //adjust the path to where your component files are
          var filePath = 'https://elfan.net/vue-components/' + vm.componentName + '.vue.js';
          loadScript(filePath, resolve);
        });
      }
      return vm.componentName;
    }
  }
});

/*below is your own third party script loader*/
var _arr = {};
function loadScript(scriptName, callback) {

    if (!_arr[scriptName]) {
        _arr[scriptName] = true;

        var body        = document.getElementsByTagName('body')[0];
        var script      = document.createElement('script');
        script.type     = 'text/javascript';
        script.src      = scriptName;

        // 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
        body.appendChild(script);

    } else if (callback) {

        callback();

    }

}
<!DOCTYPE html>
<html>
  <body>

    <div id="app">
      <input v-model="componentName">
      <div :is="currentComponent"></div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
    <script src="app.js"></script>

  </body>

</html>

В главном приложении (в том, которое загружает подстраницу) попробуйте что-нибудь вроде этого:

Vue.component('blog-entries', function(resolve) {
    loadScript('blog-entries.js', resolve);
})

где 'blog-entries' должно совпадать с именем вашего компонента Vue, а 'blog-entries.js' - это js-файл, содержащий ваш компонент Vue, который вы хотите загружать динамически.

Изменить: чтобы продолжить, здесь я помещаю полный код для динамической загрузки компонентов vue. Компонент будет загружен и визуализирован сразу после ввода пользователем. Вы можете попробовать ввести «муравей», «птичка» или «кошка». Я разместил компоненты vue с этими именами на своем сервере.

person elfan    schedule 24.08.2017
comment
есть ли другой способ просто потребовать весь blog-entries js файл, если эти теги будут доступны? - person susanoo; 24.08.2017
comment
Вы имеете в виду, что имя компонента заранее не известно? Да, он может динамически загружать любое имя компонента, а не только те, которые жестко запрограммированы. Я отредактировал свой ответ, добавив полный демонстрационный код выше. - person elfan; 25.08.2017