I'm on progress to make a dropdown component with vue and popperjs. To be known i'm using vuejs v.2.6.12
and popperjs v.2.9.2
and here is the code
<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.
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.
Could anybody here to help me for solving this problem?
Thank You
I created a snippet that works without the mentioned errors.
vue-portal
: if it's not globally imported in your code, then you have to import it to the SFC<portal-target>
somewhere, otherwise this.$refs.dropdown
won't exist, as it's the default content of the 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>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.