-
组件为父子传参里面的东西看个人需要然后定义哈,完全写细东西太多,这里不做过多说明
-
<!--
富文本编辑器
vue2.0请下载以下版本
"tinymce" : "5.1.0"
"@tinymce/tinymce-vue" : "3.0.1"
拷贝tinymce三个目录plugins,skins,themes到publiu/tinymce
---------------------------------------------------------------------
vue3.0请下载以下版本
"tinymce" : "5.10.3"
"@tinymce/tinymce-vue" : "5.0.0"
拷贝tinymce四个目录icons,plugins,skins,themes到publiu/tinymce
---------------------------------------------------------------------
汉化
publiu/tinymce/zh_CN.js 汉化,下载地址 https://www.tiny.cloud/get-tiny/language-packages/
-->
- 资源下载:npm install tinymce -S // 当前版本^5.1.0 npm install @tinymce/tinymce-vue -S // 当前版本^3.0.1
- 下载中文汉化包:Language Packages | Trusted Rich Text Editor | TinyMCE,选择
- 在public下新增tinymce文件夹用于存储插件等,当然也可以不放在public中但是使用时需要指向好,个人建议public下好一点。
- 下载tinymce完成后在node_modules 中找到 tinymce/skins目录,将其复制到public/tinymce目录下面
- 注意下面代码为组件化代码建议components下新增,也可能组件版本差距问题会报错建议按官方文档下载对应版本组件
- 页面使用可以选择全局挂载组件或者在当前页引入使用:import RichText from '@c/RichText/index.vue',使用:<RichText ref="editor" :Tinymcesource="1" v-model="ruleForm.content" />
- 代码:
<!--
富文本编辑器
vue2.0请下载以下版本
"tinymce" : "5.1.0"
"@tinymce/tinymce-vue" : "3.0.1"
拷贝tinymce三个目录plugins,skins,themes到publiu/tinymce
---------------------------------------------------------------------
vue3.0请下载以下版本
"tinymce" : "5.10.3"
"@tinymce/tinymce-vue" : "5.0.0"
拷贝tinymce四个目录icons,plugins,skins,themes到publiu/tinymce
---------------------------------------------------------------------
汉化
publiu/tinymce/zh_CN.js 汉化,下载地址 https://www.tiny.cloud/get-tiny/language-packages/
-->
<template>
<editor v-model="myValue" :init="init" :disabled="disabled" :id="tinymceId" ref="editorRef"></editor>
</template>
<script lang="ts" setup>
import { ref, reactive, watch, onMounted } from "vue";
// //JS部分
// //1、在js中引入所需的主题和组件
import tinymce from "tinymce/tinymce"; //富文本
// import "tinymce/skins/content/default/content.css";
import Editor from "@tinymce/tinymce-vue"; //富文本标签
// import "tinymce/themes/silver";
import "tinymce/themes/silver/theme";
import "tinymce/icons/default"; //引入编辑器图标icon,不引入则不显示对应图标
// 2、引入相关插件
import "tinymce/icons/default/icons"; //自定义icon 操作图标
import "tinymce/plugins/image"; // 插入上传图片插件
import "tinymce/plugins/media"; // 插入视频插件
import "tinymce/plugins/table"; // 插入表格插件
import "tinymce/plugins/emoticons";
import "tinymce/plugins/wordcount"; // 字数统计插件
import "tinymce/plugins/code"; // 源码
import "tinymce/plugins/fullscreen"; //全屏
import "tinymce/plugins/preview";
import "tinymce/icons/default";
import "tinymce/themes/silver";
import "tinymce/plugins/advlist"; //高级列表
import "tinymce/plugins/anchor"; //锚点
import "tinymce/plugins/autolink"; //自动链接
import "tinymce/plugins/autosave"; //编辑器高度自适应,注:plugins里引入此插件时,Init里设置的height将失效
import "tinymce/plugins/codesample"; //代码示例
import "tinymce/plugins/directionality"; //文字方向
import "tinymce/plugins/insertdatetime"; //插入日期时间
import "tinymce/plugins/link"; //链接插件
import "tinymce/plugins/lists"; 列表插件
import "tinymce/plugins/nonbreaking"; //插入不间断空格
import "tinymce/plugins/noneditable";
import "tinymce/plugins/pagebreak"; //插入分页符
import "tinymce/plugins/paste"; //预览
import "tinymce/plugins/print"; //打印
import "tinymce/plugins/save"; //保存
import 'tinymce/plugins/quickbars'
import 'tinymce/plugins/help' //帮助
import 'tinymce/plugins/hr' //水平分割线
import "tinymce/plugins/searchreplace"; //查找替换
// import 'tinymce/plugins/spellchecker' //拼写检查,未加入汉化,不建议使用
import "tinymce/plugins/tabfocus"; //切入切出,按tab键切出编辑器,切入页面其他输入框中
import "tinymce/plugins/template"; //内容模板
import "tinymce/plugins/textpattern"; //快速排版
import "tinymce/plugins/visualblocks"; //显示元素范围
import "tinymce/plugins/visualchars"; //显示不可见字符
import "tinymce/plugins/textcolor"; //文字颜色
import "tinymce/plugins/toc"; //目录生成器
import "../../../public/tinymce/plugins/emoticons/js/emojis.js"
import { ElMessage } from 'element-plus'
import { Upload, Uploadnews } from "@/utils/http";
const emits = defineEmits(["getContent"]);
// 父组件传值
const props = defineProps({
value: {
type: String,
default: () => {
return "";
},
},
// 禁用富文本编辑器,由父组件传值
disabled: {
type: Boolean,
default: false,
},
// 需要加载的插件
plugins: {
type: [String, Array],
default:
"link lists image code emoticons table wordcount preview fullscreen media searchreplace insertdatetime preview print",
}, //必填
// 工具栏
toolbar: {
type: [String, Array],
default:
"fullscreen undo redo emoticons cut copy paste pastetext | table media image insertdatetime bold italic underline preview | forecolor backcolor print | alignleft aligncenter alignright alignjustify | bdmap indent2em lineheight formatpainter axupimgs letterspacing| searchreplace | bullist numlist | fontselect fontsizeselect",
}, //必填
Tinymcesource: {
type: Number,
required: true
}
});
//用于接收外部传递进来的富文本
const editorRef = ref(null);
const myValue = ref(props.value);
// Source:0:教程,1:新闻
const Source = ref(props.Tinymcesource)
const tinymceId = ref(
//富文本编辑器id
"vue-tinymce-ID-" + +new Date() + ((Math.random() * 1000).toFixed(0) + "")
);
//定义一个对象 init初始化
const init = reactive({
selector: "#" + tinymceId.value, //富文本编辑器的id,
resize: false, //右下角哪个拖动改变大小是否可用
emoticons_database_url:'/tinymce/emoticons/js/emojis.js',
// icons_url: '/项目名/icons/custom/icons.js', //自定义图标
language_url: "/tinymce/langs/zh-Hans.js", //语言包路径
language: "zh-Hans", //语言
skin_url: "/tinymce/skins/ui/oxide", //皮肤,自带浅色和深色,在piblic的tinymce的skins的ui里面
height: 500, //编辑器高度
branding: false, //是否禁用“Powered by TinyMCE”
menubar: true, //顶部菜单栏显示
image_dimensions: true, //去除宽高属性
plugins: props.plugins, //这里的数据是在props里面就定义好了的
toolbar: props.toolbar, //这里的数据是在props里面就定义好了的
toolbar_mode: "sliding", //工具栏模式
//字体选择
font_formats: "Arial=arial,helvetica,sans-serif; 宋体=SimSun; 微软雅黑=Microsoft Yahei; Impact=impact,chicago;", //字体
fontsize_formats: "11px 12px 14px 16px 18px 24px 30px 36px 48px 64px 72px", //文字大小
// paste_convert_word_fake_lists: false, // 插入word文档需要该属性
paste_webkit_styles: "all", //此选项允许您指定在WebKit中粘贴时要保留的样式,true保留,false默认样式
paste_merge_formats: true, //此选项启用粘贴插件的合并格式功能
nonbreaking_force_tab: true, // 此选项允许您在用户按下键盘tab键时强制TinyMCE插入三个实体
paste_auto_cleanup_on_paste: false, //粘贴自动清理粘贴
file_picker_types: "media", // // 此选项允许您通过空格或逗号分隔的类型名称列表指定所需的文件选取器类型。目前有三种有效类型:文件、图像和媒体
insertdatetime_element: true,
insertdatetime_formats: ["%Y-%m-%d", "%H:%M:%S"],
paste_data_images: true,//图片是否可粘贴
init_instance_callback: function (editor: { on: (arg0: string, arg1: (evt: { clipboardData: object; preventDefault: () => void }) => void) => void }) {
editor.on('paste', (evt: { clipboardData: any; preventDefault: () => void; }) => {
// 监听粘贴事件,实现图片粘贴上传
const items = (evt.clipboardData).items
if (items[0].type.indexOf('image') !== -1) {
const formData = new FormData();
formData.append("file", items[0].getAsFile());
// 自定义上传图片的方法
// Source:0:教程,1:新闻
switch (Source.value) {
case 0:
Upload(formData).then(res => {
tinymce.execCommand(
"mceReplaceContent",
true,
`<img src="${res.data.fileAddr}" >`
);
})
break;
case 1:
formData.append("type", "3");
Uploadnews(formData).then(res => {
tinymce.execCommand(
"mceReplaceContent",
true,
`<img src="${res.data.fileAddr}" >`
);
})
break;
default:
break;
}
// 阻止默认事件,防止粘贴的图片进入富文本编辑器中
evt.preventDefault();
} else if (items[0].type.indexOf('video') !== -1) {
const blob = items[0].getAsFile();
const videoURL = URL.createObjectURL(blob);
tinymce.execCommand(
'mceInsertContent',
true,
`<video src="${videoURL}" controls></video>`
);
evt.preventDefault();
}
})
},
//开始前执行
setup: function (editor: { ui: { registry: { addIcon: (arg0: string, arg1: string) => void; }; }; }) {
editor.ui.registry.addIcon(
"image",
`<svg t="1664002320321" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4420" width="24" height="24"><path d="M125.9 185h772.2v653.9H125.9z" fill="#1F53CC" p-id="4421"></path><path d="M164.7 217.2h694.6v516.7H164.7z" fill="#FECD44" p-id="4422"></path><path d="M458.9 734l-8.6-43.8-101.5-102.8-135 146.6z" fill="#FC355D" p-id="4423"></path><path d="M306.9 348.7m-66.7 0a66.7 66.7 0 1 0 133.4 0 66.7 66.7 0 1 0-133.4 0Z" fill="#FFFFFF" p-id="4424"></path><path d="M384.6 734h474.7V608.8L687.8 400.1z" fill="#FC355D" p-id="4425"></path><path d="M422.5 662l-37.9 72 52.1-57.5z" fill="#BF2847" p-id="4426"></path><path d="M302.5 778.9h418.9v16.7H302.5z" fill="#00F0D4" p-id="4427"></path></svg>`
);
},
// content_css: "/web-official-website-manage/skins/content/default/content.css", //以css文件方式自定义可编辑区域的css样式,css文件需自己创建并引入
content_css: "/tinymce/skins/content/default/content.min.css", //以css文件方式自定义可编辑区域的css样式,css文件需自己创建并引入
/**
* 上传图片
* @param blobInfo 图片信息
* @param success 成功回调
* @param failure 失败回调
*/
images_upload_handler: (
blobInfo: { blob: () => string | Blob },
success: (arg0: string) => void,
failure: (arg0: string) => void
) => {
const formImg = new FormData(); //创建表单对象
formImg.append("file", blobInfo.blob());//通过formImg对象封装图片二进制数据
// Source:0:教程,1:新闻
switch (Source.value) {
case 0:
Upload(formImg).then((res) => {
const { status, message } = res
if (200 == status) {
success(res.data.fileAddr);
} else {
ElMessage({
message: message,
type: 'error',
})
failure('上传失败');
}
}).catch((err) => {
failure(err);
});
break;
case 1:
formImg.append("type", "3");
Uploadnews(formImg).then(res => {
const { status, message } = res
if (200 == status) {
success(res.data.fileAddr);
} else {
ElMessage({
message: message,
type: 'error',
})
failure('上传失败');
}
}).catch((err) => {
failure(err);
});
break;
default:
break;
}
},
// 文件上传 需要的话添加
// 上传视频
file_picker_callback: (callback: (arg0: string) => void, value: Array<any>, meta: { filetype: string; }) => {
if (meta.filetype == "media") {
// callback('movie.mp4', { source2: 'alt.ogg', poster: 'image.jpg' });
let input = document.createElement("input");
input.setAttribute("type", "file");
input.setAttribute("accept", ".mp3, .mp4");
input.click();
input.onchange = function (v: any) {
let formVideo = new FormData();
formVideo.append("file", v.target.files[0]);
// Source:0:教程,1:新闻
switch (Source.value) {
case 0:
Upload(formVideo).then((res) => {
const { status, message } = res
if (200 == status) {
let rr = res.data.fileAddr;
// callback 回调的作用是将所选择的视频的url显示在输入框中
callback(rr);
} else {
ElMessage({
message: message,
type: 'error',
})
}
});
break;
case 1:
formVideo.append("type", "3");
Uploadnews(formVideo).then((res) => {
const { status, message } = res
if (200 == status) {
let rr = res.data.fileAddr;
// callback 回调的作用是将所选择的视频的url显示在输入框中
callback(rr);
} else {
ElMessage({
message: message,
type: 'error',
})
}
});
break;
default:
break;
}
};
}
},
});
//监听外部传递进来的的数据变化,如果有变化就赋值然后调用父组件的方法同样赋值
watch(() => props.value, () => {
myValue.value = props.value;
emits("getContent", myValue.value);
}
);
//监听富文本中的数据变化
watch(() => myValue.value, () => {
emits("getContent", myValue.value);
}
);
//在onMounted中初始化编辑器
onMounted(() => { tinymce.init({}) });
</script>
<style>
.tox-tinymce {
height: 50vh !important;
width: 100%;
touch-action: none !important;
}
</style>
Vue使用tinymce富文本
最新推荐文章于 2024-08-05 17:45:34 发布