记录 nuxt3 配置百度编辑器 UEditor

388 阅读7分钟

下载百度编辑器

下面的链接是最新的版本,目前 UEditor 不再更新了。2024-02-07 19:31:49

编译百度编辑器

参考 blog.csdn.net/WU262940942…

NOTE: 因为下载的 ueditor 源码并没有 ueditor.all.js 文件,所以需要编译出来。

编译步骤如下:

  1. cd ueditor-dev-1.5.0
  2. pnpm install
  3. pnpm install -g grunt-cli
  4. grunt default
  5. mv dist/utf8-php UEditor 改个名字好认
  6. cp -R dist/utf8-php/ public nuxt3 中的 public 是静态文件根目录(只在开发环境中起作用)

配置 UEditor

百度编辑器设计为 从后端获取配置,这样的设计还是很不错的。 所以这样就会产生一个问题,即需要定制后端 api。

在该项目中,没有专门为百度编辑器 UEditor 定制后端,所以我就在前端把配置写死了。

UEditor 都有哪些配置项呢?去找个后端的实现看看吧。UEditor 的 github.com/fex-team/ue…] 上默认提供了几个后端实现,有 asp jsp net php 这4个版本。随便下载一个去看看吧。 我下载了 utf8-php 版本的发行。

打开文件 php/config.json,内容如下:

/* 前后端通信相关的配置,注释只允许使用多行方式 */
{
    /* 上传图片配置项 */
    "imageActionName": "uploadimage", /* 执行上传图片的action名称 */
    "imageFieldName": "upfile", /* 提交的图片表单名称 */
    "imageMaxSize": 2048000, /* 上传大小限制,单位B */
    "imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 上传图片格式显示 */
    "imageCompressEnable": true, /* 是否压缩图片,默认是true */
    "imageCompressBorder": 1600, /* 图片压缩最长边限制 */
    "imageInsertAlign": "none", /* 插入的图片浮动方式 */
    "imageUrlPrefix": "", /* 图片访问路径前缀 */
    "imagePathFormat": "/ueditor/php/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
                                /* {filename} 会替换成原文件名,配置这项需要注意中文乱码问题 */
                                /* {rand:6} 会替换成随机数,后面的数字是随机数的位数 */
                                /* {time} 会替换成时间戳 */
                                /* {yyyy} 会替换成四位年份 */
                                /* {yy} 会替换成两位年份 */
                                /* {mm} 会替换成两位月份 */
                                /* {dd} 会替换成两位日期 */
                                /* {hh} 会替换成两位小时 */
                                /* {ii} 会替换成两位分钟 */
                                /* {ss} 会替换成两位秒 */
                                /* 非法字符 \ : * ? " < > | */
                                /* 具请体看线上文档: fex.baidu.com/ueditor/#use-format_upload_filename */

    /* 涂鸦图片上传配置项 */
    "scrawlActionName": "uploadscrawl", /* 执行上传涂鸦的action名称 */
    "scrawlFieldName": "upfile", /* 提交的图片表单名称 */
    "scrawlPathFormat": "/ueditor/php/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
    "scrawlMaxSize": 2048000, /* 上传大小限制,单位B */
    "scrawlUrlPrefix": "", /* 图片访问路径前缀 */
    "scrawlInsertAlign": "none",

    /* 截图工具上传 */
    "snapscreenActionName": "uploadimage", /* 执行上传截图的action名称 */
    "snapscreenPathFormat": "/ueditor/php/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
    "snapscreenUrlPrefix": "", /* 图片访问路径前缀 */
    "snapscreenInsertAlign": "none", /* 插入的图片浮动方式 */

    /* 抓取远程图片配置 */
    "catcherLocalDomain": ["127.0.0.1", "localhost", "img.baidu.com"],
    "catcherActionName": "catchimage", /* 执行抓取远程图片的action名称 */
    "catcherFieldName": "source", /* 提交的图片列表表单名称 */
    "catcherPathFormat": "/ueditor/php/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
    "catcherUrlPrefix": "", /* 图片访问路径前缀 */
    "catcherMaxSize": 2048000, /* 上传大小限制,单位B */
    "catcherAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 抓取图片格式显示 */

    /* 上传视频配置 */
    "videoActionName": "uploadvideo", /* 执行上传视频的action名称 */
    "videoFieldName": "upfile", /* 提交的视频表单名称 */
    "videoPathFormat": "/ueditor/php/upload/video/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
    "videoUrlPrefix": "", /* 视频访问路径前缀 */
    "videoMaxSize": 102400000, /* 上传大小限制,单位B,默认100MB */
    "videoAllowFiles": [
        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid"], /* 上传视频格式显示 */

    /* 上传文件配置 */
    "fileActionName": "uploadfile", /* controller里,执行上传视频的action名称 */
    "fileFieldName": "upfile", /* 提交的文件表单名称 */
    "filePathFormat": "/ueditor/php/upload/file/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
    "fileUrlPrefix": "", /* 文件访问路径前缀 */
    "fileMaxSize": 51200000, /* 上传大小限制,单位B,默认50MB */
    "fileAllowFiles": [
        ".png", ".jpg", ".jpeg", ".gif", ".bmp",
        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
        ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
        ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
    ], /* 上传文件格式显示 */

    /* 列出指定目录下的图片 */
    "imageManagerActionName": "listimage", /* 执行图片管理的action名称 */
    "imageManagerListPath": "/ueditor/php/upload/image/", /* 指定要列出图片的目录 */
    "imageManagerListSize": 20, /* 每次列出文件数量 */
    "imageManagerUrlPrefix": "", /* 图片访问路径前缀 */
    "imageManagerInsertAlign": "none", /* 插入的图片浮动方式 */
    "imageManagerAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 列出的文件类型 */

    /* 列出指定目录下的文件 */
    "fileManagerActionName": "listfile", /* 执行文件管理的action名称 */
    "fileManagerListPath": "/ueditor/php/upload/file/", /* 指定要列出文件的目录 */
    "fileManagerUrlPrefix": "", /* 文件访问路径前缀 */
    "fileManagerListSize": 20, /* 每次列出文件数量 */
    "fileManagerAllowFiles": [
        ".png", ".jpg", ".jpeg", ".gif", ".bmp",
        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
        ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
        ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
    ] /* 列出的文件类型 */
}

在项目中我用到了图片、视频、文件上传,所以会用到下面的配置项。这些用到的配置项可以写在 ueditor.config.js 文件中:

window.UEDITOR_CONFIG = {
    ...
    "imageFieldName": "upfile",                        /* 提交的图片表单名称 */
    "imageUrlPrefix": "http://www.mydomain.com",       /* 图片访问路径前缀 */
    "videoFieldName": "upfile",                        /* 提交的视频表单名称 */
    "videoUrlPrefix": "http://www.mydomain.com",       /* 视频访问路径前缀 */
    ...
}

但是为了方便,也可以写在 vue 文件中,参后面封装的组件 UEditor.vue 内容。


在图片、视频、文件上传后,后端 api 返回的地址是最重要的。那么 UEditor 如何获取该地址呢?需要更改 3 个 js 文件了,分别是:

  1. public/UEditor/dialogs/image/image.js
uploader.on('uploadSuccess', function (file, ret) {
    var $file = $('#' + file.id);
    try {
        var responseText = (ret._raw || ret),
            json = utils.str2json(responseText);
        // if (json.state == 'SUCCESS') {
        if (json.code == 0 && json.data) {          // 后台返回的 json 格式
            json.url = json.data;
            _this.imageList.push(json);
            $file.append('<span class="success"></span>');
        } else {
            $file.find('.error').text(json.state).show();
        }
    } catch (e) {
        $file.find('.error').text(lang.errorServerUpload).show();
    }
});
  1. public/UEditor/dialogs/video/video.js
uploader.on('uploadSuccess', function (file, ret) {
    var $file = $('#' + file.id);
    try {
        var responseText = (ret._raw || ret),
            json = utils.str2json(responseText);
        // if (json.state == 'SUCCESS') {
        if (json.code == 0 && json.data) {
            uploadVideoList.push({
                // 'url': json.url,
                'url': json.data,
                // 'type': json.type,
                // 'original':json.original
            });
            $file.append('<span class="success"></span>');
        } else {
            $file.find('.error').text(json.state).show();
        }
    } catch (e) {
        $file.find('.error').text(lang.errorServerUpload).show();
    }
});
  1. public/UEditor/dialogs/attachment/attachment.js
uploader.on('uploadSuccess', function (file, ret) {
    var $file = $('#' + file.id);
    try {
        var responseText = (ret._raw || ret),
            json = utils.str2json(responseText);
        // if (json.state == 'SUCCESS') {
        if (json.code == 0 && json.data) {
            json.url = json.data
            _this.fileList.push(json);
            $file.append('<span class="success"></span>');
        } else {
            $file.find('.error').text(json.state).show();
        }
    } catch (e) {
        $file.find('.error').text(lang.errorServerUpload).show();
    }
});

安装 vue-ueditor-wrap

这是个第三方插件,目的是使 UEditor 在 vue3 中更好用。

# vue-ueditor-wrap v3 仅支持 Vue 3
npm i vue-ueditor-wrap@3.x
# 或者
yarn add vue-ueditor-wrap@3.x

写插件引入 vue-ueditor-wrap

写 nuxt3 插件: plugins/ueditor.client.ts

import VueUeditorWrap from 'vue-ueditor-wrap';

export default defineNuxtPlugin(nuxtApp => {
    nuxtApp.vueApp.use(VueUeditorWrap);
});

使用百度编辑器

再把 UEditor 封装成一个组件吧,参下面源码 Ueditor.vue

<script>
// 开发环境下读取 .env 中的变量
// 生产环境下读取系统变量
const config    = useRuntimeConfig()
const serverUrl = config.public.productServer
// 实际上是为了在开发环境下也能读取图片或者视频,才做的这样的设置。


// v-model 双向绑定
const props = defineProps({
    modelValue: {
        type: String,
        default: ""
    }
});
const emits = defineEmits<{
    (e: "update:modelValue", value: string): void
}>();

// 父组件传进来
watchEffect(() => {
    editorContent.value = props.modelValue;
});
// 传给父组件
watch(editorContent, (newValue) => {
    emits("update:modelValue", newValue)
});

// UEditor 配置
const editorContent = ref('<p>Hello World!</p>');
const editorConfig = {
    // 访问 UEditor 静态资源的根路径,可参考 https://hc199421.gitee.io/vue-ueditor-wrap/#/faq
    // 因为把 UEditor 目录放在了 /public 下,所以路径如下
    // 注意在服务器中需要配置 nginx 可访问路径才,可以访问 /UEditor/ 下的内容。
    UEDITOR_HOME_URL: '/UEditor/',

    // 上传图片和视频的 api
    // UEditor 也是从这个 api 中获取配置的,所以应该定制自己的上传 api,不过我没有定制
    serverUrl: serverUrl + '/api/v1/upload',

    // 配置图片上传
    imageFieldName: 'img',
    imageUrlPrefix: serverUrl,

    // 配置视频上传
    videoFieldName: 'img',
    videoUrlPrefix: serverUrl,
};
</script>
<template>
    <!-- 只在客户端使用百度编辑器 -->
    <ClientOnly>
        <div>
            <vue-ueditor-wrap
                v-model="editorContent"
                :config="editorConfig"
            />
        </div>
    </ClientOnly>
</template>

nginx 配置可访问路径(服务器端)

vim /etc/nginx/sites-available/swizerAdmin

    location /UEditor/ {
        root '/home/www.swzkj.com/swizer-admin/.output/public';
    }

我一开始写成了下面的样子,即多了 UEditor,无法访问到路径 /UEditor/,查了文心一言才知道写错了。

root '/home/www.swzkj.com/swizer-admin/.output/public/UEditor';

遇见问题

下面这个问题还没彻底知道原因,但是不使用 就可以了。

<div v-show="currentStep === 1">
    <!-- <el-form-item> -->
        <!-- WangEditor -->
        <!-- <TextEditor v-model="form.content" /> -->

        <!-- 百度编辑器 -->
        <UEditor v-model="form.content" />
    <!-- </el-form-item> -->
</div>

<el-form-item> 会导致 UEditor 在删除图像时编辑框宽度变窄。因为样式里有个 display: flex

在不知道什么情况下就生效了。按理说之前一直在起作用,估计是删除图像(或者在图像上按空格键)导致了什么样式有变化而导致的。等到看 UEditor 源码时,如有机缘再细究其原因吧。