封装QuillEditor组件
<template>
<div class="quill-editor-container">
<QuillEditor
ref="quillRef"
v-model:content="innerContent"
:options="editorOptions"
content-type="html"
@update:content="handleContentChange"
/>
</div>
</template>
<script lang="ts" setup>
import { computed, useTemplateRef } from 'vue'
import { QuillEditor } from '@vueup/vue-quill'
import type { QuillOptions } from 'quill'
import Quill from 'quill'
import '@vueup/vue-quill/dist/vue-quill.snow.css'
interface QuillEditorProps {
modelValue: string // 外部传入的内容
toolbar?: string | any[] | object // 工具栏配置
placeholder?: string // 占位符
readOnly?: boolean // 是否只读
theme?: 'snow' | 'bubble'
}
// 定义 props
const props = withDefaults(defineProps<QuillEditorProps>(), {
modelValue: '',
placeholder: '请输入内容...',
readOnly: false
})
// 定义 emits
const emit = defineEmits<{
(e: 'update:modelValue', value: string): void
(e: 'change', value: string): void
}>()
const innerContent = computed(() => props.modelValue)
const toolbarOptions = [
['bold', 'italic', 'underline', 'strike'],
['blockquote', 'code-block'],
[{ header: 1 }, { header: 2 }],
[{ list: 'ordered' }, { list: 'bullet' }],
[{ script: 'sub' }, { script: 'super' }],
[{ indent: '-1' }, { indent: '+1' }],
[{ size: ['small', false, 'large', 'huge'] }],
[{ header: [1, 2, 3, 4, 5, 6, false] }],
[{ color: [] }, { background: [] }],
[{ align: [] }],
['clean'],
['link', 'image', 'video']
]
// 编辑器配置
const editorOptions = computed<QuillOptions>(() => ({
theme: 'snow',
placeholder: props.placeholder,
readOnly: props.readOnly,
modules: {
toolbar: props.toolbar || toolbarOptions
}
}))
// 内容变化时触发
const handleContentChange = (content: string) => {
emit('update:modelValue', content)
emit('change', content)
}
// 暴露方法给父组件(如获取 Quill 实例)
const quillRef = useTemplateRef('quillRef')
defineExpose({
getQuillInstance: () => quillRef.value?.getQuill(),
getContent: () => innerContent.value
})
</script>
<style scoped>
.quill-editor-container {
width: 100%;
min-height: 200px;
}
:deep(.ql-editor) {
min-height: 150px;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92