wangEditor 编辑器引入demo

文档:https://www.wangeditor.com/

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>wangEditor with Custom Toolbar</title>
    <!-- 引入 wangEditor 的 CSS -->
    <link rel="stylesheet" href="https://unpkg.com/@wangeditor/editor/dist/css/style.css">
</head>
<body>

    <!-- 工具栏容器 -->
    <div id="toolbar-container"></div>
    <!-- 编辑器容器 -->
    <div id="editor-container" style="height: 600px;border: 1px solid;"></div>

    <!-- 引入 jQuery -->
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <!-- 引入 wangEditor -->
    <script src="https://unpkg.com/@wangeditor/editor/dist/index.js"></script>

    <script>
        // 防抖 开始
        let debounceTimer;
        const debounce = (callback, delay) => {
            return (...args) => {
                clearTimeout(debounceTimer);
                debounceTimer = setTimeout(() => callback(...args), delay);
            };
        };
        // 防抖 结束

        $(document).ready(function () {
            // 从 wangEditor 获取必要的模块
            const { createEditor, createToolbar,i18nChangeLanguage,i18nAddResources } = window.wangEditor;

            // 创建编辑器实例
            const editor = createEditor({
                selector: '#editor-container',  // 编辑器容器
                config: {
                    placeholder: '请输入内容...',
                    autoFocus: true, // 默认是否 focus ,默认为 true
                    readOnly: false, // 是否只读 默认为 false
                    scroll: false, // 配置编辑器是否支持滚动,默认为 true 。注意,此时不要固定 editor-container 的高度,设置一个 min-height 即可
                    maxLength: 10000,
                    onMaxLength: function (editor) {
                        // 当达到 maxlength 限制时,触发该回调函数
                        console.log('达到 maxlength 限制');
                    },
                    // 创建完成
                    onCreated : function (editor) {
                        // editor created
                        console.log('editor created');
                        console.log('默认支持高亮的代码语法', editor.getMenuConfig('codeSelectLang').codeLangs);

                        // 使用多语言
                        // 添加新语言,如日语 ja
                        // i18nAddResources('ja', {
                        // 支持的一些键值:https://github.com/wangeditor-team/wangEditor/issues/5361
                        //     // 标题
                        //     header: {
                        //         title: 'ヘッダー',
                        //         text: 'テキスト',
                        //     },
                        //     // ... 其他语言词汇,下文说明 ...
                        // })
                        // // 切换为日语 ja
                        // i18nChangeLanguage('ja')

                        // 切换语言 zh-CN 、 en
                        i18nChangeLanguage('zh-CN');
                    },
                    onDestroyed : function (editor) {
                        // editor onDestroyed
                        console.log('editor onDestroyed');
                    },
                    onFocus : function (editor) {
                        // editor onFocus
                        console.log('editor onFocus');
                    },
                    onBlur : function (editor) {
                        // editor onBlur
                        console.log('editor onBlur');
                    },
                    // 自定义粘贴
                    customPaste : function (editor,event) {
                        // event 是 ClipboardEvent 类型,可以拿到粘贴的数据
                        // 可参考 https://developer.mozilla.org/zh-CN/docs/Web/API/ClipboardEvent

                        // 获取粘贴的 html
                        const html = event.clipboardData.getData('text/html') ;
                        // 获取粘贴的纯文本
                        const text = event.clipboardData.getData('text/plain') ;
                        // 获取 rtf 数据(如从 word wsp 复制粘贴)
                        const rtf = event.clipboardData.getData('text/rtf') 

                        console.log(html,text,rtf)

                        // 阻止默认的粘贴行为
                        // event.preventDefault()
                        // return false

                        // 继续执行默认的粘贴行为
                        return true
                    },
                    onChange: debounce((editor) => {
                        const html = editor.getHtml();
                        console.log('300内容变化:', html,editor.children);
                    }, 300), // 300 毫秒防抖
                    // 自定义图片菜单项的行为
                    MENU_CONF: {
                        // 自定义链接菜单项的行为
                        link: {
                            isBlank: true, // 插入链接时默认打开新窗口
                            check: (text, link) => {
                                // 自定义链接校验逻辑
                                if (!/^https?:\/\//.test(link)) {
                                    alert('链接必须以 http:// 或 https:// 开头');
                                    return false; // 阻止插入链接
                                }
                                return true; // 允许插入
                            }
                        },
                        // // 字号
                        // fontSize:{
                        //     fontSizeList: [
                        //         // 元素支持两种形式
                        //         //   1. 字符串;
                        //         //   2. { name: 'xxx', value: 'xxx' }

                        //         '12px',
                        //         '16px',
                        //         { name: '24px', value: '24px' },
                        //         '40px',
                        //     ]
                        // },
                        // // 字体
                        // fontFamily:{
                        //     fontFamilyList: [
                        //         // 元素支持两种形式
                        //         //   1. 字符串;
                        //         //   2. { name: 'xxx', value: 'xxx' }

                        //         '黑体',
                        //         '楷体',
                        //         { name: '仿宋', value: '仿宋' },
                        //         'Arial',
                        //         'Tahoma',
                        //         'Verdana'
                        //     ]
                        // },
                        // // 行高
                        // lineHeight:{
                        //     lineHeightList: ['1', '1.5', '2', '2.5']
                        // },
                        // 表情
                        // emotion:{
                        //     emotions: '😀 😃 😄 😁 😆 😅 😂 🤣 😊 😇 🙂 🙃 😉'.split(' ') // 数组
                        // },
                        // 插入链接
                        insertLink:{
                            // 检查链接,也支持 async 函数
                            checkLink: (text, url)=> {
                                if (!url) {
                                    return ;
                                }
                                if (url.indexOf('http') !== 0) {
                                    return '链接必须以 http/https 开头'
                                }
                                return true;

                                // 返回值有三种选择:
                                // 1. 返回 true ,说明检查通过,编辑器将正常插入链接
                                // 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)
                                // 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息
                            },
                            // 解析链接
                            parseLinkUrl: (url)=> {
                                if (url.indexOf('http') !== 0) {
                                    return `http://${url}`
                                }
                                return url;
                            }
                        },
                        // 编辑链接
                        editLink:{
                            checkLink: (text, url)=> {
                                if (!url) {
                                    return ;
                                }
                                if (url.indexOf('http') !== 0) {
                                    return '链接必须以 http/https 开头'
                                }
                                return true;

                                // 返回值有三种选择:
                                // 1. 返回 true ,说明检查通过,编辑器将正常插入链接
                                // 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)
                                // 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息
                            },
                            parseLinkUrl: (url)=> {
                                if (url.indexOf('http') !== 0) {
                                    return `http://${url}`
                                }
                                return url;
                            }
                        },
                        // 插入图片
                        insertImage:{
                            // onInsertedImage 还用来 获取已删除的图片
                            // onInsertedImage(imageNode) 插入图片之后的回调
                            // onUpdatedImage 更新图片之后的回调
                            // checkImage(src, alt, url): boolean | undefined | string 校验图片链接
                            // parseImageSrc(src): string 转换图片链接
                            onInsertedImage(imageNode) {
                                if (imageNode == null) return
                                const { src, alt, url, href } = imageNode
                                console.log('inserted image', src, alt, url, href)
                            }
                        },
                        // 编辑图片,同insertImage
                        // editImage:{}

                        // 上传图片
                        uploadImage: {
                            // 服务端地址 必填,否则上传图片会报错。
                            // 服务端返回格式
                            // 上传成功
                            // {
                            //     "errno": 0, // 注意:值是数字,不能是字符串
                            //     "data": {
                            //         "url": "xxx", // 图片 src ,必须
                            //         "alt": "yyy", // 图片描述文字,非必须
                            //         "href": "zzz" // 图片的链接,非必须
                            //     }
                            // }
                            // 上传失败
                            // {
                            //     "errno": 1, // 只要不等于 0 就行
                            //     "message": "失败信息"
                            // }
                            server: '/upload-image', // 图片上传接口
                            // form-data fieldName ,默认值 'wangeditor-uploaded-image'
                            fieldName: 'image', // 上传文件字段名
                            // 单个文件的最大体积限制,默认为 2M
                            maxFileSize: 5 * 1024 * 1024, // 最大文件大小 (5MB)
                            // 最多可上传几个文件,默认为 100
                            maxNumberOfFiles: 10,
                            // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
                            allowedFileTypes: ['image/*'],
                            // allowedFileTypes: ['image/jpeg', 'image/png', 'image/gif'], // 允许的文件类型
                            // 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。
                            meta: {
                                token: 'xxx',
                                otherKey: 'yyy'
                            },
                            // 将 meta 拼接到 url 参数中,默认 false
                            metaWithUrl: false,
                            // 自定义增加 http  header
                            headers: {
                                Accept: 'text/x-json',
                                otherKey: 'xxx'
                            },
                            // 跨域是否传递 cookie ,默认为 false
                            withCredentials: true,
                            // 超时时间,默认为 10 秒
                            timeout: 5 * 1000, // 5 秒

                            // 小于该值就插入 base64 格式(而不上传),默认为 0
                            base64LimitSize:  10 * 1024, // 10kb

                            // https://www.wangeditor.com/v5/menu-config.html#回调函数
                            // 上传之前触发
                            onBeforeUpload(file) {    // JS 语法
                                // file 选中的文件,格式如 { key: file }
                                return file

                                // 可以 return
                                // 1. return file 或者 new 一个 file ,接下来将上传
                                // 2. return false ,不上传这个 file
                            },

                            // 上传进度的回调函数
                            onProgress(progress) {       // JS 语法
                                // progress 是 0-100 的数字
                                console.log('progress', progress)
                            },

                            // 单个文件上传成功之后
                            onSuccess(file, res) {          // JS 语法
                                console.log(`${file.name} 上传成功`, res)
                            },

                            // 单个文件上传失败
                            onFailed(file, res) {           // JS 语法
                                console.log(`${file.name} 上传失败`, res)
                            },

                            // 上传错误,或者触发 timeout 超时
                            onError(file, err, res) {               // JS 语法
                                console.log(`${file.name} 上传出错`, err, res)
                            },
                            // 如果你不想使用 wangEditor 自带的选择文件功能,例如你有自己的图床,或者图片选择器。
                            // 可以通过 customBrowseAndUpload 来自己实现选择图片、上传图片,并插入图片
                            // 自定义选择图片
                            // customBrowseAndUpload(insertFn) {
                            //     // 自己选择文件
                            //     // 自己上传文件,并得到图片 url alt href
                            //     // 最后插入图片
                            //     insertFn(url, alt, href)
                            // }
                        },
                        // 自定义视频菜单项的行为
                        // 配置同上传图片
                        uploadVideo: {
                            // 上传成功
                            // {
                            //     "errno": 0, // 注意:值是数字,不能是字符串
                            //     "data": {
                            //         "url": "xxx", // 视频 src ,必须
                            //         "poster": "xxx.png" // 视频封面图片 url ,可选
                            //     }
                            // }
                            // 上传失败
                            // {
                            //     "errno": 1, // 只要不等于 0 就行
                            //     "message": "失败信息"
                            // }
                            server: '/upload-video', // 视频上传接口
                            fieldName: 'video', // 上传文件字段名
                            maxFileSize: 10 * 1024 * 1024, // 最大文件大小 (10MB)
                            // 选择文件时的类型限制,默认为 ['video/*'] 。如不想限制,则设置为 []
                            allowedFileTypes: ['video/*'],
                            onSuccess: (file, res) => {
                                console.log('视频上传成功:', res);
                            },
                            onFailed: (file, res) => {
                                console.error('视频上传失败:', res);
                            }
                        },

                    },
                    // 可选:其他编辑器配置
                    // 注册自定义插件
                    plugins: []
                },
                mode: 'default',  // 模式 'default' 或 'simple'
            });

            // 自定义工具栏配置
            const toolbarConfig = {
                items: [
                    'headerSelect',  // 标题
                    'bold',  // 加粗
                    'italic',  // 斜体
                    'underline',  // 下划线
                    'strikeThrough',  // 删除线
                    'fontSize',  // 字体大小
                    'fontName',  // 字体
                    'color',  // 文字颜色
                    'bgColor',  // 背景颜色
                    'link',  // 插入链接
                    'justify',  // 对齐方式
                    'quote',  // 引用
                    'emoticon',  // 表情
                    'image',  // 插入图片
                    'video',  // 插入视频
                    'table',  // 插入表格
                    'code',  // 插入代码
                    'undo',  // 撤销
                    'redo',  // 重做
                    'lineHeight',  // 行高
                    'indent',  // 缩进
                    'outdent',  // 减少缩进
                    'todo',  // 任务列表
                    'list',  // 列表
                    'splitLine',  // 分割线
                    'fullScreen',  // 全屏
                ],
                // 工具栏其他配置
                // 用于排除不需要的工具栏项,通过键值指定不显示的菜单项
                excludeKeys: ['moreText', 'moreParagraph'], 
                // 允许自定义插入菜单项的位置,可以通过索引指定插入的位置
                // insertKeys: { 
                //     // 自定义插入的菜单项(高级)
                //     index: 1, 
                //     keys: ['bold', 'italic'] // 插入的位置及项
                // },
                // 允许添加自定义按钮或功能项到工具栏。例如,可以添加一个自定义按钮,通过 onClick 事件实现功能
                extraItems: [
                    { 
                        key: 'customButton', 
                        icon: '<span style="font-size: 16px;">🔍</span>', 
                        title: '自定义按钮', 
                        onClick: () => {
                            alert('自定义按钮被点击');
                        }
                    },
                    {
                        key: 'customSearch',
                        icon: '<span style="font-size: 16px;">🔍</span>', // 自定义图标
                        title: '自定义搜索',
                        onClick: () => {
                            const searchTerm = prompt('请输入搜索内容:');
                            if (searchTerm) {
                                window.open(`https://www.google.com/search?q=${encodeURIComponent(searchTerm)}`, '_blank');
                            }
                        }
                    },
                    {
                        key: 'insertDate',
                        icon: '<span style="font-size: 16px;">📅</span>',
                        title: '插入当前日期',
                        onClick: () => {
                            const dateStr = new Date().toLocaleDateString();
                            editor.insertText(dateStr);
                        }
                    }
                ]
                // 可选:其他工具栏配置
            };

            // 创建工具栏实例并与编辑器关联
            const toolbar = createToolbar({
                editor,  // 关联的编辑器实例
                selector: '#toolbar-container', // 工具栏容器
                config: toolbarConfig,  // 工具栏配置
                mode: 'default',  // 工具栏模式 'default' 或 'simple'
            });
        });

        // 获取编辑器内容
        function get_editor_content() {
            // https://www.wangeditor.com/v5/API.html#gethtml
            const html = editor.getHtml();
            const text = editor.getText();
        }
    </script>

</body>
</html>