最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Closing a ModalMenu with the back button in VueNuxt - Stack Overflow

programmeradmin5浏览0评论

I want to close a fullscreen menu or modal when the user tap the hardware backbutton. I tried this:

<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>

but that does not work. Can anyone help me here?

I want to close a fullscreen menu or modal when the user tap the hardware backbutton. I tried this:

<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>

but that does not work. Can anyone help me here?

Share Improve this question asked Oct 22, 2020 at 8:30 sintjsintj 8142 gold badges12 silver badges24 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 3

For this case, my code is similar with Cosimo's Answer but with different approach.

the difference is i keep the modal triggered by the data property ( this.isMenuOpen )

data(){
  return {
    isMenuOpen: false
  }
}

So you can use it to bind in modal ponent

<modal v-model="isMenuOpen" />

and i add a watch property to watch the query

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

then in your openMenu methods you can do this

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

But, in your closeMenu use the $router.replace instead of $router.push

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



Why I use the $router.push for openModal only ? that because it save the history of state, so whenever it open the modal, it will tell the browser new state and than you still can use the back button to the previous state.
After pressed the back button it will remove the query param and it will trigger the watch property

And why use the $router.replace in closeModal ? because it will just replace the state, So when you press back button it will go back to the previous url page instead of open the modal

hypothesis, you could bind the state of the modal (open / closed) with a property of the router, perhaps your-route?isMenuOpen=[true/false]

and on the click of the [open modal] instead of doing

this.isMenuOpen = true 

do:

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

and the modal is binded with

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

I believe that one of the RFCs merged for vue-router for Vue 3 includes better handling for modal dialogs, but there's alternatives that work fine now.

there must be something to prevent the default behavior of the back button

That is done by pushing a new route—you can do that with a query parameter as described in the other answer, or as a new route. I chose to use a new route, and it works quite well.

Install @nuxtjs/router-extras and make sure to add it to your buildModules as described in the installation instructions. Then, if your page is at pages/a.vue, create the file pages/a/some-modal.vue (with some-modal being the path name): this creates a child route. Here, write the contents of your modal dialog. Include the following in that ponent:

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

Now, add a watcher in the parent page (the one that will host the modal dialog) for $route.meta. Property decorator + TypeScript syntax:

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('/'));
        }
    }
}

In your template, include:

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

To open the modal dialog:

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

This doesn't preserve query parameters. It shouldn't be too hard though to create custom logic to do that, however.

Short answer: don't make a modal appear like a page in the first place

Longer answer: excellent question, I had the same problem, tried to run through the answers, which were very good hacks. But with every hack es a caveat, the caveat in this case was that the history state still retained all those pushes. So while you could open a modal (router push) and close it once with the back button (using router replace), when you opened a modal and closed it multiple times, you will quickly find out that you are having to press the back button many more times now to get to the state you are after, this is because the history state now has many more states. I tried to find a way to 'delete' a state but its not possible from my findings (even $router.go(-1) had caveats)

None of this is a problem if your modal is clearly visible as a modal (transparent background surrounding it), which was the case for me in tablet / desktop view. On mobile I tried to be cheeky and set a background color matching that of the modal, and it appeared as a nice flush new page, even though it was just a modal (with the close 'x' icon top right as usual).

Best solution I could e up with is to watch the modal state and if open add a beforeunload function that will prompt the user if they are sure they want to leave.

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

评论列表(0)

  1. 暂无评论