背景
实现一个博客主站的文章生成系统,使用ssr去生成自己的文章,达到seo的效果。
技术栈
- nextjs@14.2.x. [app-router]
- postgres@latest (本章不涉及)
- @wangeditor/editor@5.x @wangeditor/editor-for-react@1.x
使用
-
引入富文本编辑器
npm i -S @wangeditor/editor @wangeditor/editor-for-react
-
基本的组件引入 src/app/components/rich-text/index.tsx 需要开启
use client
可以试试不开,最后会贴上碰到的问题,以及解决方案
typescript
// 不加报错 useState only works in Client Components. Add the "use client" directive at the top of the file to use it
'use client'
import { IDomEditor, IEditorConfig, IToolbarConfig } from '@wangeditor/editor';
import { Editor, Toolbar } from '@wangeditor/editor-for-react';
import '@wangeditor/editor/dist/css/style.css';
import React, { useEffect, useState } from 'react';
import './index.scss';
export interface IRichTextProps {
/**
* 富文本内容
* @default ''
*/
defaultContent?: string;
/**
* 富文本提示文字
* @default '请输入内容'
*/
placeholder?: string;
/**
* 富文本内容变化回调
* @param html 富文本内容
*/
onChange?: (html: string) => void;
}
export default function RichText(props: IRichTextProps) {
const { defaultContent = '', placeholder = '请输入内容', onChange } = props;
// editor 实例
const [editor, setEditor] = useState<IDomEditor | null>(null);
// 编辑器内容
const [html, setHtml] = useState(defaultContent);
// 工具栏配置
const toolbarConfig: Partial<IToolbarConfig> = {};
// 编辑器配置
const editorConfig: Partial<IEditorConfig> = {
placeholder
};
// 及时销毁 editor ,重要!
useEffect(() => {
return () => {
if (editor === null) return;
editor.destroy();
setEditor(null);
};
}, [editor]);
const handleChange = (editor: IDomEditor) => {
const h = editor.getHtml();
setHtml(h);
onChange && onChange(h);
};
return (
<>
<div style={{ border: '1px solid #ccc', zIndex: 100 }}>
<Toolbar
editor={editor}
defaultConfig={toolbarConfig}
mode="default"
style={{ borderBottom: '1px solid #ccc' }}
/>
<Editor
defaultConfig={editorConfig}
value={html}
onCreated={setEditor}
onChange={handleChange}
mode="default"
/>
</div>
</>
);
}
- 页面中的使用 目录: src/app/rich/page.tsx
typescript
import dynamic from 'next/dynamic'
import { Metadata } from 'next';
// 关闭服务端渲染 否则报错 ReferenceError: Element is not defined
const RichText = dynamic(() => import("../components/rich-text"), {
ssr: false,
});
export const metadata: Metadata = {
title: '创建数据',
}
export default function CreateText() {
return (
<div className='a'>
<RichText />
</div>
);
}
- 以上基本上代码层面没问题了,问题会出现在第三方插件和nextjs集成的一些地方
问题
针对性的说一下wangeditor和nextjs一起使用出现的问题
TypeError: Cannot set property navigator of #<Object> which has only a getter
问题描述:nextjs内部对全局navigator对象通过重新定义api(defineProperty),该值被设置为不可更改,只能读;而wangeditor内部却在更改navigator这个值,导致报错提示 解决方案:找到node_modules中wangeditor/editor中dist的index.esm.js删除掉更改navigator的代码 ---- 后面会给出文件TypeError: t is not function
来自于@wangEditor/editor的报错 解决方案:找到对应报错的index.esm.js中的地方,处理一下代码即可 --- 后面会给出文件Cannot destructure property 'protocol' of 'window.location' as it is undefined.
问题描述:由问题1引发的问题,解决问题1即可⨯ ReferenceError: Element is not defined
问题描述:由于在服务端渲染@wangEditor插件导致,按照上面代码使用,就不会出现此问题
以上的统一解决方案
核心思路:替换更改后的index.esm.js作为构建的资源, 打开下方在线编辑器-进入获取js文件内容
标题在根目录下创建scripts文件夹,然后新建run.sh
markdown
`run.sh` *(这里博主以pnpm包管理器为例,如果你们是yarn和npm需要自己找到对应的依赖包做替换。)*
bash
cp scripts/index.esm.js node_modules/.pnpm/@wangeditor+editor@5.1.23/node_modules/@wangeditor/editor/dist/index.esm.js