117 lines
2.8 KiB
JavaScript
117 lines
2.8 KiB
JavaScript
import { computePosition, flip, shift } from '@floating-ui/dom'
|
|
import { posToDOMRect, VueRenderer } from '@tiptap/vue-3'
|
|
|
|
import MentionList from './MentionList.vue'
|
|
import { defAvatar } from '@/constant/default'
|
|
|
|
const updatePosition = (editor, element) => {
|
|
const virtualElement = {
|
|
getBoundingClientRect: () => posToDOMRect(editor.view, editor.state.selection.from, editor.state.selection.to),
|
|
}
|
|
|
|
computePosition(virtualElement, element, {
|
|
placement: 'bottom-start',
|
|
strategy: 'absolute',
|
|
middleware: [shift(), flip()],
|
|
}).then(({ x, y, strategy }) => {
|
|
element.style.position = strategy
|
|
if (window.__POWERED_BY_WUJIE__) {
|
|
element.style.left = `${x + 200}px`
|
|
element.style.top = `${y + 100}px`
|
|
} else {
|
|
element.style.left = `${x}px`
|
|
element.style.top = `${y}px`
|
|
}
|
|
|
|
|
|
})
|
|
}
|
|
|
|
export default {
|
|
items: ({ query, editor, props }) => {
|
|
if (!props.members || !props.members.length) {
|
|
return []
|
|
}
|
|
|
|
let list = [...props.members]
|
|
|
|
// 如果是群组管理员,添加"所有人"选项
|
|
if (props.isGroupManager) {
|
|
list.unshift({ id: 0, nickname: '所有人', avatar: defAvatar })
|
|
}
|
|
// 排除掉自己
|
|
list.splice(list.findIndex((item) => item.id === props.uid), 1)
|
|
|
|
const filteredItems = list.filter(
|
|
(item) => item.nickname.toLowerCase().includes(query.toLowerCase())
|
|
)
|
|
|
|
// 如果没有匹配项,返回空数组以关闭弹窗
|
|
if (filteredItems.length === 0) {
|
|
return []
|
|
}
|
|
|
|
return filteredItems
|
|
},
|
|
|
|
render: () => {
|
|
let component
|
|
|
|
return {
|
|
onStart: props => {
|
|
// 如果没有匹配项,不创建弹窗
|
|
if (!props.items || props.items.length === 0) {
|
|
return
|
|
}
|
|
|
|
component = new VueRenderer(MentionList, {
|
|
// Vue 3 props格式
|
|
props,
|
|
editor: props.editor,
|
|
})
|
|
|
|
if (!props.clientRect) {
|
|
return
|
|
}
|
|
|
|
component.element.style.position = 'absolute'
|
|
|
|
document.body.appendChild(component.element)
|
|
|
|
updatePosition(props.editor, component.element)
|
|
},
|
|
|
|
onUpdate(props) {
|
|
component.updateProps(props)
|
|
|
|
if (props.items.length === 0) {
|
|
this.onExit()
|
|
return
|
|
}
|
|
|
|
if (!props.clientRect) {
|
|
return
|
|
}
|
|
|
|
updatePosition(props.editor, component.element)
|
|
},
|
|
|
|
onKeyDown(props) {
|
|
if (props.event.key === 'Escape') {
|
|
this.onExit()
|
|
return true
|
|
}
|
|
if(!component?.props.items?.length){
|
|
return false
|
|
}
|
|
return component.ref.onKeyDown(props)
|
|
},
|
|
|
|
onExit() {
|
|
console.log('component.element',component.element)
|
|
component.element.remove()
|
|
component.destroy()
|
|
},
|
|
}
|
|
},
|
|
} |