记录一次nextjs添加富文本编辑器并使用图片上传功能

822 阅读3分钟

1、前端封装WangEditor富文本编辑器

  1. 参考官网文档 www.wangeditor.com/ , 然后 使用

    npm install @wangeditor/editor-for-react --save

进行安装,然后封装成自定义组件,把html和setHtml暴露给父组件

import "@wangeditor/editor/dist/css/style.css"; // 引入 css
import React, { useState, useEffect } from "react";
import { Editor, Toolbar } from "@wangeditor/editor-for-react";
import { IDomEditor, IEditorConfig, IToolbarConfig } from "@wangeditor/editor";

function MyEditor({ html, setHtml }: any) {
  // editor 实例
  const [editor, setEditor] = useState<IDomEditor | null>(null); // TS 语法

  // 工具栏配置
  const toolbarConfig: Partial<IToolbarConfig> = {}; // TS 语法

  // 编辑器配置
  const editorConfig: Partial<IEditorConfig> = {
    // TS 语法
    placeholder: "请输入内容...",
    MENU_CONF: {
      uploadImage: {
        server: "/api/common/wang_editor/upload",
        fieldName: "file",
      },
    },
  };

  // 及时销毁 editor ,重要!
  useEffect(() => {
    return () => {
      if (editor == null) return;
      editor.destroy();
      setEditor(null);
    };
  }, [editor]);

  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={(editor) => setHtml(editor.getHtml())}
          mode="default"
          style={{ height: "500px", overflowY: "hidden" }}
        />
      </div>
    </>
  );
}

export default MyEditor;

2. 父组件使用富文本编辑器组件,添加表单项

 <Form.Item label="详情" name="content">
    <MyEditor html={html} setHtml={setHtml} />
</Form.Item>

3. 修改一下网络请求,在表单提交后,也将html富文本内容用content字段也一并提交给后端

  onFinish={async (v) => {
    console.log(currentId);
    // 若有id则修改
    if (currentId) {
      const res = await fetch("/api/articles/" + currentId, {
        method: "PUT",
        body: JSON.stringify({ ...v, imageUrl, content: html }),
      });
    } else {
      // 若无则新增
      const res = await fetch("/api/articles", {
        body: JSON.stringify({ ...v, imageUrl, content: html }),
        method: "POST",
      });
    }
    setQuery({ ...query });
    setOpen(false);
    }}

2、添加富文本编辑器上传本地图片功能

  1. 参考官方文档,www.wangeditor.com/v5/menu-con… , 添加编辑器配置,将server字段改成自己的图片上传接口,fileName改成对应接收的字段

    // 编辑器配置 const editorConfig: Partial = { // TS 语法 placeholder: "请输入内容...", MENU_CONF: { uploadImage: { server: "/api/common/wang_editor/upload", fieldName: "file", }, }, };

  2. 准备后端接口,依旧是先保存图片到本地,然后根据官网配置,需要修改响应体格式,

    import { NextRequest, NextResponse } from "next/server"; import path from "path"; import fs from 'fs' import { randomUUID } from "crypto"; // 文件保存 const saveFile = async (blob: File) => { const dirName = /upload/${new Date().getFullYear()}-${new Date().getMonth() + 1} const uploadDir = path.join(process.cwd(), 'public' + dirName) // 上传路径 fs.mkdirSync(uploadDir,{recursive: true}) // 创建目录,有则创建 const fileName = randomUUID() + '.png' // 文件名 const arrayBuffer = await blob.arrayBuffer() fs.writeFileSync(uploadDir + '/' + fileName,new DataView(arrayBuffer)) // 将数据写入文件 return dirName + '/' + fileName }

    export const POST = async (req: NextRequest) => { const formData = await req.formData() // 获取formData的数据 const fileName = await saveFile(formData.get('file') as File) // 将文件数据存储 return NextResponse.json({ "errno": 0, // 注意:值是数字,不能是字符串 "data": { "url": fileName, // 图片 src ,必须 // "alt": "yyy", // 图片描述文字,非必须 // "href": "zzz" // 图片的链接,非必须 } } ) }

  3. 最后尝试在富文本编辑器中添加图片,然后查看接口,ok完成

3、最终富文本编辑器build时候会报错

  1. 因为富文本编辑器可能会用一些客户端功能函数,所以修改一下配置,不进行ssr渲染

  2. 这时要使用next的动态组件,然后关闭ssr

    import dynamic from "next/dynamic"; const MyEditor = dynamic(() => import("../../_components/MyEditor"), { ssr: false, });

  3. 然后再build,完成

4、pm2部署nextjs项目

  1. 我们希望项目可以一直在后台运行,而不是关闭命令行就结束了,所以这里使用pm2进行进程守护,首先使用命令 npm i -g pm2进行全局安装
  2. 然后使用 pm2 ls可以查看当前进程
  3. 我们在当前项目下使用命令, pm2 start npm --name 指定进程名字 -- start
  4. 这里使用