【问题标题】:Closing a Modal/Menu with the back button in Vue/Nuxt在 Vue/Nuxt 中使用后退按钮关闭模态/菜单
【发布时间】:2020-10-22 08:30:49
【问题描述】:

我想在用户点击硬件后退按钮时关闭全屏菜单或模式。 我试过这个:

<script>
    export default {
        data(){
            return{
                isMenuOpen: false
            }
        },
        methods:{
            openMenu(){
                this.isMenuOpen = true
                document.addEventListener('backbutton', this.closeMenu, false)
            },
            closeMenu(){
                this.isMenuOpen = false
                document.removeEventListener('backbutton', this.closeMenu)
            }
        }
    }
</script>

但这不起作用。有人可以帮我吗?

【问题讨论】:

    标签: javascript vue.js dom events modal-dialog


    【解决方案1】:

    对于这种情况,我的代码与 Cosimo's Answer 类似,但方法不同。

    不同之处在于我保留了由数据属性( this.isMenuOpen )触发的模式

    data(){
      return {
        isMenuOpen: false
      }
    }
    

    所以你可以用它来绑定模态组件

    <modal v-model="isMenuOpen" />
    

    我添加了一个 watch 属性来观察查询

    watch: {
      $route(newVal, oldVal) {
        this.isMenuOpen = newVal.query?.isMenuOpen || false
      }
    }
    

    然后在你的 openMenu 方法中你可以这样做

    openMenu(){
      this.isMenuOpen = true
      this.$router.push({
        name : "same-path",
        query : {
          isMenuOpen : true
        }
      })
    }
    

    但是,在您的 closeMenu 中使用 $router.replace 而不是 $router.push

    closeMenu(){
      this.isMenuOpen = false
      this.$router.replace({
        name : "same-path"
      })
    }
    



    为什么我只将 $router.push 用于 openModal ?因为它保存了状态的历史,所以每当它打开模式时,它会告诉浏览器新的状态,然后你仍然可以使用后退按钮回到之前的状态。
    按下后退按钮后,它将删除查询参数并触发监视属性

    为什么在 closeModal 中使用 $router.replace ?因为它只会替换状态,所以当你按下后退按钮时,它会回到上一个 url 页面而不是打开 modal

    【讨论】:

      【解决方案2】:

      假设,您可以将模式的状态(打开/关闭)与路由器的属性绑定,也许是 your-route?isMenuOpen=[true/false]

      点击[打开模式]而不是做

      this.isMenuOpen = true 
      

      做:

      this.$router.push({path:'same-path', query: {isMenuOpen: true}});
      

      和模态绑定

      <modal v-model="$router.query.isMenuOpen" />
      

      【讨论】:

      • 这是我没有想到的,但我不想弄乱菜单的参数查询。我的意思是当菜单打开时,必须有一些东西来阻止返回按钮的默认行为。
      【解决方案3】:

      我相信为 Vue 3 的 vue-router 合并的 RFC 之一包括更好地处理模态对话框,但现在有替代方案可以正常工作。

      必须有一些东西来阻止返回按钮的默认行为

      这是通过推送新路由来完成的——您可以使用the other answer 中描述的查询参数或作为新路由来实现。我选择了一条新路线,效果很好。

      安装@nuxtjs/router-extras 并确保按照安装说明将其添加到您的buildModules。然后,如果您的页面位于pages/a.vue,则创建文件pages/a/some-modal.vuesome-modal 是路径名):这将创建一个子路由。在这里,编写模态对话框的内容。在该组件中包含以下内容:

      <router>
      meta:
        showModal: true
      </router>
      

      现在,在$route.meta 的父页面(将承载模式对话框的页面)中添加一个观察者。 Property decorator + TypeScript 语法:

      export default class Index extends Vue {
          showModal = false;
      
          @Watch('$route.meta', { immediate: true })
          navigate(meta: { showModal?: boolean }) {
              this.showModal = !!meta.showModal;
          }
      
          back() {
              this.showModal = false;
              if (window.history.length > 2) {
                  this.$router.back();
              } else {
                  const pathPaths = this.$route.path.split('/');
                  pathPaths.pop();
                  this.$router.push(pathPaths.join('/'));
              }
          }
      }
      

      在您的模板中,包括:

      <modal-component v-model="showModal" @close="back">
          <NuxtChild :extra-props="extraProps" />
      </modal-component>
      

      打开模态对话框:

      <nuxt-link to="some-modal" append>Open</nuxt-link>
      

      这不会保留查询参数。不过,创建自定义逻辑来做到这一点应该不会太难。

      【讨论】:

        【解决方案4】:

        简短的回答:首先不要让模态框看起来像一个页面

        更长的答案:很好的问题,我有同样的问题,试图通过答案,这是非常好的黑客。但是每次 hack 都有一个警告,在这种情况下需要警告的是历史状态仍然保留了所有这些推送。因此,虽然您可以打开一个模式(路由器推送)并使用后退按钮将其关闭一次(使用路由器替换),但当您打开一个模式并多次关闭它时,您会很快发现您必须按下后退按钮现在要多次到达您所追求的状态,这是因为历史状态现在有更多状态。我试图找到一种“删除”状态的方法,但从我的发现中这是不可能的(即使$router.go(-1) 有警告)

        如果您的模态作为模态清晰可见(围绕它的透明背景),这一切都不是问题,我在平板电脑/桌面视图中就是这种情况。在移动设备上,我试图厚颜无耻地设置与模态匹配的背景颜色,它看起来像一个漂亮的刷新新页面,即使它只是一个模态(像往常一样在右上角关闭“x”图标)。

        我能想到的最佳解决方案是观察模态状态,如果打开添加一个beforeunload 函数,该函数将提示用户是否确定要离开。

        'modal.isOpen': {
            immediate: true,
            handler: function(newVal) {
                if (newVal) {
                    window.onbeforeunload = this.beforeWindowUnload;
                }
                else {
                    window.onbeforeunload = null;
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2017-05-23
          • 1970-01-01
          • 2019-04-26
          • 2017-12-19
          • 2019-10-07
          • 1970-01-01
          • 1970-01-01
          • 2015-12-20
          • 1970-01-01
          相关资源
          最近更新 更多