mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-09-22 12:52:03 +08:00
- 提交前同步 PC 与移动端编辑器内容 - 增加编辑器未初始化时的待写入内容处理 - 优化内容读写方法,保证数据绑定准确 - 重构事件处理,避免初始化时覆盖 v-model 值
172 lines
4.4 KiB
Vue
172 lines
4.4 KiB
Vue
<template>
|
||
<div>
|
||
<!-- 使用 fullscreen 类来控制是否全屏显示 -->
|
||
<div :class="{ fullscreen: fullscreen }" class="tinymce-container">
|
||
<!-- 使用 tinymce-textarea 类作为编辑器的文本区域 -->
|
||
<uploadImage @callback="insertImage" />
|
||
<textarea :id="tinymceId" class="tinymce-textarea" />
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<script>
|
||
import { initEditor } from "@/views/lili-components/editor/config";
|
||
|
||
import uploadImage from "@/views/lili-components/editor/upload-image.vue";
|
||
export default {
|
||
components:{uploadImage},
|
||
name: "Tinymce",
|
||
props: {
|
||
modelValue: {
|
||
type: String,
|
||
default: "",
|
||
},
|
||
value: {
|
||
type: String,
|
||
default: "",
|
||
},
|
||
height:{
|
||
type:String,
|
||
default:'500px'
|
||
}
|
||
},
|
||
emits: ["update:modelValue", "input"],
|
||
data() {
|
||
return {
|
||
// 引入编辑器的配置
|
||
initEditor,
|
||
hasChange: false, // 标记内容是否有更改
|
||
hasInit: false, // 标记编辑器是否已初始化
|
||
pendingContent: null, // 编辑器未就绪时暂存待回填内容
|
||
tinymceId:
|
||
"tinymce-" + +new Date() + ((Math.random() * 1000).toFixed(0) + ""), // 生成唯一的编辑器 ID
|
||
fullscreen: false, // 标记编辑器是否处于全屏模式
|
||
toolbar: [], // 工具栏配置
|
||
content: "", // 编辑器内容
|
||
};
|
||
},
|
||
computed: {
|
||
bindValue() {
|
||
return this.modelValue ?? this.value ?? "";
|
||
},
|
||
},
|
||
watch: {
|
||
bindValue: {
|
||
handler(val) {
|
||
if (!this.hasChange) {
|
||
this.setContent(val || "");
|
||
}
|
||
},
|
||
},
|
||
},
|
||
methods: {
|
||
emitContent(content) {
|
||
this.$emit("update:modelValue", content);
|
||
this.$emit("input", content);
|
||
},
|
||
getEditor() {
|
||
return window.tinymce?.get(this.tinymceId);
|
||
},
|
||
isEditorReady() {
|
||
const editor = this.getEditor();
|
||
return !!(editor && editor.initialized && editor.dom);
|
||
},
|
||
// 数据返回并给富文本框插入图片
|
||
insertImage(arr){
|
||
const editor = this.getEditor();
|
||
if (!editor || !this.isEditorReady()) {
|
||
return;
|
||
}
|
||
arr.forEach(v => editor.insertContent(`<img src="${v}" >`))
|
||
},
|
||
init() {
|
||
// 初始化编辑器
|
||
this.initTinymce();
|
||
},
|
||
initTinymce() {
|
||
if (this.getEditor()) {
|
||
return;
|
||
}
|
||
const _this = this;
|
||
window.tinymce.init({
|
||
selector: `#${this.tinymceId}`,
|
||
convert_urls: false,
|
||
init_instance_callback: (editor) => {
|
||
_this.hasInit = true;
|
||
const initial = _this.pendingContent ?? _this.bindValue;
|
||
_this.pendingContent = null;
|
||
if (initial) {
|
||
_this.applyContent(editor, initial);
|
||
}
|
||
// 不监听 NodeChange/SetContent:初始化或回填时会把空内容写回 v-model,覆盖已加载的商品描述
|
||
editor.on("input change undo redo KeyUp", () => {
|
||
_this.hasChange = true;
|
||
_this.emitContent(editor.getContent());
|
||
});
|
||
},
|
||
setup(editor) {
|
||
// 监听全屏状态变化
|
||
editor.on("FullscreenStateChanged", (e) => {
|
||
_this.fullscreen = e.state;
|
||
});
|
||
},
|
||
..._this.initEditor,
|
||
|
||
height:this.height
|
||
});
|
||
},
|
||
applyContent(editor, content) {
|
||
if (!editor || !editor.initialized || !editor.dom) {
|
||
return false;
|
||
}
|
||
try {
|
||
editor.setContent(content);
|
||
return true;
|
||
} catch (e) {
|
||
console.warn("tinymce setContent failed", e);
|
||
return false;
|
||
}
|
||
},
|
||
setContent(value) {
|
||
const content = value || "";
|
||
this.hasChange = false;
|
||
if (!this.isEditorReady()) {
|
||
this.pendingContent = content;
|
||
return;
|
||
}
|
||
this.pendingContent = null;
|
||
this.applyContent(this.getEditor(), content);
|
||
this.emitContent(content);
|
||
},
|
||
getContent() {
|
||
const editor = this.getEditor();
|
||
if (!editor || !editor.initialized) {
|
||
return this.pendingContent ?? this.bindValue ?? "";
|
||
}
|
||
return editor.getContent();
|
||
},
|
||
destroyTinymce() {
|
||
const tinymce = this.getEditor();
|
||
|
||
if (tinymce) {
|
||
// 销毁编辑器实例
|
||
tinymce.destroy();
|
||
}
|
||
},
|
||
},
|
||
mounted() {
|
||
this.init();
|
||
},
|
||
activated() {
|
||
if (window.tinymce) {
|
||
this.initTinymce();
|
||
}
|
||
},
|
||
deactivated() {
|
||
this.destroyTinymce();
|
||
},
|
||
unmounted() {
|
||
this.destroyTinymce();
|
||
},
|
||
};
|
||
</script>
|