如何在 Nuxt 中使用 TinyMCE?

How to use TinyMCE in Nuxt?

我想将此脚本添加到我的 Nuxt 代码中:

<script>
  tinymce.init({
    selector: "#mytextarea",
    plugins: "emoticons",
    toolbar: "emoticons",
    toolbar_location: "bottom",
    menubar: false
  });
</script>

我可以将它放入我的组件的模板主体中(这个脚本必须在 <body> 而不是 <head> 中) 像这样:

有趣的是它有效,但这里有两个问题:

  1. 长得丑
  2. 它不是动态的。例如,我无法将 selector 动态绑定到道具或数据 属性!它必须被硬编码。

所以我想知道是否有人知道如何将这些脚本正确地集成到我的 Nuxt 项目中?

  1. 我真的很怀疑这行得通。 Vue 总是忽略模板中的任何 <script> 标签并显示错误消息:

Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as <script>, as they will not be parsed.

  1. 没有理由将其放入模板中。它只是您可以作为组件生命周期的一部分执行的常规 JS 代码。下面是 非常 将 TinyMCE 集成到 Vue 应用程序中的简单组件包装器。

但是我不建议自己这样做而是使用official Vue wrapper (docs) - use v3 for Vue 2. Official integration handles all the edge cases like component activation/deactivation (when used together with <keep-alive>) and proper cleanup when the component is destroyed which is required in order to avoid nasty memory leaks

const ed = Vue.component("MyEditor", {
  props: ["id", "value"],
  template: `
    <div>
      <textarea :id="id" :value="value"></textarea>
    </div>
  `,
  mounted() {
    const me = this;
    window.tinymce.init({
      selector: "#" + this.id,
      plugins: "emoticons",
      toolbar: "emoticons",
      toolbar_location: "bottom",
      menubar: false,
      setup: function (editor) {
        editor.on("change input undo redo", function () {
          me.$emit('input', editor.getContent({format: 'text'}))
        });
      }
    });
  }
});

Demo

Nuxt

由于TinyMCE完全是JS渲染的,在服务器端渲染时执行它是没有意义的。事实上,上面的代码在服务器上根本不起作用,因为没有 window 变量。使用 Nuxt 的 <client-only> component 强制 Nuxt 只在客户端渲染编辑器...

更新:另一方面,在 SSR 期间根本不会调用 mounted 生命周期挂钩,因此即使没有 <client-only>

也可能会正常工作

如已接受的答案中所述,官方 vue 包是必经之路。即使是官方包,我把它拉到 Nuxt 后也有很多问题。

这是一组。通过我如何让它工作的步骤。以下是所有相关内容的版本:

    "tinymce": "^5.10.3",
    "@tinymce/tinymce-vue": "^3.2.8",
    "vue": "^2.6.11",
    "nuxt": "2.15.8",

tinymce-vue 包需要一个 tinymce 可用。您可以像上面那样通过 npm 安装它,或者使用 cloud-hosted 版本(参见 Prerequisites here)。

Nuxt-specific 问题

您需要确保组件包裹在 <client-only> 标记中以避免 SSR 错误。

此外,如果 self-hosting tinymce 包,您将只想在 client-side 上导入它。否则你会看到如下错误: [Vue warn]: Failed to resolve async component: ... Reason: ReferenceError: navigator is not defined

您可以通过在它们周围使用 requireif (process.client) { 来做到这一点。

例如:

if (process.client) {
  require('tinymce/tinymce')
  require('tinymce/themes/silver')
  require('tinymce/icons/default')
  require('tinymce/plugins/lists') // do this for any plugins you use on the editor
}

import Editor from '@tinymce/tinymce-vue'

此时编辑器应该正在您的页面上加载,但样式可能尚未加载。

您可以通过在其他 require 下方添加 require('tinymce/skins/ui/oxide/skin.min.css') 来解决此问题。

现在样式将得到修复,但 tinymce 主题仍会寻找其他 CSS 文件,例如 mobile,它自己的最小版本,并导致网络错误。

例如:

404 http://localhost:3000/_nuxt/skins/ui/oxide/content.min.css
404 http://localhost:3000/_nuxt/skins/ui/oxide/skin.min.css

内容: 您可以将该文件复制到具有相同路径的静态文件夹,或者使用 content_css setting(在 Vue 组件 init 选项中)覆盖它们。

适合皮肤: 由于您已经将其作为模块提供,因此在 Vue 组件 init 选项中设置 skin: false