vue 使用 wangEditor(wangEditor图片上传,wangEditor视频上传)

11 篇文章 0 订阅
5 篇文章 0 订阅

因为 wangEdit 内置图片上传功能,所以在创建实例的时候修改参数就行,视频上传就要修改到 wangeditor 的源码了

Demo地址:https://download.csdn.net/download/qq_25992675/12844260

如果因为特殊需求需要以 js 文件形式引入 wangEditor 的,而不是通过引入 node_modules 来引入的,只需要把 node_modules 中的 wangEditor 中的 release 中的 wangEditor.js 复制出来到 public 文件夹中,在 index.html中引入使用即可

引入代码;

    <script type="text/javascript" src="./wangEditor.js"></script>

调用代码:

var E = window.wangEditor;
...
...
// 在生命周期中初始化 editor 
this.editor = new E(this.$refs.toolbar, this.$refs.editor);

使用wangEditor

1、安装wangEditor

npm install wangeditor

2、创建组件,通过组件调用 wangEditor

edit是在index.html引入wangEdit的组件,importEdit是直接引入wangEdit的组件

  • edit 是在 index.html 引入 wangEditor 的组件
  • importEdit 是直接引入 wangEditor 的组件

3、编写 importEdit.vue 组件(以下暂时都以直接引入wangEditor为例)

视频上传片段代码需要按底下操作配置对应视频上传方法
如果不需要视频上传,删掉视频上传代码片段,直接跳至第7步即可
<template lang="html">
	<div class="editor">
	    <div ref="toolbar" class="toolbar"></div>
	    <div ref="editor" class="text"></div>
	</div>
</template>

<script>
import E from "wangeditor";
export default {
    name: "importEdit",
    data() {
        return {
            editor: null,
            info_: null,
        };
    },
    model: {
        prop: "value",
        event: "change",
    },
    props: {
        value: {
            type: String,
            default: "",
        },
        isClear: {
            type: Boolean,
            default: false,
        },
    },
    watch: {
        isClear(val) {
            // 触发清除文本域内容
            if (val) {
                this.editor.txt.clear();
                this.info_ = null;
            }
        },
        value: function (value) {
            if (value !== this.editor.txt.html()) {
                this.editor.txt.html(this.value);
            }
        },
        //value为编辑框输入的内容,这里我监听了一下值,当父组件调用得时候,如果给value赋值了,子组件将会显示父组件赋给的值
    },
    mounted() {
        this.seteditor();
        this.editor.txt.html(this.value);
    },
    methods: {
        seteditor() {
            // http://192.168.2.125:8080/admin/storage/create
            this.editor = new E(this.$refs.toolbar, this.$refs.editor);
            this.editor.customConfig.uploadImgShowBase64 = false; // base 64 存储图片
            this.editor.customConfig.uploadImgServer =
                "http://otp.cdinfotech.top/file/upload_images"; // 配置服务器端地址
            this.editor.customConfig.uploadImgHeaders = {}; // 自定义 header
            this.editor.customConfig.uploadFileName = "file"; // 后端接受上传文件的参数名
            this.editor.customConfig.uploadImgMaxSize = 2 * 1024 * 1024; // 将图片大小限制为 2M
            this.editor.customConfig.uploadImgMaxLength = 6; // 限制一次最多上传 3 张图片
            this.editor.customConfig.uploadImgTimeout = 3 * 60 * 1000; // 设置超时时间

            this.editor.customConfig.uploadImgHooks = {
                fail: (xhr, editor, result) => {
                    // 插入图片失败回调
                },
                success: (xhr, editor, result) => {
                    // 图片上传成功回调
                },
                timeout: (xhr, editor) => {
                    // 网络超时的回调
                },
                error: (xhr, editor) => {
                    // 图片上传错误的回调
                },
                customInsert: (insertImg, result, editor) => {
                    // 图片上传成功,插入图片的回调
                    //result为上传图片成功的时候返回的数据,这里我打印了一下发现后台返回的是data:[{url:"路径的形式"},...]
                    // console.log(result.data[0].url)
                    //insertImg()为插入图片的函数
                    //循环插入图片
                    // for (let i = 0; i < 1; i++) {
                    // console.log(result)
                    let url = "http://otp.cdinfotech.top" + result.url;
                    insertImg(url);
                    // }
                },
            };
            this.editor.customConfig.onchange = (html) => {
                this.info_ = html; // 绑定当前逐渐地值
                this.$emit("change", this.info_); // 将内容同步到父组件中
            };

            // 视频上传
            this.editor.customConfig.uploadVideoServer =
                "http://otp.cdinfotech.top/file/upload_images"; // 上传接口
            this.editor.customConfig.uploadVideoParams = {
                "Content-Type": "multipart/form-data; boundary=----WebKitFormBoundarycZm1pHksXeHS6t5r"
            }
            this.editor.customConfig.uploadVideoHooks = {
                // 上传完成处理方法
                customInsert: function (insertVideo, result) {
                    if (result.ret === 200) {
                        (result.data || "").split(",").forEach(function (link) {
                            link && insertVideo(link);
                        });
                    } else {
                        flavrShowByTime("上传失败", null, "danger");
                    }
                },
            };
            // 创建富文本编辑器
            this.editor.create();
        },
    },
};
</script>

<style lang="scss" scoped>
.editor {
    width: 100%;
    margin: 30px auto;
    position: relative;
    z-index: 0;

    .toolbar {
        border: 1px solid #ccc;
        min-height: 32px;
    }

    .text {
        overflow: auto;
        border: 1px solid #ccc;
        min-height: 500px;
        max-height: 500px;
    }
}
</style>

4、在 node_modules 中找到 wangeditor 里面的 release 里面的 wangEditor.js

搜索 function Video(editor) ,并找到 function Video(editor) 下面的原型 Video.prototype,
更改原型里面的 _createPanel 方法
 _createPanel: function _createPanel() {

      	var _this = this;
        var editor = this.editor;
        var uploadImg = editor.uploadImg;
        var config = editor.config;

        // 创建 id
        // 上传视频id
        var upTriggerVideoId = getRandom('up-trigger-video');
        var upFileVideoId = getRandom('up-file-video');

        // 插入视频id
        var textValId = getRandom('text-val');
        var btnId = getRandom('btn');

        // 创建 panel
        // 一个 panel 多个 tab
        var tabsConfig = [{
            title: '上传视频或pdf',
            tpl: '<div class="w-e-up-img-container"><div id="' + upTriggerVideoId + '" class="w-e-up-btn"><i class="w-e-icon-upload2"></i></div><div style="display:none;"><input id="' + upFileVideoId + '" type="file" multiple="multiple" accept="application/pdf,video/*"/></div></div>',
            events: [{
                // 触发选择图片
                selector: '#' + upTriggerVideoId,
                type: 'click',
                fn: function fn() {
                    var $file = $('#' + upFileVideoId);
                    var fileElem = $file[0];
                    if (fileElem) {
                        fileElem.click();
                    } else {
                        // 返回 true 可关闭 panel
                        return true;
                    }
                }
            }, {
                // 选择图片完毕
                selector: '#' + upFileVideoId,
                type: 'change',
                fn: function fn() {
                    var $file = $('#' + upFileVideoId);
                    var fileElem = $file[0];
                    if (!fileElem) {
                        // 返回 true 可关闭 panel
                        return true;
                    }

                    // 获取选中的 file 对象列表
                    var fileList = fileElem.files;
                    if (fileList.length) {
                        console.log(fileList);
                        uploadImg.uploadVideo(fileList);
                    }

                    // 返回 true 可关闭 panel
                    return true;
                }
            }]
        }, // first tab end
        {
            // 标题
            title: '插入视频',
            // 模板
            tpl: '<div><input id="' + textValId + '" type="text" class="block" placeholder="\u683C\u5F0F\u5982\uFF1A<iframe src=... ></iframe>"/><div class="w-e-button-container"><button id="' + btnId + '" class="right">\u63D2\u5165</button></div></div>',
            // 事件绑定
            events: [{
                selector: '#' + btnId,
                type: 'click',
                fn: function fn() {
                    var $text = $('#' + textValId);
                    var val = $text.val().trim();

                    if (val) _this._insert(val); // 插入视频

                    // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
                    return true;
                }
            }]
        } // second tab end
        ] // tabs end


        // 判断 tabs 的显示
        var tabsConfigResult = [];
        if (config.uploadVideoServer) {
            // 显示“上传视频”
            tabsConfigResult.push(tabsConfig[0]);
        }
        if (config.showLinkVideo) {
            // 显示“网络视频”
            tabsConfigResult.push(tabsConfig[1]);
        }

        // 创建 panel
        var panel = new Panel(this, {
            width: 350,
            // 一个 panel 多个 tab
            tabs: tabsConfigResult // tabs end
        }); // panel end

        // 显示 panel
        panel.show();

        // 记录属性
        this.panel = panel;
    },

5、找到上传图片的原型,搜索 UploadImg.prototype,在上传图片的方法后面插入上传视频的方法

在这里插入图片描述
上传视频代码

// 上传视频
        uploadVideo: function uploadVideo(files) {
            var _this3 = this;

            if (!files || !files.length) {
                return;
            }

            // ------------------------------ 获取配置信息 ------------------------------
            var editor = this.editor;
            var config = editor.config;
            var uploadVideoServer = config.uploadVideoServer;

            var maxSize = config.uploadVideoMaxSize;
            var maxSizeM = maxSize / 1024 / 1024;
            var maxLength = config.uploadVideoMaxLength || 10000;
            var uploadFileName = config.uploadFileName || '';
            var uploadVideoParams = config.uploadVideoParams || {};
            var uploadVideoParamsWithUrl = config.uploadVideoParamsWithUrl;
            var uploadVideoHeaders = config.uploadVideoHeaders || {};
            var hooks = config.uploadVideoHooks || {};
            var timeout = config.uploadVideoTimeout || 30 * 60 * 1000; // 30分钟
            var withCredentials = config.withCredentials;
            if (withCredentials == null) {
                withCredentials = false;
            }
            var customUploadVideo = config.customUploadVideo;

            if (!customUploadVideo) {
                // 没有 customUploadVideo 的情况下,需要如下两个配置才能继续进行图片上传
                if (!uploadVideoServer) {
                    return;
                }
            }

            // ------------------------------ 验证文件信息 ------------------------------
            var resultFiles = [];
            var errInfo = [];
            arrForEach(files, function (file) {
                var name = file.name;
                var size = file.size;

                // chrome 低版本 name === undefined
                if (!name || !size) {
                    return;
                }

                if (/\.(pdf|rm|rmvb|3gp|avi|mpeg|mpg|mkv|dat|asf|wmv|flv|mov|mp4|ogg|ogm)$/i.test(name) === false) {
                    // 后缀名不合法,不是视频
                    errInfo.push('\u3010' + name + '\u3011\u4E0D\u662F\u56FE\u7247');
                    return;
                }
                if (maxSize < size) {
                    // 上传视频过大
                    errInfo.push('\u3010' + name + '\u3011\u5927\u4E8E ' + maxSizeM + 'M');
                    return;
                }

                // 验证通过的加入结果列表
                resultFiles.push(file);
            });
            // 抛出验证信息
            if (errInfo.length) {
                this._alert('视频验证未通过: \n' + errInfo.join('\n'));
                return;
            }
            if (resultFiles.length > maxLength) {
                this._alert('一次最多上传' + maxLength + '个视频');
                return;
            }

            // ------------------------------ 自定义上传 ------------------------------
            if (customUploadVideo && typeof customUploadVideo === 'function') {
                customUploadVideo(resultFiles, this.insertLinkVideo.bind(this));

                // 阻止以下代码执行
                return;
            }

            // 添加图片数据
            var formdata = new FormData();
            arrForEach(resultFiles, function (file) {
                var name = uploadFileName || file.name;
                formdata.append(name, file);
            });

            // ------------------------------ 上传图片 ------------------------------
            if (uploadVideoServer && typeof uploadVideoServer === 'string') {
                // 添加参数
                var uploadVideoServerArr = uploadVideoServer.split('#');
                uploadVideoServer = uploadVideoServerArr[0];
                var uploadVideoServerHash = uploadVideoServerArr[1] || '';
                objForEach(uploadVideoParams, function (key, val) {
                    // 因使用者反应,自定义参数不能默认 encode ,由 v3.1.1 版本开始注释掉
                    // 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('上传视频发生错误', '\u4E0A\u4F20\u56FE\u7247\u53D1\u751F\u9519\u8BEF\uFF0C\u670D\u52A1\u5668\u8FD4\u56DE\u72B6\u6001\u662F ' + xhr.status);
                            return;
                        }

                        result = xhr.responseText;
                        if ((typeof result === 'undefined' ? 'undefined' : _typeof(result)) !== 'object') {
                            try {
                                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 || [];
                                data.forEach(function (link) {
                                    _this3.insertLinkVideo(link);
                                });
                            }

                            // 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);
            }
        },

根据链接插入视频代码

// 根据链接插入视频
        insertLinkVideo: function insertLinkVideo(link) {
            if (!link) return;

            var _this2 = this;

            var editor = this.editor;
            var config = editor.config;

            // 校验格式
            var linkVideoCheck = config.linkVideoCheck;
            var checkResult = void 0;
            if (linkVideoCheck && typeof linkVideoCheck === 'function') {
                checkResult = linkVideoCheck(link);
                if (typeof checkResult === 'string') {
                    // 校验失败,提示信息
                    alert(checkResult);
                    return;
                }
            }

            editor.cmd.do('insertHTML', '<iframe src="' + link + '" style="width:650px;height: 366px" frameborder="0"></iframe>');
        }

6、找到配置信息,搜索 var config = {

在配置信息内配置上传视频默认参数, 不配置的话也会有默认,在使用方法中都做了参数判断
为了规范代码,这里添加一下。
// 是否显示添加网络视频的 tab
showLinkVideo: true,

// 插入网络视频的回调
linkVideoCallback: function linkVideoCallback(url) {
    // console.log(url)  // url 即插入视频的地址
},

// 默认上传视频 max size: 512M
uploadVideoMaxSize: 512 * 1024 * 1024,

// 配置一次最多上传几个视频
uploadVideoMaxLength: 5,

// 上传视频的自定义参数
uploadVideoParams: {
    // token: 'abcdef12345'
},

// 上传视频的自定义header
uploadVideoHeaders: {
    // 'Accept': 'text/x-json'
},

// 自定义上传视频超时时间 30分钟
uploadVideoTimeout: 30 * 60 * 1000,

// 上传视频 hook 
uploadVideoHooks: {
    // customInsert: function (insertLinkVideo, result, editor) {
    //     console.log('customInsert')
    //     // 视频上传并返回结果,自定义插入视频的事件,而不是编辑器自动插入视频
    //     const data = result.data1 || []
    //     data.forEach(link => {
    //         insertLinkVideo(link)
    //     })
    // },
    before: function before(xhr, editor, files) {
        // 视频上传之前触发

        // 如果返回的结果是 {prevent: true, msg: 'xxxx'} 则表示用户放弃上传
        // return {
        //     prevent: true,
        //     msg: '放弃上传'
        // }
    },
    success: function success(xhr, editor, result) {
        // 视频上传并返回结果,视频插入成功之后触发
    },
    fail: function fail(xhr, editor, result) {
        // 视频上传并返回结果,但视频插入错误时触发
    },
    error: function error(xhr, editor) {
        // 视频上传出错时触发
    },
    timeout: function timeout(xhr, editor) {
        // 视频上传超时时触发
    }
}

7、在需要使用 wangEdit 的页面调用 组件即可

<template>
<div class="about">
    <editor v-model="detail" :isClear="isClear" @change="change"></editor>
</div>
</template>

<script>
import Editor from "../components/importEdit";
export default {
    name: "About",
    data() {
        return {
            isClear: false,
            detail: "",
        };
    },
    methods: {
        change(val) {
            console.log(val);
        },
    },
    components: {
        Editor,
    },
};
</script>

遇到的问题

顶部弹窗优化

因为 wangEditor 插图图片、表格、视频等的 弹窗是新增在内容区域的不是顶部菜单栏区域,如果富文本内容过长时插入图片还要滑动到顶部进行插入,所以在这里提供一个优化弹窗的方法

在 wangEditor.js 中 搜索

 var $textContainerElem = editor.$textContainerElem;

将这句代码替换成,并在当前代码块中使用到 $textContainerElem 的都替换成 $toolbarElem

var $toolbarElem = editor.$toolbarElem;

因为 wangEditor 的弹窗样式写在了内容中,所以要自己添加弹窗的样式,或则找到css源代码进行替换也行,将 .w-e-text-container .w-e-panel-container 替换成 .w-e-toolbar .w-e-panel-container

.w-e-toolbar .w-e-panel-container {
    position: absolute;
    top: 32px;
    left: 50%;
    border: 1px solid #ccc;
    border-top: 0;
    box-shadow: 1px 1px 2px #ccc;
    color: #333;
    z-index: 999999999999999;
    background-color: #fff;
    /* 为 emotion panel 定制的样式 */
    /* 上传图片的 panel 定制样式 */
}

.w-e-toolbar .w-e-panel-container .w-e-panel-close {
    position: absolute;
    right: 0;
    top: 0;
    padding: 5px;
    margin: 2px 5px 0 0;
    cursor: pointer;
    color: #999;
    background: #fff;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-close:hover {
    color: #333;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-title {
    list-style: none;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    font-size: 14px;
    margin: 2px 10px 0 10px;
    border-bottom: 1px solid #f1f1f1;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-title .w-e-item {
    padding: 3px 5px;
    color: #999;
    cursor: pointer;
    margin: 0 3px;
    position: relative;
    top: 1px;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-title .w-e-active {
    color: #333;
    border-bottom: 1px solid #333;
    cursor: default;
    font-weight: 700;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content {
    padding: 10px 15px 10px 15px;
    font-size: 16px;
    /* 输入框的样式 */
    /* 按钮的样式 */
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content input:focus,
.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content textarea:focus,
.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content button:focus {
    outline: none;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content textarea {
    width: 100%;
    border: 1px solid #ccc;
    padding: 5px;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content textarea:focus {
    border-color: #1e88e5;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content input[type=text] {
    border: none;
    border-bottom: 1px solid #ccc;
    font-size: 14px;
    height: 20px;
    color: #333;
    text-align: left;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content input[type=text].small {
    width: 30px;
    text-align: center;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content input[type=text].block {
    display: block;
    width: 100%;
    margin: 10px 0;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content input[type=text]:focus {
    border-bottom: 2px solid #1e88e5;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button {
    font-size: 14px;
    color: #1e88e5;
    border: none;
    padding: 5px 10px;
    background-color: #fff;
    cursor: pointer;
    border-radius: 3px;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.left {
    float: left;
    margin-right: 10px;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.right {
    float: right;
    margin-left: 10px;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.gray {
    color: #999;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.red {
    color: #c24f4a;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button:hover {
    background-color: #f1f1f1;
}

.w-e-toolbar .w-e-panel-container .w-e-panel-tab-content .w-e-button-container:after {
    content: "";
    display: table;
    clear: both;
}

.w-e-toolbar .w-e-panel-container .w-e-emoticon-container .w-e-item {
    cursor: pointer;
    font-size: 18px;
    padding: 0 3px;
    display: inline-block;
    *display: inline;
    *zoom: 1;
}

.w-e-toolbar .w-e-panel-container .w-e-up-img-container {
    text-align: center;
}

.w-e-toolbar .w-e-panel-container .w-e-up-img-container .w-e-up-btn {
    display: inline-block;
    *display: inline;
    *zoom: 1;
    color: #999;
    cursor: pointer;
    font-size: 60px;
    line-height: 1;
}

.w-e-toolbar .w-e-panel-container .w-e-up-img-container .w-e-up-btn:hover {
    color: #333;
}

在输入内容时光标会移动到内容尾端处理方法

如果使用富文本的时候用的是 v-model 的话会有光标闪动到内容尾端的情况
因为,editor 在接收到最新数据的时候会更新渲染视图,这个时候光标就会因为刷新移动到最尾部
所以解决办法是拿一个新字段来存储我们更改的最新内容,在预览和提交的时候使用新字段即可。这样既能保证更新的是最新内容,也能做到不去刷新视图

贴上 Demo

<template>
<div class="home">
    <button @click="submit">提交</button>
    <editor :value="detail" :isClear="isClear" @change="change"></editor>
</div>
</template>

<script>
import Editor from "../components/edit";
export default {
    name: "Home",
    data() {
        return {
            isClear: false,
            detail: "",
            newDetail: "",
        };
    },
    methods: {
        change(val) {
            this.newDetail = val;
        },
        submit() {
            console.log(this.newDetail);
        }
    },
    components: {
        Editor,
    },
};
</script>

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值