zoukankan      html  css  js  c++  java
  • .net core vue+wangEditor (双向绑定) 上传图片和视频功能

    最终效果,是这样的,现在开始记录怎么做:

    开始 npm 安装 wangEditor

    安装好后,

    因为要用vue 双向绑定 ,所以 我就把wangwangEditor 做成了一个封装组件,先看一下目录 :

    我是把wangEditor写在了my-components这个项目下,新建一个 vue组件,代码如下:

    <template>
        <div id="wangeditor">
            <div ref="editorElem" style="text-align:left"></div>
        </div>
    </template>
    <script>
        import E from 'wangeditor'
        export default {
            name: 'editorElem',
            data() {
                return {
                    editor: null,
                    editorContent: ''
                }
            },
            props: ['catchData', 'content'],    // 接收父组件的方法
            watch: {
                content() {
                    this.editor.txt.html(this.content)
                }
            },
            mounted() {
                var imgUrl = "";
                this.editor = new E(this.$refs.editorElem)
    
                this.editor.customConfig.onchange = (html) => {
                    this.editorContent = html
                    this.catchData(this.editorContent)  // 把这个html通过catchData的方法传入父组件
                }
                this.editor.customConfig.uploadImgServer = '/api/Media/OnPostUpload'
                this.editor.customConfig.uploadVideoServer="/api/Media/OnPostUploadVideo" // 或 /node_modules/wangeditor/release/wangEditor.js 里直接写上传视频接口
                // 下面是最重要的的方法
                this.editor.customConfig.uploadImgHooks = {
                    before: function (xhr, editor, files) {
                        // 图片上传之前触发
                        // xhr 是 XMLHttpRequst 对象,editor 是编辑器对象,files 是选择的图片文件
    
                        // 如果返回的结果是 {prevent: true, msg: 'xxxx'} 则表示用户放弃上传
                        // return {
                        //     prevent: true,
                        //     msg: '放弃上传'
                        // }
                    },
                    success: function (xhr, editor, result) {
                        // 图片上传并返回结果,图片插入成功之后触发
                        // xhr 是 XMLHttpRequst 对象,editor 是编辑器对象,result 是服务器端返回的结果
                   
                        this.imgUrl = Object.values(result.data).toString()
                    },
                    fail: function (xhr, editor, result) {
                        debugger;
                        var res = xhr.data;
                        // 图片上传并返回结果,但图片插入错误时触发
                        // xhr 是 XMLHttpRequst 对象,editor 是编辑器对象,result 是服务器端返回的结果
                    },
                    error: function (xhr, editor) {
                        debugger;
                        // 图片上传出错时触发
                        // xhr 是 XMLHttpRequst 对象,editor 是编辑器对象
                    },
                    timeout: function (xhr, editor) {
                        // 图片上传超时时触发
                        // xhr 是 XMLHttpRequst 对象,editor 是编辑器对象
                    },
    
                    // 如果服务器端返回的不是 {errno:0, data: [...]} 这种格式,可使用该配置
                    // (但是,服务器端返回的必须是一个 JSON 格式字符串!!!否则会报错)
                    customInsert: function (insertImg, result, editor) {
                        // 图片上传并返回结果,自定义插入图片的事件(而不是编辑器自动插入图片!!!)
                        // insertImg 是插入图片的函数,editor 是编辑器对象,result 是服务器端返回的结果
    
                        // 举例:假如上传图片成功后,服务器端返回的是 {url:'....'} 这种格式,即可这样插入图片:
                        let url = Object.values(result.data)      // result.data就是服务器返回的图片名字和链接
                        JSON.stringify(url)    // 在这里转成JSON格式
                        insertImg(url)
                        // result 必须是一个 JSON 格式字符串!!!否则报错
                    },
                };
                this.editor.customConfig.debug = true;
                this.editor.create()     // 创建富文本实例
                if (!this.content) {
                    this.editor.txt.html('请编辑内容1')
                }
            }
        }
    </script>
    

      然后,再在主页面上,引用 ,和感觉和后端差不多

    <template>
    <editorElem :catchData="catchData" :content="channelForm.content"></editorElem> (:content 这里就是双向绑定)
    </template>

      import editorElem from "../../my-components/Editor.vue";

    export default {

      name: "editor",
       components: {
           editorElem
       }

    }

    接着,开始改wangEidotr的视频上传代码,原wangEidotr上传视频用的不怎么好,所以我就去网上找了大神的( https://blog.csdn.net/m0_37885651/article/details/83660206 )代码修改了一下,

    先找到wangEidotr.js 

    //
    /*
        menu - video
    */
    // 构造函数
    function Video(editor) {
        this.editor = editor;
        this.$elem = $('<div class="w-e-menu"><i class="w-e-icon-play"><i/></div>');
        this.type = 'panel';
     
        // 当前是否 active 状态
        this._active = false;
    }
     
    // 原型
    Video.prototype = {
     
        constructor: Video,
     
        onClick: function onClick() {
            this._createInsertPanel();
        },
     
        _createInsertPanel: function _createInsertPanel() {
            var editor = this.editor;
            var uploadVideo = editor.uploadVideo;
            var config = editor.config;
     
            // id
            var upTriggerId = getRandom('up-trigger');
            var upFileId = getRandom('up-file');
     
            // tabs 的配置
            var tabsConfig = [{
                title: '上传 video',
                tpl: '<div class="w-e-up-img-container">
                        ' +
                '<div id="' + upTriggerId + '" class="w-e-up-btn">
                            ' +
                '<i class="w-e-icon-upload2"></i>
                        </div>
                        ' +
                '<div style="display:none;">
                            <input id="' + upFileId + '" type="file" multiple="multiple" accept="audio/mp4, video/mp4"/>
                        ' +
                '</div>
                                </div>',
                events: [{
                    // 触发选择视频
                    selector: '#' + upTriggerId,
                    type: 'click',
                    fn: function fn() {
                        var $file = $('#' + upFileId);
                        var fileElem = $file[0];
                        if (fileElem) {
                            fileElem.click();
                        } else {
                            // 返回 true 可关闭 panel
                            return true;
                        }
                    }
                }, {
                    // 选择视频完毕
                    selector: '#' + upFileId,
                    type: 'change',
                    fn: function fn() {
                        var $file = $('#' + upFileId);
                        var fileElem = $file[0];
                        if (!fileElem) {
                            // 返回 true 可关闭 panel
                            return true;
                        }
     
                        // 获取选中的 file 对象列表
                        var fileList = fileElem.files;
                        if (fileList.length) {
                            uploadVideo.uploadVideo(fileList);
                        }
     
                        // 返回 true 可关闭 panel
                        return true;
                    }
                }]
            }
            ]; // tabs end
     
            // 判断 tabs 的显示
            var tabsConfigResult = [];
            tabsConfigResult.push(tabsConfig[0]);
     
            // 创建 panel 并显示
            var panel = new Panel(this, {
                 300,
                tabs: tabsConfigResult
            });
            panel.show();
     
            // 记录属性
            this.panel = panel;
        },
     
        // 试图改变 active 状态
        tryChangeActive: function tryChangeActive(e) {
            var editor = this.editor;
            var $elem = this.$elem;
            if (editor._selectedImg) {
                this._active = true;
                $elem.addClass('w-e-active');
            } else {
                this._active = false;
                $elem.removeClass('w-e-active');
            }
        }
    };
     
     
    /*
        所有菜单的汇总
    */
     
    // 存储菜单的构造函数
    var MenuConstructors = {};
     
    MenuConstructors.video = Video;
    // 构造函数
    function UploadVideo(editor) {
        this.editor = editor;
    }
    
    // 原型
    UploadVideo.prototype = {
        constructor: UploadVideo,
        // 根据 debug 弹出不同的信息
        _alert: function _alert(alertInfo, debugInfo) {
            var editor = this.editor;
            var debug = editor.config.debug;
            // var debug = true;
            var customAlert = editor.config.customAlert;
    
            if (debug) {
                throw new Error('wangEditor: ' + (debugInfo || alertInfo));
            } else {
                if (customAlert && typeof customAlert === 'function') {
                    customAlert(alertInfo);
                } else {
                    alert(alertInfo);
                }
            }
        },
        //插入视频的方法  需要单独定义
        insertLinkVideo:function(link){
            var _this3 = this;
    
            if (!link) {
                return;
            }
            var editor = this.editor;
            var config = editor.config;
    
            // 校验格式
            var linkVideoCheck = config.linkVideoCheck;
            var checkResult = void 0;
            if (linkVideoCheck && linkVideoCheck === 'function') {
                checkResult = linkVideoCheck(link);
                if (typeof checkResult === 'string') {
                    // 校验失败,提示信息
                    alert(checkResult);
                    return;
                }
            }
    
            editor.cmd.do('insertHTML', '<video src="' + link + '" style="50%;height: 50%;" controls autobuffer autoplay muted/>');
    
            // 验证视频 url 是否有效,无效的话给出提示
            var video = document.createElement('video');
            video.onload = function () {
                var callback = config.linkVideoCallback;
                if (callback && typeof callback === 'function') {
                    callback(link);
                }
    
                video = null;
            };
            video.onerror = function () {
                video = null;
                // 无法成功下载图片
                _this2._alert('插入视频错误', 'wangEditor: u63D2u5165u56FEu7247u51FAu9519uFF0Cu56FEu7247u94FEu63A5u662F "' + link + '"uFF0Cu4E0Bu8F7Du8BE5u94FEu63A5u5931u8D25');
                return;
            };
            video.onabort = function () {
                video = null;
            };
            video.src = link;
        },
        // 上传视频
        uploadVideo: function uploadVideo(files) {
            var _this3 = this;
    
            if (!files || !files.length) {
                return;
            }
    
            // ------------------------------ 获取配置信息 ------------------------------
            var editor = this.editor;
            var config = editor.config;
            var uploadVideoServer = "/video/uploadVideo";//上传地址
    
            var maxSize = 100 * 1024 * 1024;       //100M
            var maxSizeM = maxSize / 1000 / 1000;
            var maxLength = 1;
            var uploadFileName = "file";
            var uploadVideoParams = config.uploadVideoParams || {};
            var uploadVideoHeaders = {};
            var hooks =config.uploadImgHooks || {};
            var timeout = 5 * 60 * 1000;        //5 min
            var withCredentials = config.withCredentials;
            if (withCredentials == null) {
                withCredentials = false;
            }
    
            // ------------------------------ 验证文件信息 ------------------------------
            var resultFiles = [];
            var errInfo = [];
            arrForEach(files, function (file) {
                var name = file.name;
                var size = file.size;
    
                // chrome 低版本 name === undefined
                if (!name || !size) {
                    return;
                }
    
                if (/.(mp4)$/i.test(name) === false) {
                    // 后缀名不合法,不是视频
                    errInfo.push('u3010' + name + 'u3011u4e0du662fu89c6u9891');
                    return;
                }
                if (maxSize < size) {
                    // 上传视频过大
                    errInfo.push('u3010' + name + 'u3011u5927u4E8E ' + maxSizeM + 'M');
                    return;
                }
    
                // 验证通过的加入结果列表
                resultFiles.push(file);
            });
            // 抛出验证信息
            if (errInfo.length) {
                this._alert('视频验证未通过: 
    ' + errInfo.join('
    '));
                return;
            }
            if (resultFiles.length > maxLength) {
                this._alert('一次最多上传' + maxLength + '个视频');
                return;
            }
    
            // ------------------------------ 自定义上传 ------------------------------
            // 添加视频数据
            var formdata = new FormData();
            arrForEach(resultFiles, function (file) {
                var name = uploadFileName || file.name;
                formdata.append(name, file);
            });
    
            // ------------------------------ 上传视频 ------------------------------
            if (uploadVideoServer && typeof uploadVideoServer === 'string') {
                // 添加参数
                var uploadVideoServer = uploadVideoServer.split('#');
                uploadVideoServer = uploadVideoServer[0];
                var uploadVideoServerHash = uploadVideoServer[1] || '';
                objForEach(uploadVideoParams, function (key, val) {
                    val = encodeURIComponent(val);
    
                    // 第一,将参数拼接到 url 中
                    if (uploadVideoParamsWithUrl) {
                        if (uploadVideoServer.indexOf('?') > 0) {
                            uploadVideoServer += '&';
                        } else {
                            uploadVideoServer += '?';
                        }
                        uploadVideoServer = uploadVideoServer + key + '=' + val;
                    }
    
                    // 第二,将参数添加到 formdata 中
                    formdata.append(key, val);
                });
                if (uploadVideoServerHash) {
                    uploadVideoServer += '#' + uploadVideoServerHash;
                }
    
                // 定义 xhr
                var xhr = new XMLHttpRequest();
                xhr.open('POST', uploadVideoServer);
    
                // 设置超时
                xhr.timeout = timeout;
                xhr.ontimeout = function () {
                    // hook - timeout
                    if (hooks.timeout && typeof hooks.timeout === 'function') {
                        hooks.timeout(xhr, editor);
                    }
    
                    _this3._alert('上传视频超时');
                };
    
                // 监控 progress
                if (xhr.upload) {
                    xhr.upload.onprogress = function (e) {
                        var percent = void 0;
                        // 进度条
                        var progressBar = new Progress(editor);
                        if (e.lengthComputable) {
                            percent = e.loaded / e.total;
                            progressBar.show(percent);
                        }
                    };
                }
    
                // 返回数据
                xhr.onreadystatechange = function () {
                    var result = void 0;
                    if (xhr.readyState === 4) {
                        if (xhr.status < 200 || xhr.status >= 300) {
                            // hook - error
                            if (hooks.error && typeof hooks.error === 'function') {
                                hooks.error(xhr, editor);
                            }
    
                            // xhr 返回状态错误
                            _this3._alert('上传视频发生错误', 'u4E0Au4F20u56FEu7247u53D1u751Fu9519u8BEFuFF0Cu670Du52A1u5668u8FD4u56DEu72B6u6001u662F ' + xhr.status);
                            return;
                        }
                        
                        result = xhr.responseText;
                        if ((typeof result === 'undefined' ? 'undefined' : _typeof(result)) !== 'object') {
                            try {
                                console.log(result);
                                result = JSON.parse(result);
                            } catch (ex) {
                                // hook - fail
                                if (hooks.fail && typeof hooks.fail === 'function') {
                                    hooks.fail(xhr, editor, result);
                                }
                                _this3._alert('上传视频失败', '上传视频返回结果错误,返回结果是: ' + result);
                                return;
                            }
                        }
                        if (!hooks.customInsert && result.errno == '0') {
                            // hook - fail
                            if (hooks.fail && typeof hooks.fail === 'function') {
                                hooks.fail(xhr, editor, result);
                            }
    
                            // 数据错误
                            _this3._alert('上传视频失败', '上传视频返回结果错误,返回结果 errno=' + result.errno);
                        } else {
                            if (hooks.customInsert && typeof hooks.customInsert === 'function') {
                                hooks.customInsert(_this3.insertLinkVideo.bind(_this3), result, editor);
                            } else {
                                // 将视频插入编辑器
                                var data = result || [];
                                // data.forEach(function (link) {
                                //     console.log(link);
                                //
                                // });
                                _this3.insertLinkVideo(data.url);
                            }
    
                            // hook - success
                            if (hooks.success && typeof hooks.success === 'function') {
                                hooks.success(xhr, editor, result);
                            }
                        }
                    }
                };
    
                // hook - before
                if (hooks.before && typeof hooks.before === 'function') {
                    var beforeResult = hooks.before(xhr, editor, resultFiles);
                    if (beforeResult && (typeof beforeResult === 'undefined' ? 'undefined' : _typeof(beforeResult)) === 'object') {
                        if (beforeResult.prevent) {
                            // 如果返回的结果是 {prevent: true, msg: 'xxxx'} 则表示用户放弃上传
                            this._alert(beforeResult.msg);
                            return;
                        }
                    }
                }
    
                // 自定义 headers
                objForEach(uploadVideoHeaders, function (key, val) {
                    xhr.setRequestHeader(key, val);
                });
    
                // 跨域传 cookie
                xhr.withCredentials = withCredentials;
    
                // 发送请求
                xhr.send(formdata);
    
                // 注意,要 return 。不去操作接下来的 base64 显示方式
                return;
            }
        }
    };
    // 修改原型
    Editor.prototype = {
        constructor: Editor,
     
        // 添加视频上传
        _initUploadVideo: function _initUploadVideo() {
            this.uploadVideo = new UploadVideo(this);
        },
        // 创建编辑器
        create: function create() {
         
            // 添加 视频上传
            this._initUploadVideo();
        },
     
    };

    1,源码里找到Video 的构造函数 还有它的prototype,替换成第一部分。(有版本是一样的,可以不替换)
    2,找到UploadImg的构造函数,还有它的prototype,这是上传图片的,相应的 你在这后面 加上第二部分UploadVideo的构造和原型,这是专门写的上传视频的。
    3,在Editor原型上加个方法,_initUploadVideo , 然后在 创建编辑器 create 里面执行 this._initUploadVideo() ,加上就可以。

    下面是后端代码:

     #region 上传图片 OnPostUpload
            [HttpPost]
            public async Task<IActionResult> OnPostUpload([FromServices]IHostingEnvironment environment)
            {
                List<string> fileUrl = new List<string>();
                var files = Request.Form.Files;
                if (string.IsNullOrWhiteSpace(environment.WebRootPath))
                {
                    environment.WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
                }
    
                string webRootPath = environment.WebRootPath;
                string filePath = Path.Combine(webRootPath + "\upload\images");
                if (!Directory.Exists(filePath))
                {
                    Directory.CreateDirectory(filePath);
                }
    
                foreach (var formFile in files)
                {
                    if (formFile.Length > 0)
                    {
                        var ext = Path.GetExtension(formFile.FileName);
                        if (!pictureFormatArray.Contains(ext.Split('.')[1]))
                        {
                            return new JsonResult(TmpUrl.ErrorInfo("图片格式不正确!", null));
                        }
                        var fileName = Guid.NewGuid().ToString() + ext;
                        var path = Path.Combine(webRootPath + "\upload\images", fileName);
                        using (var stream = new FileStream(path, FileMode.CreateNew))
                        {
                            await formFile.CopyToAsync(stream);
                            fileUrl.Add($"/api/Media/ShowNoticeImg?filePath={fileName}");
                        }
                    }
                }
    
                return new JsonResult(TmpUrl.SuccessInfo("ok!", fileUrl));
            }
            #endregion
    
      #region 上传视频 OnPostUploadVideo
            [HttpPost]
            public async Task<IActionResult> OnPostUploadVideo([FromServices]IHostingEnvironment environment)
            {
                List<string> fileUrl = new List<string>();
                var files = Request.Form.Files;
                if (string.IsNullOrWhiteSpace(environment.WebRootPath))
                {
                    environment.WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
                }
    
                string webRootPath = environment.WebRootPath;
                string filePath = Path.Combine(webRootPath + "\upload\videos");
                if (!Directory.Exists(filePath))
                {
                    Directory.CreateDirectory(filePath);
                }
    
                foreach (var formFile in files)
                {
                    if (formFile.Length > 0)
                    {
                        var ext = Path.GetExtension(formFile.FileName);
                        if (!videoFormatArray.Contains(ext.Split('.')[1]))
                        {
                            return new JsonResult(TmpUrl.ErrorInfo("视频格式不正确!", null));
                        }
                        var fileName = Guid.NewGuid().ToString() + ext;
                        var path = Path.Combine(webRootPath + "\upload\videos", fileName);
                        using (var stream = new FileStream(path, FileMode.CreateNew))
                        {
                            await formFile.CopyToAsync(stream);
                            //fileUrl.Add($"/upload/videos/{fileName}");
                            fileUrl.Add("http://localhost:15429/upload/videos/8e11ae8e-8ecc-4b7c-afac-43601530493f.mp4");
                        }
                    }
                }
    
                return new JsonResult(TmpUrl.SuccessInfo("ok!", fileUrl));
            }
            #endregion
    
            #region 获取图片流  ShowNoticeImg
            public IActionResult ShowNoticeImg(string filePath)
            {
                var contentTypeStr = "image/jpeg";
                string webRootPath = Path.Combine(Directory.GetCurrentDirectory(), $"wwwroot\upload\images\{filePath}");
                using (var sw = new FileStream(webRootPath, FileMode.Open))
                {
                    var bytes = new byte[sw.Length];
                    sw.Read(bytes, 0, bytes.Length);
                    sw.Close();
                    return new FileContentResult(bytes, contentTypeStr);
                }
            }
            #endregion
  • 相关阅读:
    苹果手机 iframe 无法滚动bug
    网页实现文件下载的一些方法
    Document对象中的一些重要的属性和方法(笔记)
    window对象中的一些重要的属性和方法(笔记)
    JS中的继承
    利用XMLHttpRequest(XHR)对象实现与web服务器通信
    JS对象中的原型
    JS中this的指向
    JS中的作用域和闭包
    HTML5新增的本地存储功能(笔记)
  • 原文地址:https://www.cnblogs.com/wjwj/p/10871350.html
Copyright © 2011-2022 走看看