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