带有路由器的 Vue 模态

Posted

技术标签:

【中文标题】带有路由器的 Vue 模态【英文标题】:Vue modal with a router 【发布时间】:2020-12-03 10:10:09 【问题描述】:

我是 Vue 的新手。我正在构建一个简单的应用程序,它将列出所有国家/地区,当您单击特定国家/地区时,它会向您显示有关该国家/地区的更多详细信息。想法是在模态中打开country details

我坚持显示该模式。模式打开,但在后台。它还会打开一个详细信息页面。

CountryDetail.vue:

<script>
import axios from 'axios';
export default 
  name: 'country-detail',
  props: [ 'isDarkTheme' ],
  data () 
    return 
      pending: false,
      error: null,
      countryInfo: null,
      alpha3Code: [],
      alpha3CodetoString: [],
    
  ,
  mounted () 
    this.pending = true;
    axios
      .get(`https://restcountries.eu/rest/v2/name/$this.$route.params.country?fullText=true`)
      .then((response) => 
        (this.countryInfo = response.data)
        this.alpha3CodetoString = this.alpha3Code.join(';');
      )
      .catch(error => (this.error = error ))
      .finally( () =>  this.pending = false );
  ,
  filters: 
    formatNumbers (value) 
      return `$value.toLocaleString()`
    
  

</script>

<template>
<modal v-model="show">
        <div class="modal-mask" :class=" darkTheme : isDarkTheme " name="modal">
          <div class="modal-wrapper">
            <div  class="modal-container">
              <div class="modal-header">
                <slot name="header">
                   <h1 v-if="error !== null">Sorry, an error has occurred error</h1>
                  <div class="loaderFlex"><div v-if="pending" class="loader"></div></div>
                </slot>
              </div>

              <div v-for="country in countryInfo" class="countryTile modal-body" v-bind:key="country.id">
                <slot name="body">
                    <img v-bind:src="country.flag"  class="flag">
                  <div class="country-details">
                        <h1>country.name</h1>
                        <div class="listDiv">
                        <ul>      
                            <li><span>Population:</span> country.population | formatNumbers </li>
                            <li><span>Capital:</span> country.capital</li>
                            <li><span>Iso:</span> country.alpha3Code</li>
                        </ul>
                        <ul>   
                            <li><span>Currencies:</span> country.currencies['0'].name</li>
                            <li><span>Languages:</span> 
                            <span 
                                v-for="(language, index) in country.languages" 
                                v-bind:key="index" 
                                class="languages">
                                language.name<span v-if="index + 1 < country.languages.length">, </span>
                            </span>
                            </li>
                        </ul>
                        </div>    
                    </div>
                </slot>
              </div>

              <div class="modal-footer">
                <slot name="footer">
                <a @click="$router.go(-1)" class="backBtn"><i class="fas fa-arrow-left" />Go Back</a>
                </slot>
              </div>
            </div>
          </div>
        </div>
      </modal>
</template>

Home.vue:

<script>
import axios from 'axios';
export default 
  name: 'home',
  props: [ 'isDarkTheme' ],
  data () 
    return 
      pending: false,
      error: null,
      countryInfo: null,
      search: '',   
      darkMode: false,
    
  ,
  mounted () 
    this.pending = true;
    axios
      .get('https://restcountries.eu/rest/v2/all')
      .then(response => (this.countryInfo = response.data))
      .catch(error => (this.error = error ))
      .finally( () =>  this.pending = false );
  ,
 
  filters: 
    formatNumbers (value) 
      return `$value.toLocaleString()`
    
  ,
  computed: 
    filteredCountries: function () 
      return this.countryInfo.filter((country) => 
        if (this.region === '' ) 
          return country.name.toLowerCase().match(this.search.toLowerCase());
         else if (this.search !== '') 
          return country.name.toLowerCase().match(this.search.toLowerCase());
         else 
          return ('blbla');
        
      )
    
  , 

</script>
<template>
  <div class="home" :class=" darkTheme : isDarkTheme ">
    <div class="searchBar">
      <div class="searchContainer">
        <i class="fas fa-search searchIcon"></i>
        <input 
          class="searchInput" 
          type="text" 
          v-model="search"
          aria-label="Search for a country..."
          placeholder="Search for a country..."
        />
        <ul class="searchResults"></ul>
      </div>

    </div>
    <h1 v-if="error !== null">Sorry, an error has occurred error</h1> 
    <div class="loaderFlex"><div v-if="pending" class="loader"></div></div>

    <div v-if="countryInfo" class="tileGrid" @click="showModal = true">
      <div v-for="country in filteredCountries" class="countryTile" v-bind:key="country.id">
        <router-link 
          :to=" name: 'country-detail', params: country: country.name " 
          class="linkTile"
        >
          <img v-bind:src="country.flag"  class="flag">
          <div class="text">
            <h1> country.name </h1>
          </div>
        </router-link>
      </div>
    </div>
  </div>
  
</template>

【问题讨论】:

【参考方案1】:

路由器链接将始终将您重定向到另一个页面,因为它基本上是&lt;a href="..."&gt;see here。如果您只想在模态上显示细节,则不需要路由器,您只需在 Home.vue 组件中添加模态组件,然后将模态和countryName 与道具绑定,然后在单击按钮时传递它们。

Home.vue:

<template>
 <div>
  <button @click="showDetail">
   Show Detail
  </button>

  <CountryDetail :countryName="countryName" :showModal="showModal"/>
 <div>
</template>

<script>
 import CountryDetail from './CountryDetail.vue'

 export default 
  name: 'Home',
  components:  CountryDetail ,
  data: () => (
   countryName: '',
   showModal: false,
  ),
  methods: 
   showDetail() 
    this.showModal = true;
   ,
  ,
 
</script>

而不是在mounted 上发出请求,您可以使用watch 来做一些事情,比如监视showModal 属性,并在每次它具有真实值时发出请求。像这样:

CountryDetail.vue:

<template>
 <modal v-model="showModal">
  <!-- modal content -->
 </modal>
</template>

<script>
 export default 
   name: 'CountryDetail',
   props: ['countryName', 'showModal'],
   watch: 
     'showModal': 
       deep: true,
       handler(val) 
         if (val && this.countryName !== '') 
           // Make request
         
       
     
   
 
</script>

【讨论】:

以上是关于带有路由器的 Vue 模态的主要内容,如果未能解决你的问题,请参考以下文章

vue给模态框弹窗添加路由,实现页面后退可以关闭模态框

做一个vue模态弹出框如何

带有 vue 2 组件的 vue 路由器不适用于 laravel 5.8

带有firebase身份验证的vue路由器错误

带有 Typescript 的 Vue3 路由器:缺少 RouteConfig

带有路由器的 Vue.js 和 OMDb 页面