Как сделать динамический popup на Vue.js?

280
02 ноября 2018, 20:30

Сделал простой попам на vue, вызывается через метод alert(text), в качестве аргумента передается простой текст.

Теперь стоит задача сделать его динамическим. Чтобы внутрь можно было передать другой компонент и он отобразился внутри.

Например у меня есть компонент categories. Можно как-то сделать чтобы конструкция alert("<categories></categories>") работала?

<div id="app">
    <a @click="alert('First popup')" href="#">Popup</a>
    <a @click="alert('Second popup')" href="#">Popup 2</a>
    <popup
         v-if="popup.show"
         v-on:close="popup.show = false"
         v-cloak>
        {{ popup.text }}
    </popup>
</div>
<template id="popup">
    <div class="popup-container" @click="close">
        <div class="popup-content" @click.stop>
            <slot></slot>
            <div>
                <a @click="close" href="#">Close</a>
            </div>
        </div>
    </div>
</template>
<template id="categories">
    <div>
        <a v-for="number in 10">
           {{ number }}
        </a>
    </div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
    Vue.component('popup', {
        template: '#popup',
        methods: {
            close: function () {
                this.$emit('close');
            }
        }
    });
    Vue.component('categories', {
        template: '#categories'
    });
    var app = new Vue({
        el: '#app',
        data: {
            popup: {
                show: false,
                text: ""
            }
        },
        methods: {
            alert: function ($text) {
                this.popup.text = $text;
                this.popup.show = true;
            }
        }
    });
</script>

Код - https://jsfiddle.net/mezhevikin/du4ca9z7/

Answer 1

Решение оказалось в специальном динамическом тэге <component v-bind:is="popup.component" :popup="popup"></component>

В переменной popup.component мы просто храним строку с именем компонента.

Документация

Answer 2

Здесь не обсуждается дизайн приложения из вопроса, оставляем это "за скобками", а говорим только о динамической отрисовке, получении HTML-кода компонента.

это эксперимент*

пример измененного fiddle из вопроса

Ниже некоторые заметки про использования .$mount() для доступа к экземпляру компонента

// сохраним в переменную
var Cat = Vue.component('categories', {})
// добавим небольшие изменения в компонент
// добавим "новый" метод для "запуска" компонента
methods: {
  alert: function(){/*...*/},
  runComponent: function(){ // отдельный метод для отрисовки
    // получаем экземпляр компонента
    var cat_ = new Cat()
    _cat.$mount() // <<< ! как будто монтируем компонент ;)        
    // нужно учесть, что прямая передача HTML является небезопасным решением
    // $refs - это рекомендованный способ получить ссылку на html элемент
    // в данном случае мы добавили <div ref="wrapper">..</div>
    // _cat.$el.outerHTML или _cat.$refs.wrapper.outerHTML  
    this.popup.text = _cat.$refs.wrapper.outerHTML // передаем html 
    this.popup.show = true  
  }
}

если это приложение, то стоит обратить внимание на возможность использования @vue/cli - это удобно для прототипирования

bonus

Как указал автор вопроса (в комментариях и собственном ответе) - есть родная во Vue возможность динамического переключения компонентов используя мета-компонент <component ...></component>, но это две разных возможности. Первая дает возможность отрисовывать HTML, теряя при этом связанность и реактивность (например: статичные уведомления), а вторая переключать компоненты (например "табы"). Но такое требуется довольно редко, правильным будет - лучше проектировать приложение и использовать изолированные независимые компоненты.

READ ALSO
Откуда взялись f и g, что это такое и как работает?

Откуда взялись f и g, что это такое и как работает?

На странице учебника JavaScript я увидел такой пример:

182
Запись в базу Firebase

Запись в базу Firebase

Пытаюсь настроить запись в базу Firebase RealtimeБаза подключение видит, но записи не происходит

146
Как получить имя файла в gulp.task(&ldquo;watch&rdquo;)

Как получить имя файла в gulp.task(“watch”)

У меня есть следующая задача: При удалении картинки из раздела /src/blocks/nav/assets/img/1jpg я хочу удалить аналогичную картинку в /src/img/

169
Записать данные с формы в модальном окне в массив и передать в php файл

Записать данные с формы в модальном окне в массив и передать в php файл

Возможно я просто не полностью понимаю как это должно работатьу меня есть форма, для создания юзера, в этой форме есть модальное окно, и в нем...

139