feat: quill module Mention
This commit is contained in:
parent
499ca08300
commit
8be935cf09
|
@ -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"
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
56
src/styles/editor/editor.module.mention.scss
Normal file
56
src/styles/editor/editor.module.mention.scss
Normal 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
1
src/types/quill-mention.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
declare module 'quill-mention' {}
|
Loading…
Reference in a new issue