mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-09-20 20:02:05 +08:00
feat(editor): 增强 TinyMCE 编辑器功能与内容同步
- 提交前同步 PC 与移动端编辑器内容 - 增加编辑器未初始化时的待写入内容处理 - 优化内容读写方法,保证数据绑定准确 - 重构事件处理,避免初始化时覆盖 v-model 值
This commit is contained in:
@@ -1452,6 +1452,22 @@ export default {
|
||||
|
||||
/** 查询商品参数 */
|
||||
this.GET_GoodsParams();
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$refs.editor?.setContent?.(this.baseInfoForm.intro);
|
||||
this.$refs.introEditor?.setContent?.(this.baseInfoForm.mobileIntro);
|
||||
});
|
||||
},
|
||||
/** TinyMCE 的 v-model 可能滞后,提交前从编辑器实例取最新 HTML */
|
||||
syncIntroFromEditors() {
|
||||
const pcEditor = this.$refs.editor;
|
||||
const mobileEditor = this.$refs.introEditor;
|
||||
if (pcEditor?.getContent) {
|
||||
this.baseInfoForm.intro = pcEditor.getContent() ?? "";
|
||||
}
|
||||
if (mobileEditor?.getContent) {
|
||||
this.baseInfoForm.mobileIntro = mobileEditor.getContent() ?? "";
|
||||
}
|
||||
},
|
||||
// 渲染sku数据
|
||||
renderGoodsDetailSku(skuList) {
|
||||
@@ -1522,8 +1538,8 @@ export default {
|
||||
},
|
||||
// 将pc商品描述同步给移动端
|
||||
promiseIntroEditor() {
|
||||
const pcContent = this.$refs.editor?.getContent?.() ?? this.baseInfoForm.intro ?? "";
|
||||
this.baseInfoForm.intro = pcContent;
|
||||
this.syncIntroFromEditors();
|
||||
const pcContent = this.baseInfoForm.intro ?? "";
|
||||
this.baseInfoForm.mobileIntro = pcContent;
|
||||
this.$nextTick(() => {
|
||||
this.$refs.introEditor?.setContent?.(pcContent);
|
||||
@@ -2360,6 +2376,7 @@ export default {
|
||||
if (!this.$route.query.copyId) {
|
||||
this.baseInfoForm.goodsId = this.goodsId;
|
||||
}
|
||||
this.syncIntroFromEditors();
|
||||
let submit = JSON.parse(JSON.stringify(this.baseInfoForm));
|
||||
if (
|
||||
submit.goodsGalleryFiles &&
|
||||
|
||||
@@ -36,6 +36,7 @@ export default {
|
||||
initEditor,
|
||||
hasChange: false, // 标记内容是否有更改
|
||||
hasInit: false, // 标记编辑器是否已初始化
|
||||
pendingContent: null, // 编辑器未就绪时暂存待回填内容
|
||||
tinymceId:
|
||||
"tinymce-" + +new Date() + ((Math.random() * 1000).toFixed(0) + ""), // 生成唯一的编辑器 ID
|
||||
fullscreen: false, // 标记编辑器是否处于全屏模式
|
||||
@@ -43,9 +44,6 @@ export default {
|
||||
content: "", // 编辑器内容
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
computed: {
|
||||
bindValue() {
|
||||
return this.modelValue ?? this.value ?? "";
|
||||
@@ -54,40 +52,55 @@ export default {
|
||||
watch: {
|
||||
bindValue: {
|
||||
handler(val) {
|
||||
if (!this.hasChange && this.hasInit) {
|
||||
const editor = window.tinymce.get(this.tinymceId);
|
||||
if (editor) {
|
||||
this.$nextTick(() => editor.setContent(val || ""));
|
||||
}
|
||||
if (!this.hasChange) {
|
||||
this.setContent(val || "");
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
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){
|
||||
arr.forEach(v => window.tinymce.get(this.tinymceId).insertContent(`<img src="${v}" >`))
|
||||
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) => {
|
||||
if (_this.bindValue) {
|
||||
_this.$nextTick(() => editor.setContent(_this.bindValue));
|
||||
}
|
||||
_this.hasInit = true;
|
||||
editor.on("NodeChange Change KeyUp SetContent", () => {
|
||||
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;
|
||||
const content = editor.getContent();
|
||||
_this.$emit("update:modelValue", content);
|
||||
_this.$emit("input", content);
|
||||
_this.emitContent(editor.getContent());
|
||||
});
|
||||
},
|
||||
setup(editor) {
|
||||
@@ -101,23 +114,38 @@ export default {
|
||||
height:this.height
|
||||
});
|
||||
},
|
||||
setContent(value) {
|
||||
const editor = window.tinymce.get(this.tinymceId);
|
||||
if (!editor) {
|
||||
return;
|
||||
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;
|
||||
editor.setContent(content);
|
||||
this.$emit("update:modelValue", content);
|
||||
this.$emit("input", content);
|
||||
if (!this.isEditorReady()) {
|
||||
this.pendingContent = content;
|
||||
return;
|
||||
}
|
||||
this.pendingContent = null;
|
||||
this.applyContent(this.getEditor(), content);
|
||||
this.emitContent(content);
|
||||
},
|
||||
getContent() {
|
||||
// 获取编辑器的内容
|
||||
return window.tinymce.get(this.tinymceId).getContent();
|
||||
const editor = this.getEditor();
|
||||
if (!editor || !editor.initialized) {
|
||||
return this.pendingContent ?? this.bindValue ?? "";
|
||||
}
|
||||
return editor.getContent();
|
||||
},
|
||||
destroyTinymce() {
|
||||
const tinymce = window.tinymce.get(this.tinymceId);
|
||||
const tinymce = this.getEditor();
|
||||
|
||||
if (tinymce) {
|
||||
// 销毁编辑器实例
|
||||
|
||||
Reference in New Issue
Block a user