feat: quill module Mention

This commit is contained in:
KUN1007 2023-09-08 22:13:36 +08:00
parent 499ca08300
commit 8be935cf09
6 changed files with 208 additions and 5 deletions

View file

@ -27,6 +27,7 @@
"quill-blot-formatter": "^1.0.5", "quill-blot-formatter": "^1.0.5",
"quill-image-uploader": "^1.3.0", "quill-image-uploader": "^1.3.0",
"quill-magic-url": "^4.2.0", "quill-magic-url": "^4.2.0",
"quill-mention": "^3.4.1",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-i18n": "^9.2.2", "vue-i18n": "^9.2.2",
"vue-router": "^4.2.4" "vue-router": "^4.2.4"

View file

@ -32,6 +32,9 @@ dependencies:
quill-magic-url: quill-magic-url:
specifier: ^4.2.0 specifier: ^4.2.0
version: 4.2.0 version: 4.2.0
quill-mention:
specifier: ^3.4.1
version: 3.4.1
vue: vue:
specifier: ^3.3.4 specifier: ^3.3.4
version: 3.3.4 version: 3.3.4
@ -1681,6 +1684,12 @@ packages:
quill-delta: 3.6.3 quill-delta: 3.6.3
dev: false dev: false
/quill-mention@3.4.1:
resolution: {integrity: sha512-7/KyWGDbh3T2pw/kPNhXrsUkc1j2Kp9mxtK7QqmU84A6oHIlcjCubsFntHQYPwX/xoJnjyzcWiBrig8vEgW0AA==}
dependencies:
quill: 1.3.7
dev: false
/quill@1.3.7: /quill@1.3.7:
resolution: {integrity: sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==} resolution: {integrity: sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==}
dependencies: dependencies:

View file

@ -136,9 +136,9 @@ const handleDeleteHistory = (historyIndex: number) => {
@click="handleClickHistory(index)" @click="handleClickHistory(index)"
> >
<span>{{ history }} </span> <span>{{ history }} </span>
<span @click="handleDeleteHistory(index)" <span @click="handleDeleteHistory(index)">
><Icon class="delete" icon="line-md:close-circle" <Icon class="delete" icon="line-md:close-circle" />
/></span> </span>
</div> </div>
</div> </div>
</div> </div>

View file

@ -9,6 +9,9 @@ import BlotFormatter from 'quill-blot-formatter'
import ImageUploader from 'quill-image-uploader' import ImageUploader from 'quill-image-uploader'
// module: URL // module: URL
import MagicUrl from 'quill-magic-url' import MagicUrl from 'quill-magic-url'
// module: mention
import Mention from 'quill-mention'
import '@/styles/editor/editor.snow.scss'
// quill // quill
import '@/styles/editor/editor.snow.scss' import '@/styles/editor/editor.snow.scss'
@ -30,7 +33,6 @@ import { storeToRefs } from 'pinia'
import DOMPurify from 'dompurify' import DOMPurify from 'dompurify'
// //
import { debounce } from '@/utils/debounce' import { debounce } from '@/utils/debounce'
import kungalgame from '@/router/modules/kungalgame'
const { editorHeight, mode, theme, isSave, content } = storeToRefs( const { editorHeight, mode, theme, isSave, content } = storeToRefs(
useKUNGalgameEditStore() useKUNGalgameEditStore()
@ -56,6 +58,12 @@ const props = defineProps<{
// //
const editorRef = ref<typeof QuillEditor>() const editorRef = ref<typeof QuillEditor>()
//
interface MentionItem {
id: number
value: string
}
// modules // modules
const modules = [ const modules = [
// BlotFormatter // BlotFormatter
@ -100,8 +108,77 @@ const modules = [
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
}, },
}, },
// Mention
{
name: 'mention',
module: Mention,
options: {
//
// allowedChars: /^[A-Za-z\s]*$/,
// mention
mentionDenotationChars: ['@', '#'],
/**
* @param {string} searchTerm - 用户输入的搜索关键词
* @param {(items: MentionItem[]) => void} renderList - 渲染列表回调函数需传入从后端获取的搜索结果数组
* @param {string} mentionChar - 触发 mention 操作的关键词
*/
source: async function (
searchTerm: string,
renderList: (items: MentionItem[]) => void,
mentionChar: string
) {
// mentionChar
if (mentionChar === '@') {
//
const matchedUsers: MentionItem[] = await searchUsers(searchTerm)
renderList(matchedUsers)
} else if (mentionChar === '#') {
//
const matchedTopics: MentionItem[] = await searchTopics(searchTerm)
renderList(matchedTopics)
}
},
},
},
] ]
//
async function searchUsers(searchTerm: string): Promise<MentionItem[]> {
//
//
return [
{ id: 1, value: 'kun' },
{ id: 2, value: 'yuyu' },
{ id: 3, value: 'kun' },
{ id: 4, value: 'yuyu' },
{ id: 5, value: 'kun' },
{ id: 6, value: 'yuyu' },
{ id: 7, value: 'kun' },
{ id: 8, value: 'yuyu' },
{ id: 9, value: 'kun' },
{ id: 10, value: 'yuyu' },
{ id: 11, value: 'kun' },
{ id: 12, value: 'yuyu' },
{ id: 13, value: 'kun' },
{ id: 14, value: 'yuyu' },
{ id: 15, value: 'kun' },
{ id: 16, value: 'yuyu' },
]
}
//
async function searchTopics(searchTerm: string): Promise<MentionItem[]> {
//
//
return [
{
id: 1,
value: '啊这可海星啊这可海星啊这可海星啊这可海星啊这可海星啊这可海星',
},
{ id: 2, value: '鲲最可爱' },
]
}
// //
const editorHeightStyle = computed( const editorHeightStyle = computed(
() => `height: ${props.height ? props.height : editorHeight.value}px` () => `height: ${props.height ? props.height : editorHeight.value}px`
@ -250,7 +327,7 @@ const handleTextChange = async () => {
} }
} }
/* BlotFormatter 插件的样式 */ /* BlotFormatter 插件的样式,这里不用 !important 不行 */
.blot-formatter__toolbar-button { .blot-formatter__toolbar-button {
margin: 0 5px; margin: 0 5px;
border: none !important; border: none !important;
@ -265,5 +342,64 @@ const handleTextChange = async () => {
background: var(--kungalgame-trans-blue-1) !important; background: var(--kungalgame-trans-blue-1) !important;
} }
} }
/* Mention 的样式 */
.ql-mention-list-container {
width: 270px;
border: 1px solid var(--kungalgame-blue-1);
border-radius: 4px;
background-color: var(--kungalgame-trans-white-2);
box-shadow: var(--shadow);
z-index: 9999;
overflow: auto;
}
.ql-mention-loading {
line-height: 44px;
padding: 0 20px;
vertical-align: middle;
font-size: 16px;
}
.ql-mention-list {
list-style: none;
margin: 0;
padding: 0;
overflow: hidden;
}
.ql-mention-list-item {
cursor: pointer;
font-size: 16px;
padding: 10px 20px;
/* 居中、超过一行省略 */
vertical-align: middle;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ql-mention-list-item.disabled {
cursor: auto;
}
.ql-mention-list-item.selected {
background-color: var(--kungalgame-trans-blue-1);
text-decoration: none;
}
.mention {
height: 24px;
width: 65px;
border-radius: 6px;
background-color: var(--kungalgame-trans-blue-1);
padding: 3px 0;
margin-right: 2px;
user-select: all;
}
.mention > span {
margin: 0 3px;
}
} }
</style> </style>

View file

@ -0,0 +1,56 @@
/* 参考 'quill-mention/dist/quill.mention.css' */
.ql-mention-list-container {
width: 270px;
border: 1px solid var(--kungalgame-blue-1);
border-radius: 4px;
background-color: var(--kungalgame-trans-white-2);
box-shadow: var(--shadow);
z-index: 9001;
overflow: auto;
}
.ql-mention-loading {
line-height: 44px;
padding: 0 20px;
vertical-align: middle;
font-size: 16px;
}
.ql-mention-list {
list-style: none;
margin: 0;
padding: 0;
overflow: hidden;
}
.ql-mention-list-item {
cursor: pointer;
line-height: 44px;
font-size: 16px;
padding: 0 20px;
vertical-align: middle;
}
.ql-mention-list-item.disabled {
cursor: auto;
}
.ql-mention-list-item.selected {
background-color: var(--kungalgame-trans-blue-0);
text-decoration: none;
}
.mention {
height: 24px;
width: 65px;
border-radius: 6px;
background-color: var(--kungalgame-trans-blue-0);
padding: 3px 0;
margin-right: 2px;
user-select: all;
}
.mention > span {
margin: 0 3px;
}

1
src/types/quill-mention.d.ts vendored Normal file
View file

@ -0,0 +1 @@
declare module 'quill-mention' {}