<template>
<div class="editor-container">
<textarea v-if="!initOptions.inline" :id="tinymceId" ref="elRef" :style="{ visibility: 'hidden' }"></textarea>
<el-dialog v-model="dialogVisible" title="图片列表" width="860" top="5vh" :before-close="imgChooseCancel">
<div v-loading="imgLoading" class="tanBox" element-loading-text="正在获取中,预计等待1-2分钟,请稍后...">
<div v-if="imgBtnFlag" style="text-align: center; margin-top: 30px">
<el-empty description="还没有获取图片,点击获取图片,预计等待1-2分钟">
<el-button type="primary" @click="goCrawling">获取图片</el-button>
</el-empty>
</div>
<div v-if="imgList.length">
<div
v-for="(item, index) in imgList"
:key="index"
class="tanItem"
:class="{ selected: isSelected(index) }"
@click="imgClick(index)"
>
<el-icon class="iconClass" color="#409eff"><Select /></el-icon>
<img :src="typeof item === 'string' ? item : undefined" />
</div>
</div>
<div v-if="!imgList.length && !imgBtnFlag" style="margin: 0 auto">
<el-empty description="暂无图片" />
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="imgChooseCancel">取消</el-button>
<el-button type="primary" @click="imgChooseSure">确认</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { useRoute } from 'vue-router';
import { Select } from '@element-plus/icons-vue';
import type { Editor, RawEditorSettings } from 'tinymce'; // tinymce 要求 5.10.3
import tinymce from 'tinymce/tinymce';
import { ElMessage } from 'element-plus';
// import { pathConfig } from '@/service/request/opinionIndex';
import 'tinymce/themes/silver';
import 'tinymce/icons/default/icons';
import 'tinymce/plugins/advlist';
import 'tinymce/plugins/code';
import 'tinymce/plugins/fullscreen';
import 'tinymce/plugins/link';
import 'tinymce/plugins/lists';
import 'tinymce/plugins/media';
import 'tinymce/plugins/image';
import 'tinymce/plugins/autoresize';
import 'tinymce/plugins/table';
import './importword/index.js';
import 'tinymce/plugins/colorpicker';
import 'tinymce/plugins/textcolor';
import 'tinymce/plugins/contextmenu';
import 'tinymce/plugins/paste';
import { $DictApi } from '@/service/api/dict';
// eslint-disable-next-line import/order
import { computed, nextTick, onBeforeUnmount, onDeactivated, onMounted, ref, unref, watch } from 'vue';
import { Rewrite } from '@/service/api/rewrite';
import { plugins, toolbar, content_style, fontsize_formats, font_formats, toolbarSimple } from './const';
interface RowVO {
[key: string]: any;
}
// 这一段是我自己的东西,获取本地缓存相关的
const $route = useRoute();
const props = defineProps({
value: { type: String, default: '' }, // html 字符串
disabled: { type: Boolean, default: false }, // 是否禁用
simple: { type: Boolean, default: false }, // 是否禁用
getText: { type: Boolean, default: false }, // 是否禁用
disabledBtn: { type: Boolean, default: false }, // 是否禁用
width: { type: [Number, String], default: '100%' }, // 宽
height: { type: [Number, String] }, // 高
defaultId: { type: String, default: '' }, // 高
// imgList: { type: Array, default: () => [] },
/** tinymce 配置项 */
options: { type: Object, default: () => {} }
});
// 插入图片
const imgLoading = ref<boolean>(false);
const imgList = ref<string[]>([]); // 这是一个 string[] 类型的数组
const tuList = ref<Array<any>>([]);
const getImgList = async () => {
imgList.value = [];
const params = {
articleId: $route.query.id
};
const response: RowVO = await Rewrite.article.queryImageList(params);
if (response.data.code === '0000') {
tuList.value = response.data.data;
tuList.value.forEach(async item => {
// imgList.value.push(`${pathConfig.baseURL}/RewriteArticleController/download?token=${item.imgPath}`);
imgList.value.push(item.imgPath);
});
}
};
const imgBtnFlag = ref<boolean>(false);
const timer = ref<NodeJS.Timeout | null>(null);
//
const getImgStatus = async () => {
if (timer.value) {
clearTimeout(timer.value);
}
const params = {
id: $route.query.id
};
const response: RowVO = await Rewrite.article.imgStatus(params);
if (response.data.code === '0000') {
if (response.data.data === '3') {
getImgList();
imgBtnFlag.value = false;
imgLoading.value = false;
} else if (response.data.data === '0' || response.data.data === '4') {
imgBtnFlag.value = true;
imgLoading.value = false;
} else {
imgBtnFlag.value = false;
imgLoading.value = true;
console.log(timer.value, 'timer.value');
timer.value = setTimeout(() => {
getImgStatus();
}, 1000);
}
}
};
const goCrawling = async () => {
const params = {
id: $route.query.id
};
const response: RowVO = await Rewrite.article.imgInitStatus(params);
if (response.data.code === '0000') {
getImgStatus();
}
};
// 插入图片
const emits = defineEmits(['update:value', 'change']);
const editorRef = ref<any>(null);
const elRef = ref<any>(null);
const dialogVisible = ref<boolean>(false);
const tinymceId = ref<string>(props.defaultId ? props.defaultId : `tiny-vue${String(Date.now())}`);
const initOptions = computed((): RawEditorSettings => {
const publicPath = '/kb-web/';
return {
selector: `#${unref(tinymceId)}`,
height: props.height ? props.height : '',
autoresize_min_height: 100, // 设置编辑器最小高度
width: props.width,
toolbar: `${props.simple ? toolbarSimple : toolbar} ${props.disabledBtn ? 'myCustomToolbarButton' : ''} `,
plugins: `${plugins} ${props.height ? '' : 'autoresize'} `,
menubar: false,
resize: false,
statusbar: false,
language_url: `${publicPath}tinymce/langs/zh_Hans.js`,
language: 'zh-Hans',
branding: false,
default_link_target: '_blank',
paste_as_text: false, // 粘贴内容时强制为纯文本q
paste_data_images: true, // 是否支持粘贴图片
skin: 'oxide',
skin_url: `${publicPath}tinymce/skins/ui/oxide`,
content_style, // 自定义内容样式
content_css: `${publicPath}tinymce/skins/ui/oxide/content.min.css`,
...props.options,
// paste_webkit_styles: 'color font-size',
fontsize_formats,
font_formats: '',
style_formats_merge: true,
paste_webkit_styles: 'all', // 允许粘贴的WebKit样式
paste_merge_formats: true, // 合并粘贴的格式
paste_retain_style_properties: 'all', // 保留所有样式属性
// importword_options: {
// extract_css: true // 确保开启CSS提取(没生效)
// },
importword_styles: 'all',
// 添加额外的样式处理插件暂时没用
// external_plugins: {
// powerpaste: `${publicPath}tinymce/powerpaste/plugin.min.js` // ${this.baseUrl}
// },
// powerpaste_word_import: 'merge', // 参数:propmt, merge, clear
// powerpaste_html_import: 'merge', // propmt, merge, clear
// powerpaste_allow_local_images: true, // 粘贴图片
// 文本的处理:例如去掉a标签
paste_preprocess(pluginApi, data) {
// // 使用DOM解析器来处理HTML内容
// const domParser = new DOMParser();
// const doc = domParser.parseFromString(data.content, 'text/html');
// // 查找所有的a标签并移除
// const links = doc.querySelectorAll('a');
// for (let i = links.length - 1; i >= 0; i--) {
// const link = links[i];
// link.parentNode.replaceChild(document.createTextNode(link.textContent), link);
// }
// // 将处理后的HTML内容赋回到粘贴数据中
// data.content = doc.documentElement.innerHTML;
// console.log(data.content, 'data.content');
},
// 导入word
importword_handler(editor, files, next) {
const file_name = files[0].name;
if (file_name.substr(file_name.lastIndexOf('.') + 1) == 'docx') {
editor.notificationManager.open({
text: '正在转换中...',
type: 'info',
closeButton: false
});
next(files);
} else {
editor.notificationManager.open({
text: '目前仅支持docx文件格式,若为doc,请将扩展名改为docx',
type: 'warning',
timeout: 3000
});
}
},
file_picker_callback(callback, value, meta) {
// 文件分类
const filetype = '.pdf, .txt, .doc, .docx, .xls, .xlsx, .ppt, .pptx,';
// 后端接收上传文件的地址
// 为不同插件指定文件类型及后端地址
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', filetype);
input.click();
// eslint-disable-next-line func-names
input.onchange = async function () {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const that: any = this;
const file = that.files[0];
const formData = new FormData();
formData.append('file', file, file.name);
const result = await $DictApi.fileUpload(formData);
if (result && result.data && result.data.data) {
// const data = result.data.data as any;
callback(result.data.data.filePath, { text: result.data.data.fileName });
return true;
}
return false;
};
},
// images_dataimg_filter(img) {
// return img.hasAttribute('internal-blob');
// },
async images_upload_handler(blobInfo, succFun, failFun) {
console.log('2222');
// const fileData = new FormData();
// const file = blobInfo.blob();
// fileData.append('file', file as File);
// const result = await $DictApi.fileUpload(fileData);
// if (result && result.data && result.data.data) {
// // const data = result.data.data as any;
// return true;
// }
// return false;
},
style_formats: [
{
title: 'Line Height',
items: [
{ title: '1', inline: 'span', styles: { 'line-height': '1' } },
{ title: '1.5', inline: 'span', styles: { 'line-height': '1.5' } },
{ title: '2', inline: 'span', styles: { 'line-height': '2' } },
{ title: '2.5', inline: 'span', styles: { 'line-height': '2.5' } },
{ title: '3', inline: 'span', styles: { 'line-height': '3' } },
{ title: '3.5', inline: 'span', styles: { 'line-height': '3.5' } },
{ title: '4', inline: 'span', styles: { 'line-height': '4' } },
{ title: '4.5', inline: 'span', styles: { 'line-height': '4.5' } },
{ title: '5', inline: 'span', styles: { 'line-height': '5' } },
{ title: '5.5', inline: 'span', styles: { 'line-height': '5.5' } },
{ title: '6', inline: 'span', styles: { 'line-height': '6' } }
]
},
{
title: 'Letter Spacing',
items: [
{ title: '-0.5px', inline: 'span', styles: { 'letter-spacing': '-0.5px' } },
{ title: '-1px', inline: 'span', styles: { 'letter-spacing': '-1px' } },
{ title: 'Default', inline: 'span', styles: { 'letter-spacing': 'normal' } },
{ title: '0.5px', inline: 'span', styles: { 'letter-spacing': '0.5px' } },
{ title: '1px', inline: 'span', styles: { 'letter-spacing': '1px' } },
{ title: '1.5px', inline: 'span', styles: { 'letter-spacing': '1.5px' } },
{ title: '2px', inline: 'span', styles: { 'letter-spacing': '2px' } },
{ title: '2.5px', inline: 'span', styles: { 'letter-spacing': '2.5px' } },
{ title: '3px', inline: 'span', styles: { 'letter-spacing': '3px' } },
{ title: '3.5px', inline: 'span', styles: { 'letter-spacing': '3.5px' } },
{ title: '4px', inline: 'span', styles: { 'letter-spacing': '4px' } },
{ title: '4.5px', inline: 'span', styles: { 'letter-spacing': '4.5px' } },
{ title: '5.5px', inline: 'span', styles: { 'letter-spacing': '5.5px' } },
{ title: '5.6px', inline: 'span', styles: { 'letter-spacing': '5.6px' } },
{ title: '5.7px', inline: 'span', styles: { 'letter-spacing': '5.7px' } },
{ title: '5.8px', inline: 'span', styles: { 'letter-spacing': '5.8px' } },
{ title: '6.0px', inline: 'span', styles: { 'letter-spacing': '6.0px' } },
{ title: '6.5px', inline: 'span', styles: { 'letter-spacing': '6.5px' } },
{ title: '7.5px', inline: 'span', styles: { 'letter-spacing': '7.5px' } },
{ title: '8.5px', inline: 'span', styles: { 'letter-spacing': '8.5px' } },
{ title: '9.5px', inline: 'span', styles: { 'letter-spacing': '9.5px' } },
{ title: '10.5px', inline: 'span', styles: { 'letter-spacing': '10.5px' } },
{ title: '11px', inline: 'span', styles: { 'letter-spacing': '11px' } },
{ title: '11.5px', inline: 'span', styles: { 'letter-spacing': '11.5px' } },
{ title: '12px', inline: 'span', styles: { 'letter-spacing': '12px' } },
{ title: '12.5px', inline: 'span', styles: { 'letter-spacing': '12.5px' } },
{ title: '13px', inline: 'span', styles: { 'letter-spacing': '13px' } },
{ title: '13.5px', inline: 'span', styles: { 'letter-spacing': '13.5px' } },
{ title: '14px', inline: 'span', styles: { 'letter-spacing': '14px' } },
{ title: '14.5px', inline: 'span', styles: { 'letter-spacing': '14.5px' } },
{ title: '15px', inline: 'span', styles: { 'letter-spacing': '15px' } },
{ title: '15.5px', inline: 'span', styles: { 'letter-spacing': '15.5px' } },
{ title: '16px', inline: 'span', styles: { 'letter-spacing': '16px' } },
{ title: '16.5px', inline: 'span', styles: { 'letter-spacing': '16.5px' } },
{ title: '17px', inline: 'span', styles: { 'letter-spacing': '17px' } },
{ title: '17.5px', inline: 'span', styles: { 'letter-spacing': '17.5px' } },
{ title: '18px', inline: 'span', styles: { 'letter-spacing': '18px' } },
{ title: '18.5px', inline: 'span', styles: { 'letter-spacing': '18.5px' } },
{ title: '19px', inline: 'span', styles: { 'letter-spacing': '19px' } },
{ title: '19.5px', inline: 'span', styles: { 'letter-spacing': '19.5px' } },
{ title: '20px', inline: 'span', styles: { 'letter-spacing': '20px' } },
{ title: '20.5px', inline: 'span', styles: { 'letter-spacing': '20.5px' } },
{ title: '21px', inline: 'span', styles: { 'letter-spacing': '21px' } },
{ title: '21.5px', inline: 'span', styles: { 'letter-spacing': '21.5px' } },
{ title: '22px', inline: 'span', styles: { 'letter-spacing': '22px' } },
{ title: '22.5px', inline: 'span', styles: { 'letter-spacing': '22.5px' } },
{ title: '23px', inline: 'span', styles: { 'letter-spacing': '23px' } },
{ title: '23.5px', inline: 'span', styles: { 'letter-spacing': '23.5px' } },
{ title: '24px', inline: 'span', styles: { 'letter-spacing': '24px' } },
{ title: '24.5px', inline: 'span', styles: { 'letter-spacing': '24.5px' } },
{ title: '25px', inline: 'span', styles: { 'letter-spacing': '25px' } },
{ title: '25.5px', inline: 'span', styles: { 'letter-spacing': '25.5px' } },
{ title: '26px', inline: 'span', styles: { 'letter-spacing': '26px' } },
{ title: '26.5px', inline: 'span', styles: { 'letter-spacing': '26.5px' } },
{ title: '27px', inline: 'span', styles: { 'letter-spacing': '27px' } },
{ title: '27.5px', inline: 'span', styles: { 'letter-spacing': '27.5px' } },
{ title: '28px', inline: 'span', styles: { 'letter-spacing': '28px' } },
{ title: '28.5px', inline: 'span', styles: { 'letter-spacing': '28.5px' } },
{ title: '29px', inline: 'span', styles: { 'letter-spacing': '29px' } },
{ title: '29.5px', inline: 'span', styles: { 'letter-spacing': '29.5px' } },
{ title: '30px', inline: 'span', styles: { 'letter-spacing': '30px' } },
{ title: '30.5px', inline: 'span', styles: { 'letter-spacing': '30.5px' } },
{ title: '31px', inline: 'span', styles: { 'letter-spacing': '31px' } },
{ title: '31.5px', inline: 'span', styles: { 'letter-spacing': '31.5px' } },
{ title: '32px', inline: 'span', styles: { 'letter-spacing': '32px' } },
{ title: '32.5px', inline: 'span', styles: { 'letter-spacing': '32.5px' } },
{ title: '33px', inline: 'span', styles: { 'letter-spacing': '33px' } },
{ title: '33.5px', inline: 'span', styles: { 'letter-spacing': '33.5px' } },
{ title: '34px', inline: 'span', styles: { 'letter-spacing': '34px' } },
{ title: '34.5px', inline: 'span', styles: { 'letter-spacing': '34.5px' } },
{ title: '35px', inline: 'span', styles: { 'letter-spacing': '35px' } },
{ title: '35.5px', inline: 'span', styles: { 'letter-spacing': '35.5px' } },
{ title: '36px', inline: 'span', styles: { 'letter-spacing': '36px' } },
{ title: '36.5px', inline: 'span', styles: { 'letter-spacing': '36.5px' } },
{ title: '37px', inline: 'span', styles: { 'letter-spacing': '37px' } },
{ title: '37.5px', inline: 'span', styles: { 'letter-spacing': '37.5px' } },
{ title: '38px', inline: 'span', styles: { 'letter-spacing': '38px' } },
{ title: '38.5px', inline: 'span', styles: { 'letter-spacing': '38.5px' } },
{ title: '39px', inline: 'span', styles: { 'letter-spacing': '39px' } },
{ title: '39.5px', inline: 'span', styles: { 'letter-spacing': '39.5px' } },
{ title: '40px', inline: 'span', styles: { 'letter-spacing': '40px' } },
{ title: '40.5px', inline: 'span', styles: { 'letter-spacing': '40.5px' } },
{ title: '41px', inline: 'span', styles: { 'letter-spacing': '41px' } },
{ title: '41.5px', inline: 'span', styles: { 'letter-spacing': '41.5px' } },
{ title: '42px', inline: 'span', styles: { 'letter-spacing': '42px' } },
{ title: '42.5px', inline: 'span', styles: { 'letter-spacing': '42.5px' } },
{ title: '43px', inline: 'span', styles: { 'letter-spacing': '43px' } },
{ title: '43.5px', inline: 'span', styles: { 'letter-spacing': '43.5px' } },
{ title: '44px', inline: 'span', styles: { 'letter-spacing': '44px' } },
{ title: '44.5px', inline: 'span', styles: { 'letter-spacing': '44.5px' } },
{ title: '45px', inline: 'span', styles: { 'letter-spacing': '45px' } },
{ title: '45.5px', inline: 'span', styles: { 'letter-spacing': '45.5px' } },
{ title: '46px', inline: 'span', styles: { 'letter-spacing': '46px' } },
{ title: '46.5px', inline: 'span', styles: { 'letter-spacing': '46.5px' } },
{ title: '47px', inline: 'span', styles: { 'letter-spacing': '47px' } },
{ title: '47.5px', inline: 'span', styles: { 'letter-spacing': '47.5px' } },
{ title: '48px', inline: 'span', styles: { 'letter-spacing': '48px' } },
{ title: '48.5px', inline: 'span', styles: { 'letter-spacing': '48.5px' } },
{ title: '49px', inline: 'span', styles: { 'letter-spacing': '49px' } },
{ title: '49.5px', inline: 'span', styles: { 'letter-spacing': '49.5px' } },
{ title: '50px', inline: 'span', styles: { 'letter-spacing': '50px' } }
]
}
],
// fontsize_formats : [],
setup: (editor: Editor) => {
editorRef.value = editor;
editor.ui.registry.addButton('myCustomToolbarButton', {
text: '原文图片',
onAction: () => {
if ($route.query.id) {
dialogVisible.value = true;
getImgStatus();
} else {
ElMessage.warning('未选择文章');
}
}
});
editor.on('init', () => initSetup());
}
};
});
const selectedIndices = ref<number[]>([]); // 被选中的图片的索引
const isSelected = index => {
return selectedIndices.value.includes(index);
};
const imgClick = val => {
if (isSelected(val)) {
selectedIndices.value = selectedIndices.value.filter(i => i !== val);
} else {
selectedIndices.value.push(val);
}
};
onMounted(() => {
if (!unref(initOptions).inline) {
// tinymceId.value = `tiny-vue${props.defaultId ? props.defaultId : String(Date.now())}`;
tinymceId.value = `${props.defaultId ? props.defaultId : `tiny-vue${String(Date.now())}`}`;
}
nextTick(() => {
setTimeout(() => {
initEditor();
}, 30);
});
});
onBeforeUnmount(() => {
destory();
});
onDeactivated(() => {
destory();
});
/** 初始化富文本 */
async function initEditor() {
const el = unref(elRef);
if (!el) return;
el.style.visibility = '';
// tinymce.init(unref(initOptions));
try {
const options = unref(initOptions);
// 初始化 TinyMCE
tinymce.init(options);
} catch (error) {
console.error('获取字体格式失败:', error);
// 错误处理或者设置默认字体格式
tinymce.init({
...unref(initOptions),
font_formats // 确保这里的 font_formats 是你的默认字体格式字符串
});
}
}
// function replaceImgSrcWithAlt1(htmlString) {
// const parser = new DOMParser();
// const doc = parser.parseFromString(htmlString, 'text/html');
// const imgTags = doc.querySelectorAll('img');
// if (imgTags && imgTags.length) {
// imgTags.forEach(img => {
// const alt = img?.getAttribute('alt');
// if (alt) {
// // 提取图片后缀
// const src = img?.getAttribute('src');
// const matches = src?.match(/(\.(jpg|jpeg|png))(?![\w\W]*\.(jpg|jpeg|png))(\?.*)?$/i);
// if (matches) {
// const imageSuffix = matches[1];
// // 替换src属性
// let newSrc = alt + imageSuffix;
// // 去掉图片后缀之后的参数部分
// newSrc = newSrc?.replace(/(\.(jpg|jpeg|png))(.*)$/i, '\$1');
// img?.setAttribute('src', newSrc);
// }
// }
// });
// }
// const bodyContent = doc.body.innerHTML;
// return bodyContent;
// }
function hasBase64Img(imgElements) {
for (const img of imgElements) {
const src = img.getAttribute('src');
if (src && src.startsWith('data:image/')) {
return true; // 如果有一个src是base64格式的,返回true
}
}
return false; // 如果所有的src都不是base64格式的,返回false
}
async function replaceImgSrcWithAlt(htmlString) {
// 创建一个DOM元素来解析HTML字符串
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, 'text/html');
// 获取所有img标签
const imgElements = doc.querySelectorAll('img');
// 如果没有img标签,直接返回原始的HTML字符串
if (imgElements.length === 0) {
return htmlString;
}
const baseFlag = hasBase64Img(imgElements);
if (baseFlag) {
// 遍历所有img标签
for (const imgElement of Array.from(imgElements)) {
// 获取img标签的src属性
const src = imgElement.getAttribute('src');
// 检查src是否为base64格式的图片
if (src && src.startsWith('data:image')) {
// 将base64格式的图片转换为Blob对象
const base64Data = src.split(',')[1];
const byteCharacters = atob(base64Data);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: 'image/png' });
// 将Blob对象添加到FormData中
const formData = new FormData();
formData.append('file', blob, 'image.png');
try {
// eslint-disable-next-line no-await-in-loop
const result = await $DictApi.fileUpload(formData);
// eslint-disable-next-line max-depth
if (result && result.data && result.data.data) {
const uploadedSrc = result.data.data.filePath;
imgElement.setAttribute('src', uploadedSrc);
}
} catch (error) {
console.error('上传图片出错:', error);
}
} else {
const src1 = src?.replace(/(\.(jpg|jpeg|png))(.*)$/i, '\$1') || '';
imgElement.setAttribute('src', src1);
}
}
return doc.body.innerHTML;
}
return htmlString;
}
// const lastHtml = ref<string>('');
// const zLastHtml = async () => {
// lastHtml.value = await replaceImgSrcWithAlt(props.value);
// };
// zLastHtml();
const imgChooseCancel = () => {
dialogVisible.value = false;
imgLoading.value = false;
selectedIndices.value = [];
// clearTimeout(timer.value);
};
const imgChooseSure = () => {
if (selectedIndices.value && !selectedIndices.value.length) {
ElMessage.warning('请选择图片');
return;
}
// editorRef.value.insertContent(`<img src="${imageUrl}" alt="Image" />`);
const images = selectedIndices.value.map(index => imgList.value[index]);
const imageTags = images.map(image => `<img src="${image}" alt="Image" />`).join('');
editorRef.value.insertContent(imageTags);
imgChooseCancel();
};
/** 初始化富文本配置 */
function initSetup() {
const editor = unref(editorRef);
if (!editor) return;
const value = props.value || '';
editor.setContent(replaceImgSrcWithAlt(value));
bindModelHandlers(editor);
}
/** 注销 */
function destory() {
console.log(tinymce, unref(initOptions).selector!, '333333333destorydestorydestory');
if (tinymce !== null) {
tinymce?.remove?.(unref(initOptions).selector!);
}
}
const oldVal = ref();
const newVal = ref();
/** 默认事件注册 */
function bindModelHandlers(editor) {
watch(
() => props.value,
async (val: any, val1: any) => {
oldVal.value = val1;
newVal.value = val;
const bb = await replaceImgSrcWithAlt(val);
setValue(editor, bb);
},
{
immediate: true
}
);
watch(
() => props.disabled,
(val: boolean) => {
const editor = unref(editorRef);
if (!editor) return;
editor.setMode(val ? 'readonly' : 'design');
},
{ immediate: true }
);
// function debounce(func, delay) {
// let timeoutId;
// return (...args) => {
// // eslint-disable-next-line consistent-this
// const context = this;
// clearTimeout(timeoutId);
// timeoutId = setTimeout(() => {
// func.apply(context, args);
// }, delay);
// };
// }
// 防抖函数
let timeout: any = null;
type GreetingFunction = (flag: boolean) => void;
const debounce = (flag: boolean, func: GreetingFunction, wait: number) => {
return function () {
clearTimeout(timeout);
timeout = setTimeout(function () {
func(flag);
}, wait);
};
};
const debouncedCallback = debounce(
false,
async () => {
const content = editor.getContent({ format: 'html' });
const contentText = editor.getContent({ format: 'text' });
// console.log(oldVal.value, ' oldVal.value');
// console.log(content, ' newVal.value');
// await replaceImgSrcWithAlt(content);
emits('update:value', content);
if (props.getText) {
emits('change', { content, contentText });
} else {
emits('change', content);
}
},
300
); // 设置防抖时间为300毫秒
editor.on('change keyup undo redo', debouncedCallback);
// editor.on('change keyup undo redo', async () => {
// const content = editor.getContent({ format: 'html' });
// const contentText = editor.getContent({ format: 'text' });
// // console.log(props.value, '1111');
// // console.log(content, 'contentcontentcontentcontent');
// console.log(oldVal.value, ' oldVal.value');
// console.log(content, ' newVal.value');
// // eslint-disable-next-line no-self-compare
// // if (oldVal.value !== content) {
// emits('update:value', content);
// if (props.getText) {
// emits('change', { content, contentText });
// } else {
// emits('change', content);
// }
// // }
// });
editor.on('ExecCommand', e => {
const command = e.command;
// 这里你可以检查执行的命令是什么
console.log('Executed command:', e.target.value);
// 根据不同的命令做不同的处理
if (command === 'mceApplyTextcolor' || command === 'ForeColor') {
console.log('文字颜色被修改了。');
}
if (command === 'FontSize' || command === 'mceFontSize') {
console.log('字体大小被修改了。');
}
if (command === 'FontName') {
}
});
// editor.on("change", async () => {
// const content: string = editor.getContent();
// console.log(content)
// // 重写内容
// editor.setContent(content);
// // 光标重写
// editor.selection.select(editor.getBody(), true);
// editor.selection.collapse(false);
// });
//
// // 失焦时,自动回传数据,考虑加入以下事件 keyup undo redo
// editor.on("blur", () => {
// const content = editor.getContent();
// emits("update:value", content);
// emits("change", content);
// });
}
/** 写入数据 */
function setValue(editor: Editor, val: string) {
const pp = editor?.selection?.getBookmark(2); // 光标重写
if (editor && val) {
const cur = editor.getContent();
if (cur !== val) {
editor.setContent(val);
setTimeout(() => {
// 定位最后的位置
editor.selection.moveToBookmark(pp); // 光标重写
}, 1);
}
}
}
</script>
<style scoped lang="scss">
.tox .tox-dialog--width-lg {
background-color: red;
}
.tanBox {
overflow: hidden;
max-height: 70vh;
overflow-y: auto;
.tanItem {
width: 200px;
height: 200px;
float: left;
margin-left: 20px;
margin-top: 20px;
border: 1px #eee solid;
padding: 10px;
position: relative;
.iconClass {
position: absolute;
top: 5px;
right: 5px;
display: none;
}
img {
display: block;
max-width: 100%;
max-height: 100%;
}
}
.tanItem.selected {
border: 1px #409eff solid;
.iconClass {
display: block;
}
}
}
</style>
<!-- ./importword/index.js ./tinymce/const.js -->