|
|
|
@ -4,13 +4,12 @@ |
|
|
|
@ 备注: |
|
|
|
--> |
|
|
|
<script lang='ts' setup> |
|
|
|
// 引入富文本编辑器与样式 |
|
|
|
import { Quill, QuillEditor } from '@vueup/vue-quill' |
|
|
|
import '@vueup/vue-quill/dist/vue-quill.snow.css' |
|
|
|
import { newUploadFileApi } from '@/api/common/public' |
|
|
|
// 引入缩放图片的插件 |
|
|
|
import BlotFormatter from 'quill-blot-formatter' |
|
|
|
Quill.register('modules/blotFormatter', BlotFormatter) |
|
|
|
import { onMounted, ref } from 'vue'; |
|
|
|
import Quill from 'quill'; |
|
|
|
import 'quill/dist/quill.snow.css'; // 引入样式 |
|
|
|
|
|
|
|
const editor = ref(null); |
|
|
|
|
|
|
|
const props = withDefaults( |
|
|
|
defineProps<{ |
|
|
|
@ -50,199 +49,19 @@ const content = computed({ |
|
|
|
emits('update:modelValue', newVal) |
|
|
|
} |
|
|
|
}) |
|
|
|
const editorRef = ref(null) |
|
|
|
// 处理富文本图片上传 |
|
|
|
const imageHandler = () => { |
|
|
|
// 创建一个文件输入元素 |
|
|
|
const input = document.createElement('input'); |
|
|
|
input.setAttribute('type', 'file'); |
|
|
|
input.setAttribute('accept', 'image/*'); |
|
|
|
// 模拟点击,打开文件选择对话框 |
|
|
|
input.click(); |
|
|
|
|
|
|
|
// 当用户选择文件后触发的事件 |
|
|
|
input.onchange = async () => { |
|
|
|
// 获取用户选择的文件 |
|
|
|
const file = input.files ? input.files[0] : null; |
|
|
|
if (file) { |
|
|
|
// 创建一个 FormData 对象,用于文件上传 |
|
|
|
const formData = new FormData(); |
|
|
|
formData.append('file', file); |
|
|
|
formData.append('type',"1") |
|
|
|
try { |
|
|
|
newUploadFileApi(formData) |
|
|
|
.then(res =>{ |
|
|
|
// console.log("上传图片",res.data) |
|
|
|
// resolve(res.data.url) |
|
|
|
const quill = toRaw(editorRef.value).getQuill() |
|
|
|
if (quill) { |
|
|
|
// 获取当前光标位置 |
|
|
|
const range = quill.getSelection(true); |
|
|
|
// 在当前光标位置插入上传的图片 |
|
|
|
quill.insertEmbed(range.index, 'image',res.data.url); |
|
|
|
} |
|
|
|
}) |
|
|
|
.catch(()=>{ |
|
|
|
// reject('上传出错,请查看你上传的文件是否符合要求!') |
|
|
|
alert('上传出错,请查看你上传的文件是否符合要求!') |
|
|
|
}) |
|
|
|
} catch (error) { |
|
|
|
alert('图片上传失败') |
|
|
|
} |
|
|
|
|
|
|
|
// try { |
|
|
|
// /** |
|
|
|
// * @todo 可以选中图片,然后把file文件给后端,后端给存到文件服务器,然后返回一个线上地址 |
|
|
|
// * 这里的abc替换成你的请求接口方法,也可以使用 axios 发送 POST 请求 |
|
|
|
// * */ |
|
|
|
// // todo |
|
|
|
// // 使用 axios 发送 POST 请求,将文件上传到服务器,这里的abc替换成你的请求接口方法 |
|
|
|
// // 可以选中图片,然后把file文件给后端,后端给存到文件服务器,然后返回一个线上地址 |
|
|
|
// const res = await abc(formData); |
|
|
|
|
|
|
|
// // 确保获取到 Quill 编辑器实例 |
|
|
|
// const quill = toRaw(editorRef.value).getQuill() |
|
|
|
// if (quill) { |
|
|
|
// // 获取当前光标位置 |
|
|
|
// const range = quill.getSelection(true); |
|
|
|
// // 在当前光标位置插入上传的图片 |
|
|
|
// quill.insertEmbed(range.index, 'image', res.data); |
|
|
|
// } |
|
|
|
|
|
|
|
// } catch (error) { |
|
|
|
// alert('图片上传失败') |
|
|
|
// } |
|
|
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// toolbar标题,划过富文本头部提示信息 |
|
|
|
const titleConfig = [ |
|
|
|
{ Choice: '.ql-insertMetric', title: '跳转配置' }, |
|
|
|
{ Choice: '.ql-bold', title: '加粗' }, |
|
|
|
{ Choice: '.ql-italic', title: '斜体' }, |
|
|
|
{ Choice: '.ql-underline', title: '下划线' }, |
|
|
|
{ Choice: '.ql-header', title: '段落格式' }, |
|
|
|
{ Choice: '.ql-strike', title: '删除线' }, |
|
|
|
{ Choice: '.ql-blockquote', title: '块引用' }, |
|
|
|
{ Choice: '.ql-code', title: '插入代码' }, |
|
|
|
{ Choice: '.ql-code-block', title: '插入代码段' }, |
|
|
|
{ Choice: '.ql-font', title: '字体' }, |
|
|
|
{ Choice: '.ql-size', title: '字体大小' }, |
|
|
|
{ Choice: '.ql-list[value="ordered"]', title: '编号列表' }, |
|
|
|
{ Choice: '.ql-list[value="bullet"]', title: '项目列表' }, |
|
|
|
{ Choice: '.ql-direction', title: '文本方向' }, |
|
|
|
{ Choice: '.ql-header[value="1"]', title: 'h1' }, |
|
|
|
{ Choice: '.ql-header[value="2"]', title: 'h2' }, |
|
|
|
{ Choice: '.ql-align', title: '对齐方式' }, |
|
|
|
{ Choice: '.ql-color', title: '字体颜色' }, |
|
|
|
{ Choice: '.ql-background', title: '背景颜色' }, |
|
|
|
{ Choice: '.ql-image', title: '图像' }, |
|
|
|
{ Choice: '.ql-video', title: '视频' }, |
|
|
|
{ Choice: '.ql-link', title: '添加链接' }, |
|
|
|
{ Choice: '.ql-formula', title: '插入公式' }, |
|
|
|
{ Choice: '.ql-clean', title: '清除字体格式' }, |
|
|
|
{ Choice: '.ql-script[value="sub"]', title: '下标' }, |
|
|
|
{ Choice: '.ql-script[value="super"]', title: '上标' }, |
|
|
|
{ Choice: '.ql-indent[value="-1"]', title: '向左缩进' }, |
|
|
|
{ Choice: '.ql-indent[value="+1"]', title: '向右缩进' }, |
|
|
|
{ Choice: '.ql-header .ql-picker-label', title: '标题大小' }, |
|
|
|
{ Choice: '.ql-header .ql-picker-item[data-value="1"]', title: '标题一' }, |
|
|
|
{ Choice: '.ql-header .ql-picker-item[data-value="2"]', title: '标题二' }, |
|
|
|
{ Choice: '.ql-header .ql-picker-item[data-value="3"]', title: '标题三' }, |
|
|
|
{ Choice: '.ql-header .ql-picker-item[data-value="4"]', title: '标题四' }, |
|
|
|
{ Choice: '.ql-header .ql-picker-item[data-value="5"]', title: '标题五' }, |
|
|
|
{ Choice: '.ql-header .ql-picker-item[data-value="6"]', title: '标题六' }, |
|
|
|
{ Choice: '.ql-header .ql-picker-item:last-child', title: '标准' }, |
|
|
|
{ Choice: '.ql-size .ql-picker-item[data-value="small"]', title: '小号' }, |
|
|
|
{ Choice: '.ql-size .ql-picker-item[data-value="large"]', title: '大号' }, |
|
|
|
{ Choice: '.ql-size .ql-picker-item[data-value="huge"]', title: '超大号' }, |
|
|
|
{ Choice: '.ql-size .ql-picker-item:nth-child(2)', title: '标准' }, |
|
|
|
{ Choice: '.ql-align .ql-picker-item:first-child', title: '居左对齐' }, |
|
|
|
{ Choice: '.ql-align .ql-picker-item[data-value="center"]', title: '居中对齐' }, |
|
|
|
{ Choice: '.ql-align .ql-picker-item[data-value="right"]', title: '居右对齐' }, |
|
|
|
{ Choice: '.ql-align .ql-picker-item[data-value="justify"]', title: '两端对齐' } |
|
|
|
] |
|
|
|
// 富文本配置 |
|
|
|
const options = ref({ |
|
|
|
theme: 'snow', // 使用snow主题 |
|
|
|
modules: { |
|
|
|
// 富文本头部栏的功能配置 |
|
|
|
toolbar: { |
|
|
|
container: [ |
|
|
|
['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线 |
|
|
|
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色 |
|
|
|
[{ align: [] }], // 对齐方式 |
|
|
|
[{ size: ['small', false, 'large', 'huge'] }], // 字体大小 |
|
|
|
[{ font: [] }], // 字体种类 |
|
|
|
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题 |
|
|
|
[{ direction: 'ltl' }], // 文本方向 |
|
|
|
[{ direction: 'rtl' }], // 文本方向 |
|
|
|
[{ indent: '-1' }, { indent: '+1' }], // 缩进 |
|
|
|
[{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表 |
|
|
|
[{ script: 'sub' }, { script: 'super' }], // 上标/下标 |
|
|
|
['blockquote', 'code-block'], // 引用 代码块 |
|
|
|
['clean'], // 清除文本格式 |
|
|
|
['link', 'image', 'video'], // 链接、图片、视频 |
|
|
|
], |
|
|
|
handlers: { |
|
|
|
image: imageHandler, // 点击图片触发事件 |
|
|
|
}, |
|
|
|
}, |
|
|
|
// 图片缩放 |
|
|
|
blotFormatter: { |
|
|
|
// 可以在这里设置缩放样式 |
|
|
|
// overlay: { |
|
|
|
// style: { |
|
|
|
// border: '2px solid red', |
|
|
|
// } |
|
|
|
// }, |
|
|
|
toolbar: { |
|
|
|
mainClassName: 'blot-formatter__toolbar' |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
// !!!如果方法报错,把imageHandler 方法放到options的上面 |
|
|
|
|
|
|
|
// 给富文本框工具栏加上鼠标悬浮中文提示 |
|
|
|
const initTitle = () => { |
|
|
|
for (let item of titleConfig) { |
|
|
|
// .editor 是富文本编辑器的类名 |
|
|
|
let tip = document.querySelector('.editor ' + item.Choice); |
|
|
|
if (tip) { |
|
|
|
tip.setAttribute('title', item.title); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 自定义粘贴事件 |
|
|
|
const customPaste=(e)=>{ |
|
|
|
// 获取当前最新时间 改名啥的可以用 |
|
|
|
let newTime = new Date().getTime() |
|
|
|
|
|
|
|
const clipboardData = e.clipboardData // 粘贴信息 |
|
|
|
const types = clipboardData.types // 当前文件类型 |
|
|
|
if (types.includes('Files')) { |
|
|
|
e.preventDefault(); |
|
|
|
e.clipboardData.files.forEach(file=>{ |
|
|
|
// 在这里可以拿到粘贴后的图片与文件信息 |
|
|
|
// 在这里做操作 |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(()=>{ |
|
|
|
nextTick(()=>{ |
|
|
|
// 给富文本框工具栏加上鼠标悬浮中文提示 |
|
|
|
initTitle() |
|
|
|
quill() |
|
|
|
}) |
|
|
|
// 给富文本增加粘贴事件 |
|
|
|
editorRef.value.getQuill().root.addEventListener('customPaste', customPaste, false) |
|
|
|
|
|
|
|
}) |
|
|
|
watch( |
|
|
|
() => props.modelValue, |
|
|
|
@ -252,16 +71,36 @@ watch( |
|
|
|
} |
|
|
|
} |
|
|
|
) |
|
|
|
|
|
|
|
const quill = new Quill(editor.value, { |
|
|
|
theme: 'snow', |
|
|
|
modules: { |
|
|
|
toolbar: [ |
|
|
|
[{ header: [1, 2, false] }], |
|
|
|
['bold', 'italic', 'underline', 'strike'], // toggled buttons |
|
|
|
['blockquote', 'code-block'], |
|
|
|
|
|
|
|
[{ list: 'ordered'}, { list: 'bullet' }], |
|
|
|
[{ script: 'sub'}, { script: 'super' }], // superscript/subscript |
|
|
|
[{ indent: '-1'}, { indent: '+1' }], // outdent/indent |
|
|
|
[{ direction: 'rtl' }], // text direction |
|
|
|
|
|
|
|
[{ size: ['small', false, 'large', 'huge'] }], // custom dropdown |
|
|
|
[{ header: [1, 2, 3, 4, 5, 6, false] }], |
|
|
|
|
|
|
|
[{ color: [] }, { background: [] }], // dropdown with defaults from theme |
|
|
|
[{ font: [] }], |
|
|
|
[{ align: [] }], |
|
|
|
|
|
|
|
['clean'] // remove formatting button |
|
|
|
] |
|
|
|
} |
|
|
|
}); |
|
|
|
</script> |
|
|
|
<template><div class="butBox" @click="openVideo">按钮</div> |
|
|
|
<template><div class="butBox" >按钮</div> |
|
|
|
<div class="editor"> |
|
|
|
<!-- 这两个都是获取值的必要条件: v-model:content contentType="html" --> |
|
|
|
<quill-editor |
|
|
|
ref="editorRef" |
|
|
|
v-model:content="content" |
|
|
|
:options="options" |
|
|
|
contentType="html" |
|
|
|
></quill-editor> |
|
|
|
{{ content }} {{ newUploadFileApi }} |
|
|
|
<div ref="editor">{{ content }}</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
<style lang='scss' scoped> |
|
|
|
|