使用 Popper Js 创建 Vue 组件下拉列表
Creating Vue Component Dropdown with Popper Js
我正在使用 vue 和 popperjs 制作下拉组件。众所周知,我正在使用 vuejs v.2.6.12
和 popperjs 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>
当我尝试 运行 代码时,我收到错误消息 Popper: Invalid reference or popper argument provided. They must be either a DOM element or virtual element.
我不知道为什么会出现此错误,我想我已将参考 this.$el
和 popper this.$refs.dropdown
放在正确的位置。
有人可以帮我解决这个问题吗?
谢谢
我创建了一个没有提到的错误的片段。
- 你使用了
vue-portal
:如果你的代码中没有全局导入,那么你必须将它导入到SFC
- 您必须在某处创建
<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>
我正在使用 vue 和 popperjs 制作下拉组件。众所周知,我正在使用 vuejs v.2.6.12
和 popperjs 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>
当我尝试 运行 代码时,我收到错误消息 Popper: Invalid reference or popper argument provided. They must be either a DOM element or virtual element.
我不知道为什么会出现此错误,我想我已将参考 this.$el
和 popper this.$refs.dropdown
放在正确的位置。
有人可以帮我解决这个问题吗?
谢谢
我创建了一个没有提到的错误的片段。
- 你使用了
vue-portal
:如果你的代码中没有全局导入,那么你必须将它导入到SFC - 您必须在某处创建
<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>