简体   繁体   English

使用 Popper Js 创建 Vue 组件下拉菜单

[英]Creating Vue Component Dropdown with Popper Js

I'm on progress to make a dropdown component with vue and popperjs.我正在使用 vue 和 popperjs 制作一个下拉组件。 To be known i'm using vuejs v.2.6.12 and popperjs v.2.9.2 and here is the code要知道我正在使用vuejs v.2.6.12popperjs v.2.9.2 ,这是代码

<template>
        <button type="button" @click="show = true">
            <slot />
            <portal v-if="show" to="dropdown">
                <div>
                    <div
                        style="position: fixed; top: 0; right: 0; left: 0; bottom: 0; z-index: 99998; background: black; opacity: .2"
                        @click="show = false"
                    />
                    <div
                        ref="dropdown"
                        style="position: absolute; z-index: 99999;"
                        @click.stop="show = autoClose ? false : true"
                    >
                        <slot name="dropdown" />
                    </div>
                </div>
            </portal>
        </button>
    </template>
    
    <script>
    import { createPopper } from "@popperjs/core";
    
    export default {
        props: {
            placement: {
                type: String,
                default: "bottom-end"
            },
            boundary: {
                type: String,
                default: "scrollParent"
            },
            autoClose: {
                type: Boolean,
                default: true
            }
        },
        data() {
            return {
                show: false
            };
        },
        watch: {
            show(show) {
                if (show) {
                    this.$nextTick(() => {
                        this.popper = createPopper(this.$el, this.$refs.dropdown, {
                            placement: this.placement,
                            modifiers: [
                                {
                                    name: "preventOverflow",
                                    options: {
                                        boundary: this.boundary
                                    }
                                }
                            ]
                        });
                    });
                } else if (this.popper) {
                    setTimeout(() => this.popper.destroy(), 100);
                }
            }
        },
        mounted() {
            document.addEventListener("keydown", e => {
                if (e.keyCode === 27) {
                    this.show = false;
                }
            });
        }
    };
    </script>

When i'm trying to run the code, i get error message Popper: Invalid reference or popper argument provided. They must be either a DOM element or virtual element.当我尝试运行代码时,我收到错误消息Popper: Invalid reference or popper argument provided. They must be either a DOM element or virtual element. Popper: Invalid reference or popper argument provided. They must be either a DOM element or virtual element. I don't know why i got this error, i think i've put the reference this.$el and the popper this.$refs.dropdown on the right place.我不知道为什么会出现此错误,我想我已将引用this.$el和 popper this.$refs.dropdown放在正确的位置。

Could anybody here to help me for solving this problem?有人可以帮我解决这个问题吗?
Thank You谢谢你

I created a snippet that works without the mentioned errors.我创建了一个没有上述错误的片段。

  • you used vue-portal : if it's not globally imported in your code, then you have to import it to the SFC你使用了vue-portal :如果它没有在你的代码中全局导入,那么你必须将它导入到 SFC
  • you have to create <portal-target> somewhere, otherwise this.$refs.dropdown won't exist, as it's the default content of the portal .您必须在某处创建<portal-target> ,否则this.$refs.dropdown将不存在,因为它是portal的默认内容。

 const createPopper = Popper.createPopper /* import { createPopper } from "@popperjs/core"; */ Vue.component('DropDown', { props: { placement: { type: String, default: "bottom-end" }, boundary: { type: String, default: "scrollParent" }, autoClose: { type: Boolean, default: true } }, data() { return { show: false }; }, watch: { show(show) { if (show) { this.$nextTick(() => { this.popper = createPopper(this.$el, this.$refs.dropdown, { placement: this.placement, modifiers: [{ name: "preventOverflow", options: { boundary: this.boundary } }] }); }); } else if (this.popper) { setTimeout(() => this.popper.destroy(), 100); } } }, mounted() { document.addEventListener("keydown", e => { if (e.keyCode === 27) { this.show = false; } }); }, template: ` <button type="button" @click="show = true"> <slot /> <portal v-if="show" to="dropdown" > <div> <div style="position: fixed; top: 0; right: 0; left: 0; bottom: 0; z-index: 99998; background: black; opacity: .2" @click="show = false" /> <div ref="dropdown" style="position: absolute; z-index: 99999;" @click.stop="show = autoClose? false: true" > <slot name="dropdown" /> </div> </div> </portal> </button> ` }) new Vue({ el: "#app", template: ` <div> <drop-down> <template v-slot:default > Dropdown default slot </template> <template v-slot:dropdown > This is the dropdown slot content </template> </drop-down> <portal-target name="dropdown" /> </div> ` })
 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script> <script src="http://unpkg.com/portal-vue"></script> <script src="https://unpkg.com/@popperjs/core@2"></script> <div id="app"></div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM