|
@@ -1,9 +1,10 @@
|
|
|
<template>
|
|
|
<div>
|
|
|
<Editor
|
|
|
- api-key="写你的key"
|
|
|
+ api-key="nfaxt3iz0ciqr1yg7zxzifvksvval28yl46wr1n0847mt0d3"
|
|
|
:init="init"
|
|
|
- v-model:content="content"
|
|
|
+ v-model="content"
|
|
|
+ :disabled="disabled"
|
|
|
ref="tinymce"
|
|
|
/>
|
|
|
</div>
|
|
@@ -11,16 +12,38 @@
|
|
|
|
|
|
<script setup name="TinymceEditor">
|
|
|
import Editor from "@tinymce/tinymce-vue";
|
|
|
+import { getToken } from "@/utils/auth";
|
|
|
+
|
|
|
+import { watch } from "vue";
|
|
|
const { proxy } = getCurrentInstance();
|
|
|
-const props = defineProps(["value"]);
|
|
|
+const props = defineProps({
|
|
|
+ value: {
|
|
|
+ type: String,
|
|
|
+ default: "",
|
|
|
+ },
|
|
|
+ disabled: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ },
|
|
|
+ plugins: {
|
|
|
+ type: [String, Array],
|
|
|
+ default: "lists link image table code help wordcount",
|
|
|
+ }, //必填
|
|
|
+ toolbar: {
|
|
|
+ type: [String, Array],
|
|
|
+ default:
|
|
|
+ "fontselect | fontsizeselect | formatselect | bold italic underline forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table | image | removeformat",
|
|
|
+ }, //必填
|
|
|
+});
|
|
|
const emit = defineEmits(["updateValue"]);
|
|
|
-const content = ref("");
|
|
|
+const content = ref(props.value);
|
|
|
+const toolbar = ref(props.toolbar);
|
|
|
+const plugins = ref(props.plugins);
|
|
|
+const disabled = ref(props.disabled);
|
|
|
const tinymce = ref(null);
|
|
|
-const value = ref("");
|
|
|
const init = reactive({
|
|
|
- plugins: "lists link image table code help wordcount",
|
|
|
- toolbar:
|
|
|
- "myButton | fontselect | fontsizeselect | formatselect | bold italic underline forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table | image | removeformat",
|
|
|
+ plugins: plugins,
|
|
|
+ toolbar: toolbar,
|
|
|
content_css: "tinymce-5", //主题tinymce-5-dark || tinymce-5 || default || writer || document || dark
|
|
|
custom_undo_redo_levels: 50, //回退数量
|
|
|
end_container_on_empty_block: true, //块级文本是否换行
|
|
@@ -32,66 +55,52 @@ const init = reactive({
|
|
|
elementpath: false, //是否展示编辑层级 > p span
|
|
|
resize: true, //调整宽高 > true 调整高 | false 不可调整宽高 | both 宽高可调
|
|
|
language: "zh_CN", //中文
|
|
|
- images_upload_url: "/demo/upimg.php",
|
|
|
- images_upload_base_path: "/demo",
|
|
|
- // 自定义快捷将
|
|
|
- text_patterns: [
|
|
|
- { start: "---", replacement: "<hr/>" },
|
|
|
- { start: "--", replacement: "—" },
|
|
|
- { start: "-", replacement: "—" },
|
|
|
- { start: "(c)", replacement: "©" },
|
|
|
- { start: "//brb", replacement: "Be Right Back" },
|
|
|
- {
|
|
|
- start: "//h",
|
|
|
- replacement:
|
|
|
- '<h1 style="color: blue">Heading here</h1> <h2>Author: Name here</h2> <p><em>Date: 01/01/2000</em></p> <hr />',
|
|
|
- },
|
|
|
- ],
|
|
|
- images_upload_handler: function (blobInfo, succFun, failFun) {
|
|
|
- var xhr, formData;
|
|
|
- var file = blobInfo.blob(); //转化为易于理解的file对象
|
|
|
- xhr = new XMLHttpRequest();
|
|
|
- xhr.withCredentials = false;
|
|
|
- xhr.open("POST", "/demo/upimg.php");
|
|
|
- xhr.onload = function () {
|
|
|
- var json;
|
|
|
- if (xhr.status != 200) {
|
|
|
- failFun("HTTP Error: " + xhr.status);
|
|
|
- return;
|
|
|
- }
|
|
|
- json = JSON.parse(xhr.responseText);
|
|
|
- if (!json || typeof json.location != "string") {
|
|
|
- failFun("Invalid JSON: " + xhr.responseText);
|
|
|
- return;
|
|
|
- }
|
|
|
- succFun(json.location);
|
|
|
- };
|
|
|
- formData = new FormData();
|
|
|
- formData.append("file", file, file.name); //此处与源文档不一样
|
|
|
- xhr.send(formData);
|
|
|
- },
|
|
|
-
|
|
|
- // 自定义指令
|
|
|
- text_patterns_lookup: (ctx) => {
|
|
|
- const parentTag = ctx.block.nodeName.toLowerCase();
|
|
|
- if (parentTag === "pre" || parentTag === "p") {
|
|
|
- return [{ start: "`", end: "`", format: "code" }];
|
|
|
- } else if (parentTag === "p") {
|
|
|
- return [{ start: "*", end: "*", format: "bold" }];
|
|
|
- } else if (parentTag === "span") {
|
|
|
- return [
|
|
|
- // ctx.text is the string from the start of the block to the cursor
|
|
|
- { start: "brb", replacement: ctx.text + ": Be Right Back" },
|
|
|
- ];
|
|
|
- } else {
|
|
|
- return [];
|
|
|
- }
|
|
|
+ paste_data_images: true, //是否打开黏贴图片功能
|
|
|
+ font_formats:
|
|
|
+ "Arial=arial,helvetica,sans-serif; 宋体=SimSun; 微软雅黑=Microsoft Yahei; Impact=impact,chicago;", //字体
|
|
|
+ fontsize_formats: "8pt 10pt 12pt 14pt 18pt 24pt 36pt", // 第二步
|
|
|
+ convert_fonts_to_spans: true,
|
|
|
+ font_size_style_values: "8pt,10pt,12pt,14pt,18pt,24pt,36pt",
|
|
|
+ images_upload_url: import.meta.env.VITE_APP_BASE_API,
|
|
|
+ // images_upload_base_path: "/demo",
|
|
|
+ images_upload_handler: function async(blobInfo, succFun, failFun) {
|
|
|
+ const file = blobInfo.blob();
|
|
|
+ proxy
|
|
|
+ .post("/fileInfo/getSing", { fileName: blobInfo.filename() })
|
|
|
+ .then((res) => {
|
|
|
+ const otherData = res.uploadBody;
|
|
|
+ const formData = new FormData();
|
|
|
+ for (const key in otherData) {
|
|
|
+ formData.append(key, otherData[key]);
|
|
|
+ }
|
|
|
+ formData.append("file", file);
|
|
|
+ proxy
|
|
|
+ .post("https://winfaster.obs.cn-south-1.myhuaweicloud.com", formData)
|
|
|
+ .then((data) => {
|
|
|
+ if (res && typeof res.fileUrl == "string" && res.fileUrl) {
|
|
|
+ succFun(res.fileUrl);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
},
|
|
|
});
|
|
|
|
|
|
-onMounted(() => {
|
|
|
- content.value = props.value;
|
|
|
+const changeHtml = (val) => {
|
|
|
+ content.value = val;
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {});
|
|
|
+
|
|
|
+defineExpose({
|
|
|
+ changeHtml,
|
|
|
});
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => content.value,
|
|
|
+ (val) => {
|
|
|
+ emit("updateValue", val);
|
|
|
+ }
|
|
|
+);
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|