Nuxt 报错 Document / Window not defined 亲测解决方案(vue2Editor富文本编辑器之类三方包)

本文主要介绍 vue2Editor 在 Nuxt 中的使用,以及报错解决方案(亲测有效)。

1、问题背景

项目中要使用富文本编辑器,看了下一些流行的编辑器(UEditor、wangEditor、vue2Editor、quill…),最后选择了 vue2Editor,虽然功能不多,star 也不多,但是我喜欢它的超轻量(只有200+K),反正我们的需求也不需要那么多功能。
但上天往往爱考验我,Error 来了!!!

so,今天主要来攻克:

  • 在 Nuxt 等 SSR 框架中,引入第三方包 (类似于 富文本编辑器: UEditor、wangEditor、vue2Editor、quill…) 的时候,报错 Document / Window is not defined,或者报错 render function or template not defined in component: anonymous
  • Nuxt 中使用 vue2Editor

2、入坑过程及解决历史(废话)

想直接看解决方案,不想看我废话的,请直接滚动到下面(第三章)!!!
刚开始,我是这样入坑的…

  • ROUND 1

plugins/vue2-editor.js

import Vue from "vue"
import Vue2Editor from "vue2-editor"

Vue.use(Vue2Editor)

nuxt.config.js

...
plugins: [
    ...
    { src: '~/plugins/vue2-editor.js', ssr: false },
    ...
  ],
...

index.vue


ERROR 来了!

First Blood

  • ROUND 2
    兵来 Google 挡!
    原来是 SSR 时 Node 环境下没有 Document 的原因。

修改 plugins/vue2-editor.js

import Vue from "vue"
import Vue2Editor from "vue2-editor"

if (process.browser) {
  Vue.use(Vue2Editor)
}

Double Kill

  • ROUND 3

修改 plugins/vue2-editor.js

import Vue from "vue"
import Vue2Editor from "vue2-editor"

if (process.client) {
  Vue.use(Vue2Editor)
}

Triple Kill

  • ROUND 4
    好,我不用全局!

删除 plugins/vue2-editor.js
注释 nuxt.config.js

...
plugins: [
    ...
    // { src: '~/plugins/vue2-editor.js', ssr: false },
    ...
  ],
...

index.vue


...
import { VueEditor } from 'vue2-editor'
...
components: {
  VueEditor
},

起初我以为好了,可后来刷新页面,还是会报错!

Quadruple Kill

  • ROUND 5
    好,我先不渲染!

修改 index.vue


...
import { VueEditor } from 'vue2-editor'
...
components: {
  VueEditor
},
data () {
  return {
    isClient: false
  }
},
mounted () {
  if (process.client) {
    this.isClient = true
  }
},

还是刷新报错

Penta Kill

后来甚至还用了
const VueEditor= () => import('vue2-editor')
也是无用

Aced

至此已经感受到了,其实就是在 SSR 阶段时加载了这个组件,导致报错。


3、问题解析及终极解决方案

因为 nuxt 默认首页服务端渲染,其他页面客户端渲染,而 Window / Document 对象只在客户端存在。

官方其实给出了解决方案:https://zh.nuxtjs.org/faq/window-document-undefined

Window 或 Document 对象未定义?
这是因为一些只兼容客户端的脚本被打包进了服务端的执行脚本中去。 对于只适合在客户端运行的脚本,需要通过使用 process.client 变量来判断导入。

举个例子, 在你的 .vue 文件中:

if (process.client) {
  require('external_library')
}

根据官方解决方案,应用到我这里:
index.vue


...
data () {
  return {
    customToolbar: defaultBar,
    isClient: false
  }
},
mounted () {
  if (process.client) {
    const { VueEditor } = require('vue2-editor')
    this.$options.components = { VueEditor }
    this.isClient = true
  }
},

另外,Vue 中也提供了 vm.$isServer 可以使用,判断当前 Vue 实例是否运行于服务器。https://cn.vuejs.org/v2/api/#vm-isServer,有想法的也可以试试。

Victory


最后附上 vue2Editor 自定义菜单参数


...
data () {
   return {
     customToolbar: defaultBar,
     isClient: false
   }
},
export const defaultBar =  [
  // 标题
  [{ 'header': [false, 1, 2, 3, 4, 5, 6] }],
  // 字体颜色、背景颜色 (dropdown with defaults from theme)
  [{ 'color': [] }, { 'background': [] }],
  // 加粗、斜体、下划线、作废
  ['bold', 'italic', 'underline', 'strike'],
  // 文本对齐方式
  [{ 'align': ['', 'center', 'right', 'justify'] }],
  // 引用
  ['blockquote'],
  // 列表、有序、多选列表
  [{ 'list': 'ordered' }, { 'list': 'bullet' }, { 'list': 'check' }],
  // 下标、上标 X2 (superscript/subscript)
  // [{ 'script': 'sub'}, { 'script': 'super' }],
  // 缩进
  // [{ 'indent': '-1' }, { 'indent': '+1' }],
  // 链接、图片、视频 ['link', 'image', 'video']
  ['link'],
  // 代码、代码块
  ['code', 'code-block'],
  // [{ 'direction': 'rtl' }],
  // [{'size': ['small', false, 'large', 'huge']}],
  // [{'font': []}],
  // 清除格式
  ['clean']
]

码字不易,觉得有帮助的小伙伴右上角点个赞鼓励下~

在这里插入图片描述

扫描上方二维码关注我的订阅号~

你可能感兴趣的:(vue)