javascript - Vuejs & Vuetify - 在对话框中使用 Tinymce 作为组件需要重新加载
问题描述
我正在使用 tinymce 作为组件来创建和编辑文章
https://www.tiny.cloud/docs/integrations/vue/
我也在使用 vuetify 和组件v-dialog
,我的所有表单都在这个模式中
但是,每次我更改 tinymce 组件的实例时,我都必须通过更改key
属性来重新加载组件
我认为一个例子更相关
我在开发环境中有一个 Web 服务
https://service-dev.alexisgatuingt.fr/
id:test@stackoverflow.com
通过:p@ssw0rd!
重现:
- 转到“文章”部分
- 打开模态“Créer unarticles”(编辑器位于底部)
- 关闭对话框
- 并使用图标打开编辑模式
mdi-pencil
最后编辑器里没有内容,我要点击“Relancer l'éediteur”来加载内容
“投资组合”部分相同
你可以创建,编辑,删除任何你想要的,它是一个开发环境
这是我的代码(简化):
modal.vue (modal 的根组件)
<template>
<div :style="`z-index:${index} !important; display: inherit`">
<!-- scroll bar = 15px -->
<v-dialog v-model="dialog" persistent transition="dialog-top-transition" :hide-overlay="hideOverlay"
:max-width="maxWidth" overlay-color="primary">
<v-form v-model="formValidation" ref="form" lazy-validation enctype='multipart/form-data'
:retain-focus="false">
<slot name="content"></slot>
</v-form>
</v-dialog>
<div style="display: inherit" @click="dialog = true">
<slot></slot>
</div>
</div>
</template>
创建.vue
<template>
<modal title="Créer un article" description="Pour créer un article, renseigner les champs ci-dessous : "
v-on:submit="submit" ref="modal" show-cancel label="Enregistrer">
<slot></slot>
<template v-slot:content>
<v-btn @click="reload">Relancer l'éditeur</v-btn>
<v-col cols="12" @focusin.stop>
<editor id="create-article" :key="key" :api-key="apiKey" v-model="request.content"
:init="editorOptions"></editor>
</v-col>
</template>
</modal>
</template>
<script>
import {editorOptions, apiKey} from "&/plugins/editor";
import {generateRandomKey} from "@/utils";
export default {
name: "create",
data() {
return {
key: '',
apiKey,
editorOptions,
request: {
content: '',
},
}
},
methods: {
submit() {
},
reload() {
this.key = generateRandomKey();
},
}
}
</script>
编辑.vue
<template>
<modal title="Modifier l'article" description="Pour modifier cet article, renseigner les champs ci-dessous : "
v-on:submit="submit" ref="modal" show-cancel label="Enregistrer">
<slot></slot>
<template v-slot:content>
<v-btn @click="reload">Relancer l'éditeur</v-btn>
<v-col cols="12" @focusin.stop>
<editor :id="item.slug" :api-key="apiKey" :key="key" v-model="request.content"
:init="editorOptions"></editor>
</v-col>
</template>
</modal>
</template>
<script>
import {editorOptions, apiKey} from "&/plugins/editor";
import {generateRandomKey} from "@/utils";
export default {
name: "edit",
props: {
item: {
type: Object,
required: true,
}
},
data() {
return {
key: '',
apiKey,
editorOptions,
request: {
content: '',
},
}
},
mounted() {
this.request.content = this.$props.item.content ?? '';
},
methods: {
reload() {
this.key = generateRandomKey();
},
submit() {
},
}
}
</script>
<style scoped>
</style>
编辑器.js
import store from '&/store';
import {mixin} from '@/store/mixin';
import Crud from "&/api/crud";
const MediaController = new Crud('media');
let imagesList = [];
MediaController.list({
perPage: 999,
search: 'image',
page: 1,
}).then((r) => {
r.data.forEach(e => imagesList.push({
title: e?.oldName,
value: e?.url
}));
})
let method = mixin(store).methods;
const toolbar = ['searchreplace h1 h2 h3 h4 h5 h6 bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo', 'removeformat subscript superscript code codesample hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen'];
const plugins = ['advlist anchor autolink autosave code codesample directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textpattern visualblocks visualchars wordcount'];
const editorOptions = {
//selector: "textarea",
height: 500,
image_uploadtab: true,
menubar: true,
relative_urls: false,
remove_script_host: false,
convert_urls: true,
images_upload_credentials: true,
image_list: imagesList,
images_upload_handler: (blobInfo, success, failure, progress) => {
let form = new FormData();
form.append('file', blobInfo.blob(), blobInfo.filename());
form.append('type', "image/*");
form.append('old_name', blobInfo.filename());
MediaController.add(form).then((r) => {
success(r.data.url);
}).catch((e) => {
method.showError(e);
failure("Un problème est survenu");
})
},
plugins,
toolbar,
}
const apiKey = '#######################';
export {editorOptions, apiKey}
模态激活剂
<component is="edit"> // can be create
<v-btn color="primary">
Modifier
</v-btn>
</component>
更新 :
我也试过
mounted() {
this.$nextTick(() => {
this.$watch(
() => this.$refs.modal.dialog,
(v) => v ? this.reload() : null,
)
});
},
先感谢您
解决方案
在与大致相同的问题挣扎了几个小时之后,对我有用的是以下组合:
带有包含 TincyMCE 的对话框的外部组件,将 eager 设置为 True,并将 Retain-focus 设置为 False。
<v-dialog
v-if="someCondition"
v-model="openEditorModal"
max-width="600px"
scrollable
:retain-focus="false"
@click:outside="closeEditorModal"
@keydown="closeOnKeydown"
:eager="true"
/>
包装 TinyMCE 的组件有条件地使用 v-if 显示其内容:
<MceEditor
v-if="showMce"
:inline="true"
:content="someObject.text
@change="someObjectChange($event)"
></MceEditor>
延迟 TinyMCE 创建并在包装组件卸载时将其销毁:
public mounted() {
this.$nextTick(() => {
setTimeout(() => {
this.showMce = true;
}, 3000);
});
}
public beforeUnmount() {
this.showMce = false;
}
丑陋,但有效。
推荐阅读
- javascript - 将状态从 localstate 移动到 globalstate 后,所有按钮都会立即单击。如何解决?
- javascript - 是否有任何解决方案可以显示从弹出窗口到选择字段的选定记录
- javascript - 如何在 JavaScript 中访问 HTML INPUT?
- macos - 在 MacOS 中从 C 调用 BLAS
- python - 从字典运行 GPIO 命令
- sql-server - 自动转义传递给 sqlcmd 的参数值的特殊字符
- python - 访问第一个元素后无法通过循环中的 xpaths 访问其余元素-Webscraping Selenium Python
- visual-studio - 无法导航以查看根目录中的文件夹以在 Sitecore 9 中保存布局
- google-api-nodejs-client - Google 语音转文本 api 延迟问题
- docker - 运行时将值从 dockerfile 传递给 json 文件