如何解决获取 tiptap-vuetify 以在 Vue Nuxt 应用程序中使用“提及”
所以我的问题是我似乎无法在 vuetify-nuxt 项目中使用 tiptap 的“提及”功能。
原始示例可在here
更多有用信息:
为此,我正在尝试结合文档示例。
我想在我尝试使用“tippy”时会出错,这是用于显示实际列出要从中选择的用户的弹出窗口的 css 库(在 @
之后),但我不能似乎不明白真正的问题。
因此,当我键入 @
时,keydown/up 事件侦听器正在运行,但提示似乎没有成功绑定弹出窗口(未显示),并出现以下错误:
Editor.vue?6cd8:204 Uncaught TypeError: Cannot read property '0' of undefined
at VueComponent.enterHandler (Editor.vue?6cd8:204)
at onKeyDown (Editor.vue?6cd8:175)
at Plugin.handleKeyDown (extensions.esm.js?f23d:788)
at eval (index.es.js?f904:3298)
at EditorView.someProp (index.es.js?f904:4766)
at editHandlers.keydown (index.es.js?f904:3298)
这是我的tippy.js nuxt插件:
import Vue from "vue";
import VueTippy,{ Tippycomponent } from "vue-tippy";
Vue.use(VueTippy,{
interactive: true,theme: "light",animateFill: false,arrow: true,arrowType: "round",placement: "bottom",trigger: "click",// appendTo: () => document.getElementById("app")
});
Vue.component("tippy",Tippycomponent);
<template>
<div>
<div class="popup">
aaaa
</div>
<editor-menu-bar v-slot="{ commands }" :editor="editor">
<div class="menubar">
<v-btn class="menubar__button" @click="commands.mention({ id: 1,label: 'Fred Kühn' })">
<v-icon left>@</v-icon>
<span>Mention</span>
</v-btn>
</div>
</editor-menu-bar>
<tiptap-vuetify v-model="localValue" :extensions="extensions" :native-extensions="nativeExtensions" :toolbar-attributes="{ color: 'grey' }" @init="onInit" />
</div>
</template>
<script>
// import the component and the necessary extensions
import {
TiptapVuetify,heading,Bold,Italic,Strike,Underline,Code,CodeBlock,Image,Paragraph,BulletList,OrderedList,ListItem,Link,Blockquote,HardBreak,HorizontalRule,History,} from "tiptap-vuetify";
// TESTING
import { EditorMenuBar,Editor } from "tiptap";
import { Mention } from "tiptap-extensions";
import tippy,{ sticky } from "tippy.js";
export default {
components: { TiptapVuetify,EditorMenuBar },props: {
value: {
type: String,default: "",},data: () => ({
editor: null,extensions: null,nativeExtensions: null,// TESTING
query: null,suggestionRange: null,filteredUsers: [],navigatedUserIndex: 0,insertMention: () => {},popup: null,}),computed: {
localValue: {
get() {
return this.value;
},set(value) {
this.$emit("input",value);
},// TESTING
hasResults() {
return this.filteredUsers.length;
},showSuggestions() {
return this.query || this.hasResults;
},created() {
this.extensions = [
History,[
heading,{
options: {
levels: [1,2,3],],];
this.nativeExtensions = [
// https://github.com/ueberdosis/tiptap/blob/main/examples/Components/Routes/Suggestions/index.vue
new Mention({
// a list of all suggested items
items: async () => {
await new Promise((resolve) => {
setTimeout(resolve,500);
});
return [
{ id: 1,name: "sven Adlung" },{ id: 2,name: "Patrick Baber" },{ id: 3,name: "Nick Hirche" },{ id: 4,name: "Philip Isik" },{ id: 5,name: "Timo Isik" },{ id: 6,name: "Philipp Kühn" },{ id: 7,name: "Hans Pagel" },{ id: 8,name: "Sebastian Schrama" },];
},// When @ is pressed,we enter here
onEnter: ({ items,query,range,command,virtualNode }) => {
this.query = query; // the field that the @ queries? currently empty
this.filteredUsers = items;
this.suggestionRange = range;
this.renderPopup(virtualNode); // render popup - failing
this.insertMention = command; // this is saved to be able to call it from within the popup
},// probably when value after @ is changed
onChange: ({ items,virtualNode }) => {
this.query = query;
this.filteredUsers = items;
this.suggestionRange = range;
this.navigatedUserIndex = 0;
this.renderPopup(virtualNode);
},// mention canceled
onExit: () => {
// reset all saved values
this.query = null;
this.filteredUsers = [];
this.suggestionRange = null;
this.navigatedUserIndex = 0;
this.destroyPopup();
},// any key down during mention typing
onKeyDown: ({ event }) => {
if (event.key === "ArrowUp") {
this.upHandler();
return true;
}
if (event.key === "ArrowDown") {
this.downHandler();
return true;
}
if (event.key === "Enter") {
this.enterHandler();
return true;
}
return false;
},// there may be built-in filtering,not sure
onFilter: async (items,query) => {
await console.log("on filter");
},];
},methods: {
// TESTING
// navigate to the prevIoUs item
// if it's the first item,navigate to the last one
upHandler() {
this.navigatedUserIndex =
(this.navigatedUserIndex + this.filteredUsers.length - 1) %
this.filteredUsers.length;
},// navigate to the next item
// if it's the last item,navigate to the first one
downHandler() {
this.navigatedUserIndex =
(this.navigatedUserIndex + 1) % this.filteredUsers.length;
},enterHandler() {
const user = this.filteredUsers[this.navigatedUserIndex];
if (user) {
this.selectUser(user);
}
},// we have to replace our suggestion text with a mention
// so it's important to pass also the position of your suggestion text
selectUser(user) {
this.insertMention({
range: this.suggestionRange,attrs: {
id: user.id,label: user.name,});
this.editor.focus();
},renderPopup(node) {
if (this.popup) {
return;
}
// ref: https://atomiks.github.io/tippyjs/v6/all-props/
this.popup = tippy(".page",{
getReferenceClientRect: node.getBoundingClientRect,// input location
appendTo: () => document.body,// must be issue
interactive: true,sticky: true,// make sure position of tippy is updated when content changes
plugins: [sticky],content: this.$refs.suggestions,trigger: "mouseenter",// manual
showOnCreate: true,theme: "dark",placement: "top-start",inertia: true,duration: [400,200],});
},destroyPopup() {
if (this.popup) {
this.popup[0].destroy();
this.popup = null;
}
},beforeDestroy() {
this.destroyPopup();
},/**
* NOTE: destructure the editor!
*/
onInit({ editor }) {
this.editor = editor;
},};
</script>
如何在上述设置中显示“建议”项?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。