本文主要介绍 vue2Editor 在 Nuxt 中的使用,以及报错解决方案(亲测有效)。
项目中要使用富文本编辑器,看了下一些流行的编辑器(UEditor、wangEditor、vue2Editor、quill…),最后选择了 vue2Editor,虽然功能不多,star 也不多,但是我喜欢它的超轻量(只有200+K),反正我们的需求也不需要那么多功能。
但上天往往爱考验我,Error 来了!!!
so,今天主要来攻克:
想直接看解决方案,不想看我废话的,请直接滚动到下面(第三章)!!!
刚开始,我是这样入坑的…
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
修改 plugins/vue2-editor.js
import Vue from "vue" import Vue2Editor from "vue2-editor" if (process.browser) { Vue.use(Vue2Editor) }
Double Kill
修改 plugins/vue2-editor.js
import Vue from "vue" import Vue2Editor from "vue2-editor" if (process.client) { Vue.use(Vue2Editor) }
Triple Kill
删除 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
修改 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')
也是无用
至此已经感受到了,其实就是在 SSR 阶段时加载了这个组件,导致报错。
因为 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,有想法的也可以试试。
最后附上 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']
]