Laravel中使用wangEditor

wangEditor 5

官網(wǎng):https://www.wangeditor.com
demo 示例:https://www.wangeditor.com/demo/
快速開(kāi)始:https://www.wangeditor.com/v5/getting-started.html
內(nèi)容處理:https://www.wangeditor.com/v5/content.html
上傳圖片:https://www.wangeditor.com/v5/menu-config.html#%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%87
上傳視頻:https://www.wangeditor.com/v5/menu-config.html#%E4%B8%8A%E4%BC%A0%E8%A7%86%E9%A2%91

1、 創(chuàng)建空白編輯器

引入 CSS 定義樣式
<link  rel="stylesheet">
<style>
  #editor—wrapper {
    border: 1px solid #ccc;
    z-index: 100; /* 按需定義 */
  }
  #toolbar-container { border-bottom: 1px solid #ccc; }
  #editor-container { height: 500px; }
</style>
定義 HTML 結(jié)構(gòu)
<div id="editor—wrapper">
    <div id="toolbar-container"><!-- 工具欄 --></div>
    <div id="editor-container"><!-- 編輯器 --></div>
</div>
引入 JS 創(chuàng)建編輯器
<script src="https://unpkg.com/@wangeditor/editor@latest/dist/index.js"></script>
<script>
const { createEditor, createToolbar } = window.wangEditor

const editorConfig = {
    placeholder: 'Type here...',
    onChange(editor) {
      const html = editor.getHtml()
      console.log('editor content', html)
      // 也可以同步到 <textarea>
    }
}

const editor = createEditor({
    selector: '#editor-container',
    html: '<p><br></p>',
    config: editorConfig,
    mode: 'default', // or 'simple'
})

const toolbarConfig = {}

const toolbar = createToolbar({
    editor,
    selector: '#toolbar-container',
    config: toolbarConfig,
    mode: 'default', // or 'simple'
})
</script>
  • mode: 'default' 默認(rèn)模式 - 集成了 wangEditor 所有功能
    default模式.png
  • mode: 'simple' 簡(jiǎn)潔模式 - 僅有部分常見(jiàn)功能,但更加簡(jiǎn)潔易用
    simple模式.png

2、 內(nèi)容處理

獲取 HTML 和 Text

使用 editor.getHtml() 獲取 HTML 內(nèi)容,可參考 demo。使用 editor.getText() 獲取純文本內(nèi)容。

推薦使用 HTML 格式存儲(chǔ)數(shù)據(jù)。

設(shè)置內(nèi)容

設(shè)置 HTML

【注意】這里的 HTML 內(nèi)容必須是 wangEditor 生成的(即 editor.getHtml() 返回的) HTML 格式,不可以自己隨意寫。HTML 格式非常靈活,wangEditor 無(wú)法兼容所有的 HTML 格式。

例如,wangEditor 可以識(shí)別 <strong>hello</strong> 為加粗,但無(wú)法識(shí)別 <span style="font-weight: bold;">hello</span> 等其他加粗方式。

創(chuàng)建時(shí)設(shè)置 HTML

const editor = createEditor({
  html: '<p>hello <strong>world</strong></p>', // 從 editor.getHtml() 獲取的 html 內(nèi)容
  // 其他屬性...
})

動(dòng)態(tài)設(shè)置 HTML

參考 demo

editor.setHtml('<p>hello <strong>world</strong></p>')

3、 工具欄配置

使用toolbar.getConfig().toolbarKeys獲取所有工具欄的配置信息

const toolbarConfig = {}

// 自定義工具欄
toolbarConfig.toolbarKeys = [
      'color',
      'bgColor',
      'clearStyle',
      'justifyLeft',
      'justifyRight',
      'justifyCenter',
      // 菜單組,包含多個(gè)菜單
     {
          key: 'group-image',
          title: '圖片',
          iconSvg: '<svg viewBox="0 0 1024 1024"><path d="M959.877 128l0.123 0.123v767.775l-0.123 0.122H64.102l-0.122-0.122V128.123l0.122-0.123h895.775zM960 64H64C28.795 64 0 92.795 0 128v768c0 35.205 28.795 64 64 64h896c35.205 0 64-28.795 64-64V128c0-35.205-28.795-64-64-64zM832 288.01c0 53.023-42.988 96.01-96.01 96.01s-96.01-42.987-96.01-96.01S682.967 192 735.99 192 832 234.988 832 288.01zM896 832H128V704l224.01-384 256 320h64l224.01-192z"></path></svg>',
           menuKeys: ["insertImage", "uploadImage"]
     },
     {
           key: 'group-video',
           title: '視頻',
           iconSvg: '<svg viewBox="0 0 1024 1024"><path d="M981.184 160.096C837.568 139.456 678.848 128 512 128S186.432 139.456 42.816 160.096C15.296 267.808 0 386.848 0 512s15.264 244.16 42.816 351.904C186.464 884.544 345.152 896 512 896s325.568-11.456 469.184-32.096C1008.704 756.192 1024 637.152 1024 512s-15.264-244.16-42.816-351.904zM384 704V320l320 192-320 192z"></path></svg>',
                menuKeys: ["insertVideo", "uploadVideo"]
     },
     'undo',
     'redo',
]
工具欄顯示.png

4、上傳圖片

上傳圖片的配置比較復(fù)雜,拆分為幾個(gè)部分來(lái)講解??蓞⒖歼@個(gè) demo。

editorConfig.MENU_CONF['uploadImage'] = {
    // 上傳圖片的配置
}
服務(wù)端地址

必填,否則上傳圖片會(huì)報(bào)錯(cuò)。

editorConfig.MENU_CONF['uploadImage'] = {
     server: '/api/upload',
}

【特別注意】服務(wù)端 response body 格式要求如下:
上傳成功的返回格式:

{
    "errno": 0, // 注意:值是數(shù)字,不能是字符串
    "data": {
        "url": "xxx", // 圖片 src ,必須
        "alt": "yyy", // 圖片描述文字,非必須
        "href": "zzz" // 圖片的鏈接,非必須
    }
}

上傳失敗的返回格式:

{
    "errno": 1, // 只要不等于 0 就行
    "message": "失敗信息"
}

如果你的服務(wù)端 response body 無(wú)法按照上述格式,可以使用下文的 customInsert

自定義功能

如果用于 Typescript ,則要定義插入函數(shù)的類型。

type InsertFnType = (url: string, alt: string, href: string) => void

自定義插入

如果你的服務(wù)端 response body 無(wú)法按照上文規(guī)定的格式,則無(wú)法插入圖片,提示失敗。
但你可以使用 customInsert 來(lái)自定義插入圖片。

editorConfig.MENU_CONF['uploadImage'] = {
    // 自定義插入圖片
    customInsert(res: any, insertFn: InsertFnType) {  // TS 語(yǔ)法
    // customInsert(res, insertFn) {                  // JS 語(yǔ)法
        // res 即服務(wù)端的返回結(jié)果

        // 從 res 中找到 url alt href ,然后插圖圖片
        insertFn(url, alt, href)
    },
}
基本配置
editorConfig.MENU_CONF['uploadImage'] = {
    // form-data fieldName ,默認(rèn)值 'wangeditor-uploaded-image'
    fieldName: 'your-custom-name',

    // 單個(gè)文件的最大體積限制,默認(rèn)為 2M
    maxFileSize: 1 * 1024 * 1024, // 1M

    // 最多可上傳幾個(gè)文件,默認(rèn)為 100
    maxNumberOfFiles: 10,

    // 選擇文件時(shí)的類型限制,默認(rèn)為 ['image/*'] 。如不想限制,則設(shè)置為 []
    allowedFileTypes: ['image/*'],

    // 自定義上傳參數(shù),例如傳遞驗(yàn)證的 token 等。參數(shù)會(huì)被添加到 formData 中,一起上傳到服務(wù)端。
    meta: {
        token: 'xxx',
        otherKey: 'yyy'
    },

    // 將 meta 拼接到 url 參數(shù)中,默認(rèn) false
    metaWithUrl: false,

    // 自定義增加 http  header
    headers: {
        Accept: 'text/x-json',
        otherKey: 'xxx'
    },

    // 跨域是否傳遞 cookie ,默認(rèn)為 false
    withCredentials: true,

    // 超時(shí)時(shí)間,默認(rèn)為 10 秒
    timeout: 5 * 1000, // 5 秒
}

回調(diào)函數(shù)
editorConfig.MENU_CONF['uploadImage'] = {
    // 上傳之前觸發(fā)
    onBeforeUpload(file: File) { // TS 語(yǔ)法
    // onBeforeUpload(file) {    // JS 語(yǔ)法
        // file 選中的文件,格式如 { key: file }
        return file

        // 可以 return
        // 1\. return file 或者 new 一個(gè) file ,接下來(lái)將上傳
        // 2\. return false ,不上傳這個(gè) file
    },

    // 上傳進(jìn)度的回調(diào)函數(shù)
    onProgress(progress: number) {  // TS 語(yǔ)法
    // onProgress(progress) {       // JS 語(yǔ)法
        // progress 是 0-100 的數(shù)字
        console.log('progress', progress)
    },

    // 單個(gè)文件上傳成功之后
    onSuccess(file: File, res: any) {  // TS 語(yǔ)法
    // onSuccess(file, res) {          // JS 語(yǔ)法
        console.log(`${file.name} 上傳成功`, res)
    },

    // 單個(gè)文件上傳失敗
    onFailed(file: File, res: any) {   // TS 語(yǔ)法
    // onFailed(file, res) {           // JS 語(yǔ)法
        console.log(`${file.name} 上傳失敗`, res)
    },

    // 上傳錯(cuò)誤,或者觸發(fā) timeout 超時(shí)
    onError(file: File, err: any, res: any) {  // TS 語(yǔ)法
    // onError(file, err, res) {               // JS 語(yǔ)法
        console.log(`${file.name} 上傳出錯(cuò)`, err, res)
    },
}

5、上傳視頻

上傳視頻的配置比較復(fù)雜,拆分為幾個(gè)部分來(lái)講解。可參考這個(gè) demo。

editorConfig.MENU_CONF['uploadVideo'] = {
    // 上傳視頻的配置
}

服務(wù)端地址

必填,否則上傳視頻會(huì)報(bào)錯(cuò)。

editorConfig.MENU_CONF['uploadVideo'] = {
     server: '/api/upload',
}

【特別注意】服務(wù)端 response body 格式要求如下:
上傳成功的返回格式:

{
    "errno": 0, // 注意:值是數(shù)字,不能是字符串
    "data": {
        "url": "xxx", // 視頻 src ,必須
        "poster": "xxx.png" // 視頻封面圖片 url ,可選
    }
}

// 注意:@wangeditor/editor 版本 >= 5.1.8 才支持 video poster

上傳失敗的返回格式:

{
    "errno": 1, // 只要不等于 0 就行
    "message": "失敗信息"
}

如果你的服務(wù)端 response body 無(wú)法按照上述格式,可以使用下文的 customInsert

基本配置
editorConfig.MENU_CONF['uploadVideo'] = {
    // form-data fieldName ,默認(rèn)值 'wangeditor-uploaded-video'
    fieldName: 'your-custom-name',

    // 單個(gè)文件的最大體積限制,默認(rèn)為 10M
    maxFileSize: 5 * 1024 * 1024, // 5M

    // 最多可上傳幾個(gè)文件,默認(rèn)為 5
    maxNumberOfFiles: 3,

    // 選擇文件時(shí)的類型限制,默認(rèn)為 ['video/*'] 。如不想限制,則設(shè)置為 []
    allowedFileTypes: ['video/*'],

    // 自定義上傳參數(shù),例如傳遞驗(yàn)證的 token 等。參數(shù)會(huì)被添加到 formData 中,一起上傳到服務(wù)端。
    meta: {
        token: 'xxx',
        otherKey: 'yyy'
    },

    // 將 meta 拼接到 url 參數(shù)中,默認(rèn) false
    metaWithUrl: false,

    // 自定義增加 http  header
    headers: {
        Accept: 'text/x-json',
        otherKey: 'xxx'
    },

    // 跨域是否傳遞 cookie ,默認(rèn)為 false
    withCredentials: true,

    // 超時(shí)時(shí)間,默認(rèn)為 30 秒
    timeout: 15 * 1000, // 15 秒

    // 視頻不支持 base64 格式插入
}

回調(diào)函數(shù)
editorConfig.MENU_CONF['uploadVideo'] = {
    // 上傳之前觸發(fā)
    onBeforeUpload(file: File) {   // TS 語(yǔ)法
    // onBeforeUpload(file) {      // JS 語(yǔ)法
        // file 選中的文件,格式如 { key: file }
        return file

        // 可以 return
        // 1\. return file 或者 new 一個(gè) file ,接下來(lái)將上傳
        // 2\. return false ,不上傳這個(gè) file
    },

    // 上傳進(jìn)度的回調(diào)函數(shù)
    onProgress(progress: number) {  // TS 語(yǔ)法
    // onProgress(progress) {       // JS 語(yǔ)法
        // progress 是 0-100 的數(shù)字
        console.log('progress', progress)
    },

    // 單個(gè)文件上傳成功之后
    onSuccess(file: File, res: any) {  // TS 語(yǔ)法
    // onSuccess(file, res) {          // JS 語(yǔ)法
        console.log(`${file.name} 上傳成功`, res)
    },

    // 單個(gè)文件上傳失敗
    onFailed(file: File, res: any) {  // TS 語(yǔ)法
    // onFailed(file, res) {          // JS 語(yǔ)法
        console.log(`${file.name} 上傳失敗`, res)
    },

    // 上傳錯(cuò)誤,或者觸發(fā) timeout 超時(shí)
    onError(file: File, err: any, res: any) {  // TS 語(yǔ)法
    // onError(file, err, res) {               // JS 語(yǔ)法
        console.log(`${file.name} 上傳出錯(cuò)`, err, res)
    },
}

自定義功能

如果用于 Typescript ,則要定義插入函數(shù)的類型。

type InsertFnType = (url: string, poster: string = '') => void

自定義插入

如果你的服務(wù)端 response body 無(wú)法按照上文規(guī)定的格式,則無(wú)法插入視頻,提示失敗。
但你可以使用 customInsert 來(lái)自定義插入視頻。

editorConfig.MENU_CONF['uploadVideo'] = {
    // 自定義插入視頻
    customInsert(res: any, insertFn: InsertFnType) {  // TS 語(yǔ)法
    // customInsert(res, insertFn) {                  // JS 語(yǔ)法
        // res 即服務(wù)端的返回結(jié)果

        // 從 res 中找到 url poster ,然后插入視頻
        insertFn(url, poster)
    },
}

示例代碼:

ajax-create.blade.php
<style>
    #editor—wrapper {
        border: 1px solid #ccc;
        z-index: 100; /* 按需定義 */
    }
    #toolbar-container { border-bottom: 1px solid #ccc; }
    #editor-container { height: 500px; }
</style>
<form action="{{route('order.note.ajax.create')}}" method="post">
    @csrf
    <input type="hidden" name="order_id" value="{{$orderId}}"/>
    <div class="mb-3">
        <textarea style="display:none;" class="form-control" name="content" rows="5"></textarea>
        <div id="editor—wrapper">
            <div id="toolbar-container"><!-- 工具欄 --></div>
            <div id="editor-container"><!-- 編輯器 --></div>
        </div>
        <div class="invalid-feedback"></div>
    </div>
    <button type="button" class="btn btn-primary" onclick="ajaxSubmitForm(this)">保存</button>
    <div class="js-ajax-msg"></div>
</form>

<script>

    $(document).ready(function(){
        // 自定義校驗(yàn)圖片
        function customCheckImageFn(src, alt, url) {
            if (!src) {
                return
            }
            if (src.indexOf('http') !== 0) {
                return '圖片網(wǎng)址必須以 http/https 開(kāi)頭'
            }
            return true

            // 返回值有三種選擇:
            // 1. 返回 true ,說(shuō)明檢查通過(guò),編輯器將正常插入圖片
            // 2. 返回一個(gè)字符串,說(shuō)明檢查未通過(guò),編輯器會(huì)阻止插入。會(huì) alert 出錯(cuò)誤信息(即返回的字符串)
            // 3. 返回 undefined(即沒(méi)有任何返回),說(shuō)明檢查未通過(guò),編輯器會(huì)阻止插入。但不會(huì)提示任何信息
        }

        // 轉(zhuǎn)換圖片鏈接
        function customParseImageSrc(src) {
            if (src.indexOf('http') !== 0) {
                return `http://${src}`
            }
            return src
        }

        const { createEditor, createToolbar } = window.wangEditor

        const editorConfig = {
            MENU_CONF: {},
            placeholder: 'Type here...',
            onChange(editor) {
                const html = editor.getHtml()
                console.log('editor content', html)

                // 同步到 <textarea>
                if('<p><br></p>' !== html){
                    $("textarea[name=content]").text(html)
                }
            }
        }

        // 配置上傳圖片
        editorConfig.MENU_CONF['uploadImage'] = {
            server: '{{ route("api.upload.file") }}',
            fieldName: 'image',
            // 單個(gè)文件的最大體積限制,默認(rèn)為 2M
            maxFileSize: 1 * 1024 * 1024, // 1M
            // 最多可上傳幾個(gè)文件,默認(rèn)為 100
            maxNumberOfFiles: 10,
            // 選擇文件時(shí)的類型限制,默認(rèn)為 ['image/*'] 。如不想限制,則設(shè)置為 []
            allowedFileTypes: ['image/*'],
            // 自定義上傳參數(shù),例如傳遞驗(yàn)證的 token 等。參數(shù)會(huì)被添加到 formData 中,一起上傳到服務(wù)端。
            meta: {
                _token: "{{ csrf_token() }}"
            },
            // 將 meta 拼接到 url 參數(shù)中,默認(rèn) false
            metaWithUrl: false,
            // 自定義增加 http  header
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            },
            // 跨域是否傳遞 cookie ,默認(rèn)為 false
            withCredentials: true,
            // 超時(shí)時(shí)間,默認(rèn)為 10 秒
            timeout: 5 * 1000, // 5 秒

            // 上傳之前觸發(fā)
            onBeforeUpload(file) {
                // file 選中的文件,格式如 { key: file }
                return file

                // 可以 return
                // 1. return file 或者 new 一個(gè) file ,接下來(lái)將上傳
                // 2. return false ,不上傳這個(gè) file
            },

            // 上傳進(jìn)度的回調(diào)函數(shù)
            onProgress(progress) {
                // progress 是 0-100 的數(shù)字
                console.log('progress', progress)
            },

            // 單個(gè)文件上傳成功之后
            onSuccess(file, res) {
                console.log(`${file.name} 上傳成功`, res)
            },

            // 單個(gè)文件上傳失敗
            onFailed(file, res) {
                console.log(`${file.name} 上傳失敗`, res)
            },

            // 上傳錯(cuò)誤,或者觸發(fā) timeout 超時(shí)
            onError(file, err, res) {
                // onError(file, err, res) {
                console.log(`${file.name} 上傳出錯(cuò)`, err, res)
            },
        }

        // 配置上傳視頻
        editorConfig.MENU_CONF['uploadVideo'] = {

            server: '{{ route("api.upload.file") }}',
            fieldName: 'video',

            // 單個(gè)文件的最大體積限制,默認(rèn)為 10M
            maxFileSize: 5 * 1024 * 1024, // 5M
            // 最多可上傳幾個(gè)文件,默認(rèn)為 5
            maxNumberOfFiles: 3,
            // 選擇文件時(shí)的類型限制,默認(rèn)為 ['video/*'] 。如不想限制,則設(shè)置為 []
            allowedFileTypes: ['video/*'],
            // 自定義上傳參數(shù),例如傳遞驗(yàn)證的 token 等。參數(shù)會(huì)被添加到 formData 中,一起上傳到服務(wù)端。
            meta: {
                _token: "{{ csrf_token() }}"
            },
            // 將 meta 拼接到 url 參數(shù)中,默認(rèn) false
            metaWithUrl: false,

            // 自定義增加 http  header
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            },

            // 跨域是否傳遞 cookie ,默認(rèn)為 false
            withCredentials: true,

            // 超時(shí)時(shí)間,默認(rèn)為 30 秒
            timeout: 15 * 1000, // 15 秒
            // 視頻不支持 base64 格式插入
            // 上傳之前觸發(fā)
            onBeforeUpload(file) {
                // file 選中的文件,格式如 { key: file }
                return file

                // 可以 return
                // 1. return file 或者 new 一個(gè) file ,接下來(lái)將上傳
                // 2. return false ,不上傳這個(gè) file
            },

            // 上傳進(jìn)度的回調(diào)函數(shù)
            onProgress(progress) {
                // progress 是 0-100 的數(shù)字
                console.log('progress', progress)
            },

            // 單個(gè)文件上傳成功之后
            onSuccess(file, res) {
                console.log(`${file.name} 上傳成功`, res)
            },

            // 單個(gè)文件上傳失敗
            onFailed(file, res) {
                console.log(`${file.name} 上傳失敗`, res)
            },

            // 上傳錯(cuò)誤,或者觸發(fā) timeout 超時(shí)
            onError(file, err, res) {
                console.log(`${file.name} 上傳出錯(cuò)`, err, res)
            },
        }

        // 插入圖片
        editorConfig.MENU_CONF['insertImage'] = {
            onInsertedImage(imageNode) {
                if (imageNode == null) return

                const { src, alt, url, href } = imageNode
                console.log('inserted image', src, alt, url, href)
            },
            checkImage: customCheckImageFn, // 也支持 async 函數(shù)
            parseImageSrc: customParseImageSrc, // 也支持 async 函數(shù)
        }
        // 編輯圖片
        editorConfig.MENU_CONF['editImage'] = {
            onUpdatedImage(imageNode) {
                if (imageNode == null) return

                const { src, alt, url } = imageNode
                console.log('updated image', src, alt, url)
            },
            checkImage: customCheckImageFn, // 也支持 async 函數(shù)
            parseImageSrc: customParseImageSrc, // 也支持 async 函數(shù)
        }


        // 自定義校驗(yàn)視頻
        function customCheckVideoFn(src){
            if (!src) {
                return
            }
            if (src.indexOf('http') !== 0) {
                return '視頻地址必須以 http/https 開(kāi)頭'
            }
            return true

            // 返回值有三種選擇:
            // 1. 返回 true ,說(shuō)明檢查通過(guò),編輯器將正常插入視頻
            // 2. 返回一個(gè)字符串,說(shuō)明檢查未通過(guò),編輯器會(huì)阻止插入。會(huì) alert 出錯(cuò)誤信息(即返回的字符串)
            // 3. 返回 undefined(即沒(méi)有任何返回),說(shuō)明檢查未通過(guò),編輯器會(huì)阻止插入。但不會(huì)提示任何信息
        }

        // 自定義轉(zhuǎn)換視頻
        function customParseVideoSrc(src) {
            if (src.includes('.bilibili.com')) {
                // 轉(zhuǎn)換 bilibili url 為 iframe (僅作為示例,不保證代碼正確和完整)
                const arr = location.pathname.split('/')
                const vid = arr[arr.length - 1]
                return `<iframe src="http://player.bilibili.com/player.html?bvid=${vid}" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe>`
            }
            return src
        }

        editorConfig.MENU_CONF['insertVideo'] = {
            onInsertedVideo(videoNode) {
                if (videoNode == null) return

                const { src } = videoNode
                console.log('inserted video', src)
            },
            checkVideo: customCheckVideoFn, // 也支持 async 函數(shù)
            parseVideoSrc: customParseVideoSrc, // 也支持 async 函數(shù)
        }


        const editor = createEditor({
            selector: '#editor-container',
            // html: '<p>hello <strong>world</strong></p>',
            config: editorConfig,
            mode: 'default', // or 'simple'
        })

        const toolbarConfig = {}

        // 自定義工具欄
        toolbarConfig.toolbarKeys = [
            'color',
            'bgColor',
            'clearStyle',
            'justifyLeft',
            'justifyRight',
            'justifyCenter',
            // 菜單組,包含多個(gè)菜單
            {
                key: 'group-image',
                title: '圖片',
                iconSvg: '<svg viewBox="0 0 1024 1024"><path d="M959.877 128l0.123 0.123v767.775l-0.123 0.122H64.102l-0.122-0.122V128.123l0.122-0.123h895.775zM960 64H64C28.795 64 0 92.795 0 128v768c0 35.205 28.795 64 64 64h896c35.205 0 64-28.795 64-64V128c0-35.205-28.795-64-64-64zM832 288.01c0 53.023-42.988 96.01-96.01 96.01s-96.01-42.987-96.01-96.01S682.967 192 735.99 192 832 234.988 832 288.01zM896 832H128V704l224.01-384 256 320h64l224.01-192z"></path></svg>',
                menuKeys: ["insertImage", "uploadImage"]
            },
            {
                key: 'group-video',
                title: '視頻',
                iconSvg: '<svg viewBox="0 0 1024 1024"><path d="M981.184 160.096C837.568 139.456 678.848 128 512 128S186.432 139.456 42.816 160.096C15.296 267.808 0 386.848 0 512s15.264 244.16 42.816 351.904C186.464 884.544 345.152 896 512 896s325.568-11.456 469.184-32.096C1008.704 756.192 1024 637.152 1024 512s-15.264-244.16-42.816-351.904zM384 704V320l320 192-320 192z"></path></svg>',
                menuKeys: ["insertVideo", "uploadVideo"]
            },
            'undo',
            'redo',
        ]

        const toolbar = createToolbar({
            editor,
            selector: '#toolbar-container',
            config: toolbarConfig,
            mode: 'default', // 'simple' or 'default'
        })

    });

</script>
UploadController.php
<?php

namespace App\Http\Controllers\WangEditor;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Storage;

class UploadController extends Controller
{

    public function handle(Request $request)
    {
        try{

            $resData = [
                'errno'=>0,
                'data'=>[]
            ];

            // 圖片上傳
            if($file = $request->file('image')) {

                // wangeditor/image/20220819/OZqFtvH6vAu52ZMFLeq3w5bfPgeHPhGyqYVUeQFr.png
                $imageFile = $file->store('wangeditor/image/'.date('Ymd'));
                $resData = [
                    'errno'=>0,
                    'data'=>
                        [
                            'url'=> Storage::url($imageFile), // 圖片 src ,必須
                            'alt'=> '', // 圖片描述文字,非必須
                            'href'=> '' // 圖片的鏈接,非必須
                        ]
                ];

            }

            // 視頻上傳
            if ($file = $request->file('video')){

                // wangeditor/video/20220819/GOVnjEqXH1aI7hhuAskf05QR8t62vKKXPKThYDfH.mp4
                $videoFile = $file->store('wangeditor/video/'.date('Ymd'));

                $resData = [
                    'errno'=>0,
                    'data'=>
                        [
                            'url'=> Storage::url($videoFile), // 視頻 src ,必須
                            'poster'=>'' // 視頻封面圖片 url ,可選
                        ]
                ];
            }

            return response()->json($resData);

        }catch(\Exception $e){

            return response()->json([
                'errno'=>1,
                'message'=> $e->getMessage()
            ]);
        }

    }

}

web.php
<?php

namespace App\Http\Controllers;
use Illuminate\Support\Facades\Route;


Route::middleware('auth.user')->group(function () {
    // wangeditor 圖片、視頻上傳
    Route::post('api-upload-file',[WangEditor\UploadController::class,'handle'])->name('api.upload.file');

});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容