|
@@ -2,7 +2,8 @@
|
|
|
<div class="quill-editor-wrapper">
|
|
|
<QuillEditor
|
|
|
:modules="modules"
|
|
|
- :toolbar="disabled ? disabledToolbarOptions : toolbarOptions"
|
|
|
+ :toolbar="toolbarOptions"
|
|
|
+ ref="wrapperRef"
|
|
|
theme="snow"
|
|
|
contentType="html"
|
|
|
v-bind="$attrs"
|
|
@@ -10,7 +11,56 @@
|
|
|
:content="modelValue"
|
|
|
:placeholder="disabled ? (modelValue ? '' : '暂未填写') : placeholder"
|
|
|
@update:content="(val: string) => emit('update:modelValue', val)"
|
|
|
- />
|
|
|
+ >
|
|
|
+ <template #toolbar>
|
|
|
+ <div :id="toolbarId">
|
|
|
+ <template v-if="!disabled">
|
|
|
+ <button class="ql-bold" title="加粗"></button>
|
|
|
+ <button class="ql-italic" title="斜体"></button>
|
|
|
+ <button class="ql-underline" title="下划线"></button>
|
|
|
+ <button class="ql-strike" title="删除线"></button>
|
|
|
+
|
|
|
+ <button class="ql-divider"></button>
|
|
|
+
|
|
|
+ <button class="ql-blockquote" title="引用"></button>
|
|
|
+ <button class="ql-divider"></button>
|
|
|
+
|
|
|
+ <select class="ql-header">
|
|
|
+ <option v-for="value in headerOptions" :value="value"></option>
|
|
|
+ </select>
|
|
|
+ <button class="ql-divider"></button>
|
|
|
+
|
|
|
+ <button class="ql-list" value="ordered" title="有序列表"></button>
|
|
|
+ <button class="ql-list" value="bullet" title="无序列表"></button>
|
|
|
+ <button class="ql-list" value="check" title="任务列表"></button>
|
|
|
+ <button class="ql-divider"></button>
|
|
|
+
|
|
|
+ <button class="ql-indent" value="-1" title="减少缩进"></button>
|
|
|
+ <button class="ql-indent" value="+1" title="增加缩进"></button>
|
|
|
+ <button class="ql-divider"></button>
|
|
|
+
|
|
|
+ <button class="ql-direction" value="rtl" title="从右到左"></button>
|
|
|
+ <button class="ql-paste-plain" title="粘贴为无格式普通文本">粘贴为纯文本</button>
|
|
|
+ <button class="ql-divider"></button>
|
|
|
+
|
|
|
+ <select class="ql-size">
|
|
|
+ <option v-for="value in Size.whitelist" :value="value"></option>
|
|
|
+ </select>
|
|
|
+
|
|
|
+ <select class="ql-font">
|
|
|
+ <option v-for="value in Font.whitelist" :value="value"></option>
|
|
|
+ </select>
|
|
|
+ <button class="ql-divider"></button>
|
|
|
+
|
|
|
+ <button class="ql-clean" title="清除格式"></button>
|
|
|
+ </template>
|
|
|
+ <div v-else >
|
|
|
+ <ExclamationCircleOutlined />
|
|
|
+ <span class="ms-2">只读模式,无法编辑</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </QuillEditor>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -19,7 +69,13 @@ import { QuillEditor, Quill } from '@vueup/vue-quill'
|
|
|
import '@vueup/vue-quill/dist/vue-quill.snow.css'
|
|
|
import ImageUploader from 'quill-image-uploader';
|
|
|
import CommonContent from '@/api/CommonContent';
|
|
|
-import { onMounted } from 'vue';
|
|
|
+import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
|
|
+import { onMounted, ref } from 'vue';
|
|
|
+import { RandomUtils } from '@imengyu/imengyu-utils';
|
|
|
+import { message } from 'ant-design-vue';
|
|
|
+
|
|
|
+const toolbarId = 'toolbar' + RandomUtils.genNonDuplicateID(5);
|
|
|
+const wrapperRef = ref();
|
|
|
|
|
|
const Size = Quill.import('attributors/style/size')
|
|
|
const Font = Quill.import('attributors/style/font')
|
|
@@ -83,36 +139,30 @@ onMounted(() => {
|
|
|
}, 100)
|
|
|
})
|
|
|
|
|
|
-const disabledToolbarOptions = {
|
|
|
- container: [
|
|
|
- [{ 'text': '只读模式' }]
|
|
|
- ],
|
|
|
-
|
|
|
- // 处理自定义静态文字的渲染
|
|
|
+const toolbarOptions = {
|
|
|
+ container: `#${toolbarId}`,
|
|
|
handlers: {
|
|
|
- 'text': function(value: any) {
|
|
|
- // 静态文字不需要交互,这里留空即可
|
|
|
- }
|
|
|
- },
|
|
|
-}
|
|
|
-const toolbarOptions = [
|
|
|
- ['bold', 'italic', 'underline', 'strike'], // toggled buttons
|
|
|
- ['blockquote'],
|
|
|
- ['link', 'image', 'video'],
|
|
|
-
|
|
|
- [{ 'list': 'ordered'}, { 'list': 'bullet' }, { 'list': 'check' }],
|
|
|
- [{ 'indent': '-1'}, { 'indent': '+1' }], // outdent/indent
|
|
|
- [{ 'direction': 'rtl' }], // text direction
|
|
|
-
|
|
|
- [{ 'size': Size.whitelist }], // custom dropdown
|
|
|
- [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
|
|
|
+ 'divider': () => {},
|
|
|
+ 'text': () => {},
|
|
|
+ 'paste-plain': async () => {
|
|
|
+ const quill = wrapperRef.value.getQuill();
|
|
|
+ let text = ''
|
|
|
+ try {
|
|
|
+ text = await navigator.clipboard.readText()
|
|
|
+ } catch (e) {
|
|
|
+ message.error('粘贴失败,请手动粘贴');
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- [{ 'color': [] }, { 'background': [] }], // dropdown with defaults from theme
|
|
|
- [{ 'font': Font.whitelist }],
|
|
|
- [{ 'align': [] }],
|
|
|
+ if (!text) return
|
|
|
|
|
|
- ['clean'] // remove formatting button
|
|
|
-];
|
|
|
+ const range = quill.getSelection(true)
|
|
|
+ quill.insertText(range.index, text)
|
|
|
+ quill.setSelection(range.index + text.length, 0)
|
|
|
+ },
|
|
|
+ },
|
|
|
+}
|
|
|
+const headerOptions = [ '', 1, 2, 3, 4, 5, 6 ];
|
|
|
const modules = [
|
|
|
{
|
|
|
name: 'imageUploader',
|
|
@@ -243,6 +293,23 @@ $fontList: (
|
|
|
}
|
|
|
|
|
|
}
|
|
|
+ .ql-paste-plain {
|
|
|
+ width: 75px!important;
|
|
|
+ font-size: 12px!important;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.ql-toolbar {
|
|
|
+ .ql-divider {
|
|
|
+ display: inline-block;
|
|
|
+ width: 1px!important;
|
|
|
+ height: 20px!important;
|
|
|
+ margin: 0 5px;
|
|
|
+ margin-top: 3px;
|
|
|
+ padding: 0;
|
|
|
+ border: none;
|
|
|
+ background-color: #efefef;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@each $key, $value in $fontList {
|