Я использую Vue3, Pinia и библиотеку float-vue.
Я пытаюсь динамически создать всплывающее окно в позиции, которая зависит от других элементов, которые могут перемещаться в области просмотра. Для этого я размещаю фиктивный элемент div popup-anchor, к которому прикреплено всплывающее окно.
Когда я нажимаю на конкретный элемент, к которому хочу прикрепить всплывающее окно, этот элемент сохраняется в магазине Pinia.
Всякий раз, когда товар в магазине меняется, я вызываю setPosition() и show() для этого компонента Vue.
selectedItemCoords (newValue, oldValue) {
if (this.$refs.infoPopup) {
if (newValue) {
const pixelCoords = this.getPixelPositionOfItem()
this.$refs.infoPopup.setPosition(pixelCoords)
this.$refs.infoPopup.show();
} else {
this.$refs.infoPopup.close();
}
} else {
console.info("Info Popupvalue not found")
}
}
Это работает хорошо, если между обновлениями предмета в магазине есть задержка (т. е. между обновлениями предмета нет значения), и я нажимаю где-нибудь в другом месте на экране. Однако, если я нажимаю один элемент за другим, всплывающее окно закрывается и не открывается снова, если только я не нажму что-то, что не является элементом, и значение хранилища не будет установлено на ноль.
Однако я хочу, чтобы всплывающее окно появлялось всякий раз, когда showPopup=true, т. е. если выбранные элементы меняются, я просто хочу переместить всплывающее окно и обновить его содержимое.
Ниже находится компонент Vue, который содержит фиктивную привязку и раскрывающийся список с плавающей запятой.
<template>
<div
id = "popup-anchor"
ref = "anchor"
class = "w-1 h-1 "
:style = "{ position: 'absolute'}"
>
<Dropdown
:shown = "showPopup"
:distance = "1"
:triggers = "[]"
:popper-triggers = "[]"
>
<template #popper>
<div
v-if = "item"
:item = "item"
@share = "share"
>
item.text
</div>
<div
v-else
class = "loading-text"
>
Loading...
</div>
</template>
</Dropdown>
</div>
</template>
<script>
import { ref, computed } from 'vue';
import {Dropdown, hideAllPoppers, recomputeAllPoppers} from 'floating-vue';
import { useStore} from "@/store/store";
export default {
components: {
Dropdown,
},
props: {
position: {
type: Object,
required: true,
default: () => ({ top: '0px', left: '0px' }),
},
},
setup(props, { expose }) {
const anchor = ref(null);
const showPopup = ref(false);
const storage = useStore();
const item = computed(() => storage.item);
// Method to toggle the visibility of the InfoPopup
const show = () => {
showPopup.value = true
console.info('show', showPopup.value)
};
const close = () => {
showPopup.value = false
hideAllPoppers();
console.info('close', showPopup.value)
};
const setPosition = (pixelCoords) => {
anchor.value.style.top = `${pixelCoords[1]}px`;
anchor.value.style.left =`${pixelCoords[0]}px`;
recomputeAllPoppers();
};
const share = () => {
console.info('share')
};
expose({ anchor, show, close , setPosition});
return {
anchor,
show,
close,
share,
showPopup,
item,
};
},
};
</script>
Но разве не это именно то, что я здесь делаю? Всплывающая привязка имеет абсолютную позицию, а в setPosition я задаю координаты.





После обширной отладки я обнаружил, что проблема заключалась не в положении привязывающего div, а в том, что всплывающему окну нужно время, чтобы закрыться и снова открыться. Таким образом, установка showPopup = false, а затем showPopup = true в одном и том же галочке фактически скрывает всплывающее окно, но не открывает его повторно. Решение состоит в том, чтобы ввести задержку между обоими действиями.
const show = () => {
if (showPopup.value = true) {
// if the popup is already showing we have to close it
// and reopen it in the next tick so it can update the position
close();
nextTick(() => {
showPopup.value = true
});
} else {
showPopup.value = true
}
};
«...позиция, которая зависит от других элементов...» — получите координаты этого базового элемента (смещение) и поместите всплывающее окно в нужную вам координату (с позицией: абсолютная. Посмотрите stackoverflow.com/questions/ 6802956/…