首页 > 解决方案 > 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!

重现:

最后编辑器里没有内容,我要点击“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,
        )
    });
},

先感谢您

标签: javascriptvue.jsvuejs2tinymcevuetify.js

解决方案


在与大致相同的问题挣扎了几个小时之后,对我有用的是以下组合:

带有包含 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;
  }

丑陋,但有效。


推荐阅读