VueJS显示动态模态组件

时间:2019-10-16 16:17:36

标签: vue.js modal-dialog vuex

我有帖子和回复。通过属性reply.posts_id,回复属于帖子。

我正在尝试将答复表单显示为用户输入答复的模式。但是,我想创建一个通用的Modal组件,该组件可以在任何地方使用,并且可以使用针对特定上下文而构建的另一个组件中指定的内容。

回复是我希望这样做的第一个地方。

当前,当单击答复按钮时,Vuex正确返回Modal visible:true,但是模态未呈现,并且我收到一条错误消息,表明未找到Modal组件:

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 :(得分:0)

  

未知的自定义元素:-您是否注册了   组件正确吗?对于递归组件,请确保提供   “名称”选项。

此消息表明您从未导入/定义ModalReplyForm,而您尚未导入/定义它。

在我自己的通用模式中,我最终不得不导入可能出现在模式本身中的所有组件。

如果添加:

import ModalReportForm from ...

和一个:

components: {
  ModalReplyForm
}

对于AppModal.vue,模态应该可以完成您期望的工作。