VueJS отображает динамический модальный компонент - PullRequest
0 голосов
/ 16 октября 2019

У меня есть сообщения и ответы. St-ответы принадлежат сообщениям с помощью атрибута reply.posts_id.

Я пытаюсь показать форму ответа как модальное для ввода пользователем ответа. Однако я хочу создать общий модальный компонент, который я могу использовать везде с контентом, указанным в другом компоненте, созданном для определенного контекста.

Ответ на публикацию - это первое место, где я хотел бы, чтобы это работало.

В настоящее время Vuex правильно возвращает модальное видимое: true, когда нажата кнопка ответа, но модальное изображение не отображается, и я получаю сообщение об ошибке, показывающее, что модальный компонент не найден:

Unknown custom element: <ModalReplyForm> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

Я использую vuex для управления видимостью модальной зоны. Вот соответствующие файлы:

store.js:

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
...

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    status: '',
    ...
    modalVisible: false,
    modalComponent: null
  },
  mutations: {
    ...
    showModal(state, componentName) {
      console.log('showing the modal')
      state.modalVisible = true;
      state.modalComponent = componentName;
    },
    hideModal(state) {
      console.log('hiding the modal')
      state.modalVisible = false;
    }
  },
  actions: {
    ...
    }
  },
  getters: {
    isAuthenticated: state => !!state.user,
    authStatus: state => state.status,
    user: state => state.user,
    token: state => state.token,
    posts: state => {
      return state.posts;
    }
...
  }
})

App.vue

<template>
  <div id="app">
    <app-modal></app-modal>
    <NavigationBar />
    <div class="container mt-20">
      <router-view />
    </div>
    <vue-snotify></vue-snotify>
  </div>
</template>

<script>
import AppModal from '@/components/global/AppModal';
import NavigationBar from '@/components/layout/NavigationBar'
export default {
  name: "App",
  components: {
    AppModal,
    NavigationBar
  }
};
</script>

<style>
body {
  background-color: #f7f7f7;
}

.is-danger {
  color: #9f3a38;
}
</style>

Post.vue (содержит кнопку для вызова модального ответа):

<template>
  <div class="row ui dividing header news">
    <!-- Label -->
    <div class="m-1 col-md-2 ui image justify-content-center align-self-center">
      <img v-if="post.avatar_url" :src="post.avatar_url" class="mini rounded"/>
      <v-gravatar v-else :email="post.email" class="mini thumbnail rounded image rounded-circle z-depth-1-half"/>
    </div>
    <!-- Excerpt -->
    <div class="col-md-9 excerpt">

...

        <!-- Feed footer -->
      <div class="feed-footer row">
        <div class="small"> {{ post.created_at | timeAgo }}</div>
        <button type="button" flat color="green" @click="showModal('ModalReplyForm')">
          <i class="fa fa-reply" ></i>

...

        <div v-show="postOwner(post)" class="">
          <button type="button" flat color="grey" @click="deletePost(post.id)">
            <i class="fa fa-trash " ></i>
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { mapMutations } from 'vuex';
import PostsService from '../../services/PostsService'
import RepliesService from '../../services/RepliesService'
import Replies from '@/components/Reply/Replies'
import ReplyForm from '@/components/Reply/ReplyForm'
export default {
  name: "Post",
  props: {
    post: {
      type: Object,
      required: true
    }
  },
  components: {
    Replies,
    ReplyForm
  },
  computed: {
    me() {
      return this.$store.getters.user
    }
  },
  methods: {
    ...mapMutations(['showModal']),
    ...
  }
};
</script>

AppModal.vue - универсальный модальный компонент

<template>
  <div class="c-appModal">
    <div class="c-appModal__overlay" v-if="visible"></div>
    <div class="c-appModal__content" v-if="visible" @click.self="hideModal"></div>
      <div class="c-appModal__innerContent">
        <component :is="component"></component>
      </div>
  </div>
</template>

<script>
import Vue from 'vue';
import { mapState, mapMutations } from 'vuex';

export default {
  name: 'AppModal',
  data() {
    return {
      component: null
    }
  },
  computed: {
    ...mapState({
      visible: 'modalVisible',
      modalComponent: 'modalComponent'
    }),
  },
  methods: {
    ...mapMutations(['hideModal'])
  },
  watch: {
    modalComponent(componentName) {
      if (!componentName) return;

      Vue.component(componentName, () => import(`@/components/modals/${componentName}`));

      this.component = componentName;
    }
  },
  created() {
    const escapeHandler = (e) => {
      if (e.key === 'Escape' && this.visible) {
        this.hideModal();
      }
    };

    document.addEventListener('keydown', escapeHandler);
    this.$once('hook:destroyed', () => {
      document.removeEventListener('keydown', escapeHandler);
    });
  },
};
</script>

ModalReplyForm - конкретный модальный контент ответа

<template>
  <div>
    <div class="c-modalReply">
      <div>
        <label for="reply">Your comment</label>
        <div class="field">
          <textarea name="reply" v-model="reply" rows="2" placeholder="Compose reply"></textarea>
        </div>
      </div>

      <button class="c-modalReply__cancel" @click="hideModal">Cancel</button>
      <button class="c-modalReply__post" :disabled="!isFormValid" @click="createReply">Reply</button>
    </div>
  </div>
</template>

<script>
import RepliesService from '@/services/RepliesService'
import { mapMutations } from 'vuex';

export default {
  name: "ModalReplyForm",
  // props: {
  //   post: {
  //     type: Object,
  //     required: true
  //   }
  // },
  data() {
    return {
      reply: ""
    };
  },
  computed: {
    isFormValid() {
      return !!this.reply;
    },
    currentGroup() {
      return this.$store.getters.currentPost;
    }
  },
  methods: {
    ...mapMutations([
      'hideModal'
    ]),
    async createReply () {
      let result = await RepliesService.addReply({
        reply: {
          body: this.reply,
          postId: this.post.id
        }
      });
      this.$emit("reply-created");
      this.hideModal();
    }
  }
};
</script>

1 Ответ

0 голосов
/ 16 октября 2019

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

В этом сообщении говорится, что вы никогда не импортировали / не определяли ModalReplyForm, которого у вас нет.

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

Если вы добавите:

import ModalReportForm from ...

и:

components: {
  ModalReplyForm
}

AppModal.vue, модал должен делать то, что вы ожидаете.

...