前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue-html5-editor 编辑器的使用及一些问题解决

Vue-html5-editor 编辑器的使用及一些问题解决

作者头像
越陌度阡
发布2022-05-06 15:03:04
1.4K0
发布2022-05-06 15:03:04
举报

近期由于需要对公司运营系统进行优化和升级,而原有后台系统所使用的vue-quill-editor编辑器对粘贴进来的内容的行内样式全部进行了过滤,虽然这样可以防止XSS攻击,但是却完全无法满足业务需要,为此对编辑器进行了更换,采用Vue-html5-editor 这个编辑器。

这是一个基于Vue 2.0系列的编辑器(官方地址),还不错,但却存在一些问题,以下记录这些问题,并提供解决办法。

1. 复制网络图片时无法粘贴成功

主要原因是图片链接存在跨域问题。运营人员复制的内容都是基于微信环境的,微信对所有的图片链接地址加了crossorigin="anonymous",所以复制图片的时候无法正常显示出来。

解决的办法是在编辑器的更新事件触发时,对所有的img图片链接中的crossorigin="anonymous"替换为空,代码如下:

代码语言:javascript
复制
// 更新编辑器内容
updateData(){
    let obj = document.getElementsByClassName("content")[0];
    let html = obj.innerHTML;
    let filterHtml =  html.replace(/crossorigin="anonymous"/g,"");
    this.content  = filterHtml;
    // 编辑器封装后,将内容传出去
    this.$emit('contentChange',filterHtml);
},

2. 无法从已有的图库中选择图片

此编辑器插入图片的方式主要有两种,一是输入链接插入图片,二是选择本地的图片转成base64后插入图片。

很显然,没法使用公司已经有素材库的图片,为此需要对该编辑器的源码做一些修改, 主要修改如下:

(1). 将“上传”改为“选择”。修改文件 vue-html5-editor.js ,大约在310行的 template$3 变量中。

(2). 将以前触发上传的事件改为触发一个打开选择图片的模态框,以便选择图库中的图片。修改文件vue-html5-editor.js ,大约在343行的pick事件中。

代码语言:javascript
复制
pick: function pick() {

    // 取消触发上传图片的事件
    // this.$refs.file.click();
 
    // 自定义的触发图片选择模态框的事件
    this.$parent.$parent.openModal();

},

 以下是图片选择的模态框展示: 

(3). 由于从图库中选择图片获取的仅仅是一个图片的链接地址,最终也是要以图片的形式插入编辑器中的,而编辑器插入图片的功能本身是比较OK的,为了省事,决定借用编辑器的插入图片功能,所以定义了一个事件,用于接收选择的图片地址,然后将图片的链接地址赋给编辑器自带的插入图片的输入链接框中,然后点击“确定”就可以插入图片了。

 代码如下:

代码语言:javascript
复制
// 选择的图片地址
selectedImageUrl(url){
    let obj = this.$refs.editor.$children;
    // imageUrl为编辑器原有的变量
    obj[0].imageUrl = url;
},

3. 插入的图片没有做宽度限制

由于图库中有些图片的尺寸比较大,会超出编辑器的总宽度,导致排版比较难看,为此在插入新图片时,需要给图片加一个行内样式,即宽度为百分百。

设置图片宽度的代码如下:

代码语言:javascript
复制
// 设置图片宽度
setImageWidth(){
    this.$nextTick(()=>{
        let list = document.querySelectorAll(".vue-html5-editor .content img");
        if(list.length){
            for(let i=0;i<list.length;i++){
                let img = list[i];
                img.style.width = "100%";
            }
        };
    });
}

 同时在编辑器插入图片的事件中调用上面这个方法,修改文件vue-html5-editor.js ,大约在 333 行的 insertImageUrl 事件中,代码如下:

代码语言:javascript
复制
insertImageUrl: function insertImageUrl() {
    if (!this.imageUrl) {
        return
    }
    this.$parent.execCommand(Command.INSERT_IMAGE, this.imageUrl);
    
    // 对新插入的图片设置图片最大宽度
    this.$parent.$parent.setImageWidth();

    this.imageUrl = null;
},

4. 给图片加超链接

由于在富文本里是有很多图片是要加超链接的,这个编辑器提供的加超链接是真心不好用,需要用鼠标选中文本或是图片才能加超链接,运营人员反映相当麻烦,而且加了链接也看不到是否加成功了的标识。

实现思路如下:

1. 在编辑器的内容更新时,给富文本中所有的图片加上一个data-index,并同时加上点击事件。当点击当前图片时,获取当前图片的HTML、自定义的data-index,同时获取当前图片的父元素,如果当前图片的父元素是已经加了链接的A标签,则获取A标签的链接地址以方便修改。代码如下:

代码语言:javascript
复制
// 给图片添加事件
addImgEvent(){
    let imgs = document.querySelectorAll(".vue-html5-editor img");
    for(let i=0;i<imgs.length;i++){
        let img = imgs[i];
        img.style.cursor="pointer";
        img.setAttribute("data-index",i);
        img.onclick = (e)=>{
            // 显示加链接的对话框
            this.showImgLinkModal = true;
            // 区取当前图片的HTML
            this.imgTarget = e.target.outerHTML;
            // 获取当前图片自定义的index
            this.imgIndex = e.target.getAttribute("data-index");
            // 获取当前元素的父元素
            let parent = e.target.parentElement;
            // 如果图片的父元素是已经加了链接的A标签
            if(parent.tagName=='A'){
                // 获取A标签的链接地址,方便修改链接地址
                this.imgLink = parent.getAttribute("href");
            }
        }
    }
},

2. 确认添加图片链接时,根据当前图片是否已经添加了链接来做不同的处理。如果没有加链接就加上;如果已经加了链接,就更新链接地址。代码如下:

代码语言:javascript
复制
// HTML转换为DOM结点
parseElement(htmlString){
    return new DOMParser().parseFromString(htmlString,'text/html').body.childNodes[0];
},


// 确认添加图片链接
confirmAddLink(){
    // 加了链接的标识符
    let span = '<span id="linkMark" style="width: 26px;height: 26px;display: block;position: absolute;top: 5px;right: 5px;background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAAA0CAYAAADFeBvrAAAAAXNSR0IArs4c6QAACJVJREFUaAWtWV1o1lUY3/u+m25zalF+MSoVKr3IacUCIWUXE0xMu+nCrNCyCy/CRThJughDUoq6yJCUukhYFJihSzJkNCpNUlsEjaAMQmyOCJmbcx/v2/M7+//Onv+zc+T98MDZ8/08v+ecs//7f8+bqbp9I1NhqkKF8S68UhDFxFufYoAX4xPs3xYLOgWUsTirtzJTWcBWjvlRH6WxgrGAkL/WkSdlHsoWOGVS+Gue8SEdbSnKQillQAj5Uaep5pGGsk1JgJpqHv6UdWxIp+3RgtrJgqIMavmQTuciD2AER54UPpZnHG1aTvEElFIqwdopEzhpVmIcf+7cuUVLlixZO3369KZsNjsfM5PJzEfOQqHwTz6fd/PmzZs9vb29J5ubmy/BlMy84qkTlW8ePAZsJQ+CJQXonMxqmTUyp8mslVnX2dl538DAwJ7x8fHzAnqwlIkYxCIHciU5kRs1UAs1/YIJTzzCFj8YRGqbmS6p6vbu3Tvn2rVrbwiofln5wUomciAXciK3TNQouSkAtsPq2BQoVyp75cqV9XPnzt0vxwkAbtuQ3e2/evXqzgULFhyXpDyCpPoYsmbq+FnwcNI62wwayspKts+cOfNVZgQVIFosmZeFScXIMXx79uzZ+0SJZjjZkC6mebfiOpHOOqWZtra2+hs3bnykm0EjsWZos1QXJE8fyqiBWqgpOreQQjUmumrMqd2AA42k/oiJLYcC8vRaD0fdhOZhK3foXSIvT8PjdXV1WyXnuEwePVAM7g5paofYxITr5Gr4Y2ab0atKvlzq0Knd5iKhJo642O0uESeox+4ZpYSOE0lyeADMmzfvY+H9zrDgsa8vVB/75mLN6OiYzgXXkkZNTXVh45qHRzeuWTGGQO4QaV9f35bkQaF3CjvD3XEUgDFCYKDLymO0AU8z52X+oKnb0QzSYkGOnbpQw4UiZUlgABaRgTmG1xvoAMrpdke2excfAiyi6eYdH+KftuqTd7cNUQ+51PHcK4ddniPvvTSEWOwMd4c0efK9JeboLnGHbH00lZVP77kNDQ3brRGyBW/lUEwxOp1H84gFFmASNrZLQQN3KLNq1aptsjpu5YoBE/PRq619AJhT68HrZsgDi2B6Ucweo4nL6B3STo6vr69fawKiIkGHKINo0zJ5TdmA1pEXTE8IPwUr7Xj5C40M3prlTXlJLDnAwYYzH/NBYvjl84WqbHbCnzrGME8IREgHTMAmb+l/BO1Gyc6r8BXA2LwIEBiagg/Nges3q15/52ht1w+/5WjXsZZno9DHhsLm8dJXHznqQDP4PqMVTpk0ovUaJH2oA73w61+5S3/3Zw992j2t60wvvgqkFkLnCvGhBhNsE6tqgnRDdHBd44uZ8XUiQGIQtBNuIbesXDr+zMaVI5lMIXOo49uymmIN0gSbw5noiN095aDzChNEMUXZFJRszFId8GTrirFNGyab+vHnP91OaR/yOjd1lkYW2/VgHwq+MUkc3CEmR+F//xvMvLb/M3xrTYYPpyJFJUZeTwqZzzvP1Ty2fPE4cuBIgZYyxF9jQzBff9xX3Fgu7xRzyAuYawM3SkMjyWSFXROh/49YLaOPYrM75B2lWJ+sxGKuoknoxLvvnFE4uHeLe1UJ2bXuyNHvp3330+/VuVyusPmplSPaVioPbCrGY4aODUGZWmnczshKLlaBU1g0e8esuil6qzjyxZkaNrNja+tI09J7+H3GuhYlA1vA0TWmn3LsFLTAoAqOhat54nRP9YnTF2uwM20vrBl5dNkivFhWNBJsDmeSiNj9U84WKODezCpDMhrmDNkfb35g7N7Gu/Jo5pGHFvpmKlmoBJtvQtfVOwS97xqXgNrR8qEmqNN0VkNt1b5dTw+zGd0IeVJbIyYrbB4vfW1D1Bdwoylb20uFphrAppcP1mNCp6f2J884Uuo1vZUNfsCkblt1qON1Q+zW06Ghoa9sBAuCkodPTKaevjFq68TkBJPHiNLJdCFoCAo96FDo7u4+LAD8Y5lgtLPl4WMnfKgjryn42MCTlENyDAGTyB4jbQkt6B3SNgTk161bd/X69esfaAN4gNOUPEFrShtpLBZ2DN3AhGbyL7AAk2h4nTVpTDh+DtEwgXRCcqtw4MCB99vb25+XQqkrXwLDbQ0uOJ5tO1TxN1vkIhBLpV4/sIje4TLUu0/u5+QHK3Sc2EF/jcUmQMl/eeribbvG2tC6YnRD6/Ix7hIoebnvLuoaK9QQutUNoSncZ++SSwp3n60bYmOkCC53ELxuBLwcNdxz47YHR42TO8Vybnd1QzBQJkUz4N1OyRPGXQUTvG4MwdSDL3XoZhDLpnAVLPcIW0Wlr6746sQjSup+TNK12YjLqQxOLw2dWr169f3V1dUP0kYgLiA5IgQTozqWPozXdGRk5Pju3bu3nz17Fi+z3BGCJ2U6R3UDNGgdeE539ETOyfHbOWPGDH/8GFjuDtlFQb7BwUEcs/3Ccmf4ZGNjviwZUA2eeqtjQ6A8grnLly+vnzNnzj55I3dPv3Kb8UWTzxt5E+iX0d7Y2IgfvNAMGog1g/DUTgGgHSkHMXJFmBjJx1FQ7pqbsZLSzBCPTrkUOZALOVUzqFV0M7YRK+ud4e6EfjSu7+joWCjH8E058+flt9JBzrGxscHQpB0UMRK7BzkEAD7L8JW+7B+NAfRWw9opg+rJ/69MV1fXoqamprW1tbXLcJnBiSL4HsM5PDz8S09Pz8mWlpZLYtK7r08EeAzSCWmqTH3wf8gbE4ZNUE+ZDUFPnlTrGKcpQUNHnlTryINy2Oaod5TgUsqAEPKjTlPNIw1lm5KgNNU8/Cnr2JBO26MFU05KCAHUOvKkDKVsAVEmhb/mGR/S0ZaiLJRSFiHE4qzeykxtAVo55kd9lMYKRgOMoZh46xMDr1MX46P9PW+LeUMZTKW5ym5CY/0fFRkGdpS/H20AAAAASUVORK5CYII=) no-repeat center;background-size: contain; "></span>';
    // 当前图片
    let img = this.imgTarget;
    // 图片添加链接后的HTML
    let a = '<a style="position:relative;display:block" href="'+this.imgLink+'">'+span+img+'</a>';
    
    // 将HTML转换为节点类型
    let spanNode = this.parseElement(span);
    let aNode = this.parseElement(a);

    // 获取当前图片
    let index = this.imgIndex;
    let imgs = document.querySelectorAll(".vue-html5-editor img");
    let current = imgs[index];


    let children = current.parentNode.children;
    // 如果当前图片父元素不是A标签
    if(current.parentNode.tagName!='A'){
        for(let i=0;i<children.length;i++){
            let item = children[i];
            // 如果子节点中的某一个节点等于当前图片对象
            if(item.isEqualNode(current)){
                // 将加了链接的图片添加到当前节点下一个节点之前
                current.parentNode.insertBefore(aNode, item.nextSibling);
                // 移除没有加链接的图片
                current.parentNode.removeChild(item);
                break;
            }
        };
    }else{
        let link = this.imgLink;
        // 重新给当前图片的父元素A标签设置可能更改的链接
        current.parentNode.setAttribute("href",link);
        // 给富文本中的图片本身存在链接设置样式,防置链接是原有的
        current.parentNode.setAttribute("style","position:relative;display:block");


        let hasLinkMark=false;
        // 判断是否有链接标识
        for(let i=0;i<children.length;i++){
            let item = children[i];
            if(item!=current ){
                if(item.tagName=='SPAN' && item.id=="linkMark"){
                    hasLinkMark=true;
                }else{
                    current.parentNode.removeChild(item); 
                }
            }
        };
        // 如果没有链接标识
        if(!hasLinkMark){
            // 添加一个链接标识
            current.parentNode.insertBefore(spanNode,children[0]);
        }
    };
    // 关闭添加链接的模态框
    this.closeImgLinkModal();
    // 更新图片事件
    this.addImgEvent();
    
    this.$nextTick(()=>{
        let result = document.querySelectorAll(".content")[0].innerHTML;
        this.data.content = result;
    });
    
},

3. 关闭图片添加链接的模态框。代码如下:

代码语言:javascript
复制
// 关闭插入图片链接模态框
closeImgLinkModal(){
    this.showImgLinkModal = false;
    this.imgTarget = null;
    this.imgIndex = null;
    this.imgLink = "";
},

以下是加了链接的效果:

5. 代码实现

以下是封装好的编辑器文件代码。

代码语言:javascript
复制
<template>
    <div>
        <vue-html5-editor 
            ref="editor"
            :height="960" 
            :content="content" 
            :auto-height="false"  
            @change="updateData">
        </vue-html5-editor>
    </div>
</template>


<script>
// npm install font-awesome --save
import "font-awesome/css/font-awesome.css" 

export default {
    name:"editor",
    props: {
        // 打开图片选择框
        openModal:{
            type:Function
        }
    },
    data() {
        return {
            content:"",
        }
    },
    mounted(){},
    methods: {
        // 更新编辑器内容
        updateData(){
            let obj = document.getElementsByClassName("content")[0];
            let html = obj.innerHTML;
            let filterHtml =  html.replace(/crossorigin="anonymous"/g,"");
            this.content  = filterHtml;
            // 编辑器封装后,将内容传出去
            this.$emit('contentChange',filterHtml);
        },

        // 选择的图片地址
        selectedImageUrl(url){
            let obj = this.$refs.editor.$children;
            // imageUrl为编辑器原有的变量
            obj[0].imageUrl = url;
        },

        // 设置图片宽度
        setImageWidth(){
            this.$nextTick(()=>{
                let list = document.querySelectorAll(".vue-html5-editor .content img");
                if(list.length){
                    for(let i=0;i<list.length;i++){
                        let img = list[i];
                        img.style.width = "100%";
                    }
                };
            });
        }

    },
}
</script>

以下是调用编辑器的文件代码,相关无用代码已经做了清除,可根据需要自行添加。

代码语言:javascript
复制
<template>
    <div>
        <!-- 调用编辑器 -->
        <div class="editor-box">
            <my-editor ref="myEditor" @contentChange="contentChange" :openModal="openModal"></my-editor>
        </div>

        <!-- 图片素材库-->
        <el-dialog title="选择图片" :visible.sync="showSelectImgModal" @close="closeModal" width="960px">
            <div class="img-modal">
                <div class="image-list">
                    <el-upload
                        name="img"
                        class="avatar-uploader"
                        style="width:100px;height:100px;"
                        :multiple="false"
                        :headers="headers"
                        :action="uploadUrl"
                        :data="uploadData"
                        :show-file-list="false"
                        :on-success="onUploadSuccess"
                        :before-upload="onUploadBefore"
                        accept=".jpg,.jpeg,.png,.gif,.bmp,.JPG,.JPEG,.PBG,.GIF,.BMP">
                        <i class="el-icon-plus avatar-uploader-icon"></i>
                    </el-upload>
                    <div class="image-item" v-for="item in imageList" :key="item.id" @click="selectImage(item.path)">
                        <el-image  fit="cover" :src="item.path"></el-image>
                    </div>
                </div>
            </div> 
        </el-dialog>

        <!-- 插入链接-->
        <el-dialog title="插入链接" :visible.sync="showImgLinkModal" @close="closeImgLinkModal" width="800px">
            <div style="display:flex;">
                <el-input placeholder="请输入图片链接地址" v-model="imgLink"></el-input>
                <el-button type="primary" style="margin-left:10px;" @click="confirmAddLink">确定</el-button>
            </div>
        </el-dialog>

    </div>
  
</template>

<script>
// 引入封装后的编辑器组件
import editor from './components/editor';
// 引入获取Token的方法
import { getToken } from '@/utils/auth';

export default {
    name: "myEditor",
    components:{'myEditor':editor},
    data() {
        return {
            // 编辑器的内容
            content:"",

            // 打开显示图库
            showSelectImgModal:false,
            // 图库图片列表
            imageList:[],
            // 上传图片地址(模拟)
            uploadUrl:"http://www.upload.com",
            // 上传图片验证
            headers: {
                authorization: getToken()
            },
            // 上传附加参数
            uploadData:{},


            // 添加链接
            showImgLinkModal:false,
            // 当前图片
            imgTarget:null,
            // 图片下标
            imgIndex:null,
            // 图片链接
            imgLink:"",

        };
    },

    created(){
        // 获取图片素材库
        this.getImage();
    },
    mounted(){},
    methods: {

        // 内容更新时
        contentChange(result){
            this.content = result;
            this.$nextTick(()=>{
                // 内容更新时给图片加事件
                this.addImgEvent();
            });
        },


        // 打开选择图片
        openModal(){
            this.showSelectImgModal = true;
        },
        
        // 获取微信图片
        getImage(){
            // 获取图库的接口中地址(模拟)
            let url = "getWechatImage";
            this.$http.get(url).then((result) => {
                if (result.code == 10000) {
                    this.imageList = result.data;
                }
            });
        },

        // 上传以前
        onUploadBefore(file){
            const size = file.size / 1024 / 1024;
            if (size>10){
                this.$message.error('图片大小不能超过10MB');
                return false
            }
        },

        // 上传成功后
        onUploadSuccess(res){
            if(res.code==10000){
                // 重新获取图片库的图片
                this.getImage();
            }
        },

        // 选择图库图片
        selectImage(url){
            this.$refs.myEditor.selectedImageUrl(url);
            this.closeModal();
        },

        // 关闭选择图片
        closeModal(){
            this.showSelectImgModal = false;
        },


        // 给图片添加事件
        addImgEvent(){
            let imgs = document.querySelectorAll(".vue-html5-editor img");
            for(let i=0;i<imgs.length;i++){
                let img = imgs[i];
                img.style.cursor="pointer";
                img.setAttribute("data-index",i);
                img.onclick = (e)=>{
                    // 显示加链接的对话框
                    this.showImgLinkModal = true;
                    // 区取当前图片的HTML
                    this.imgTarget = e.target.outerHTML;
                    // 获取当前图片自定义的index
                    this.imgIndex = e.target.getAttribute("data-index");
                    // 获取当前元素的父元素
                    let parent = e.target.parentElement;
                    // 如果图片的父元素是已经加了链接的A标签
                    if(parent.tagName=='A'){
                        // 获取A标签的链接地址,方便修改链接地址
                        this.imgLink = parent.getAttribute("href");
                    }
                }
            }
        },


        // 关闭插入图片链接模态框
        closeImgLinkModal(){
            this.showImgLinkModal = false;
            this.imgTarget = null;
            this.imgIndex = null;
            this.imgLink = "";
        },

        // HTML转换为DOM结点
        parseElement(htmlString){
            return new DOMParser().parseFromString(htmlString,'text/html').body.childNodes[0];
        },


        // 确认添加图片链接
        confirmAddLink(){
            // 加了链接的标识符
            let span = '<span id="linkMark" style="width: 26px;height: 26px;display: block;position: absolute;top: 5px;right: 5px;background: url(data:image/png;base64,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) no-repeat center;background-size: contain; "></span>';
            // 当前图片
            let img = this.imgTarget;
            // 图片添加链接后的HTML
            let a = '<a style="position:relative;display:block" href="'+this.imgLink+'">'+span+img+'</a>';
            
            // 将HTML转换为节点类型
            let spanNode = this.parseElement(span);
            let aNode = this.parseElement(a);

            // 获取当前图片
            let index = this.imgIndex;
            let imgs = document.querySelectorAll(".vue-html5-editor img");
            let current = imgs[index];


            let children = current.parentNode.children;
            // 如果当前图片父元素不是A标签
            if(current.parentNode.tagName!='A'){
                for(let i=0;i<children.length;i++){
                    let item = children[i];
                    // 如果子节点中的某一个节点等于当前图片对象
                    if(item.isEqualNode(current)){
                        // 将加了链接的图片添加到当前节点下一个节点之前
                        current.parentNode.insertBefore(aNode, item.nextSibling);
                        // 移除没有加链接的图片
                        current.parentNode.removeChild(item);
                        break;
                    }
                };
            }else{
                let link = this.imgLink;
                // 重新给当前图片的父元素A标签设置可能更改的链接
                current.parentNode.setAttribute("href",link);
                // 给富文本中的图片本身存在链接设置样式,防置链接是原有的
                current.parentNode.setAttribute("style","position:relative;display:block");


                let hasLinkMark=false;
                // 判断是否有链接标识
                for(let i=0;i<children.length;i++){
                    let item = children[i];
                    if(item!=current ){
                        if(item.tagName=='SPAN' && item.id=="linkMark"){
                            hasLinkMark=true;
                        }else{
                            current.parentNode.removeChild(item); 
                        }
                    }
                };
                // 如果没有链接标识
                if(!hasLinkMark){
                    // 添加一个链接标识
                    current.parentNode.insertBefore(spanNode,children[0]);
                }
            };
            // 关闭添加链接的模态框
            this.closeImgLinkModal();
            // 更新图片事件
            this.addImgEvent();
            
            this.$nextTick(()=>{
                let result = document.querySelectorAll(".content")[0].innerHTML;
                this.data.content = result;
            });
            
        }

    },
};
</script>

<style lang="scss" scoped>

.editor-box{
    width:718px;
    height:1000px;
    overflow:hidden;
}

.img-modal{
    width:100%;
    height:600px;
    overflow-y: auto;
    .image-list{
        width:100%;
        display: flex;
        flex-direction: row;
        justify-content: flex-start;
        flex-wrap: wrap;
        align-items: flex-start;
        .image-item{
            height:100px;
            width:100px;
            overflow: hidden;
            display: flex;
            flex-direction:column;
            justify-content:space-around;
            align-items:center;
            .el-image{
                width:100%;
                height:100%;
                cursor: pointer;
            }
        }
    }  
}


</style>

以下是上面代码中获取Token的文件代码:

代码语言:javascript
复制
// npm inatall js-cookie --save
import Cookies from 'js-cookie'

const TokenKey = 'Admin-Token'

export function getToken() {
  return Cookies.get(TokenKey)
}

export function setToken(token) {
  return Cookies.set(TokenKey, token)
}

export function removeToken() {
  return Cookies.remove(TokenKey)
}

 如果上面的文件作为编辑素材时,可以用下面的代码对编辑器进行初始赋值。

代码语言:javascript
复制
this.$refs.myEditor.content = "要赋值的富文本";
// 设置内容中图片的宽度
this.$refs.myEditor.setImageWidth();

最后是在main.js中集成编辑器的代码。

代码语言:javascript
复制
// npm install vue-html5-editor --save
import VueHtml5Editor from 'vue-html5-editor'
var options = {
    // 全局组件名称,使用new VueHtml5Editor(options)时该选项无效 
    name: "vue-html5-editor",
    // 是否显示模块名称,开启的话会在工具栏的图标后台直接显示名称
    showModuleName: false,
    // 自定义各个图标的class,默认使用的是font-awesome提供的图标
    icons: {
        text: "fa fa-pencil",
        color: "fa fa-paint-brush",
        font: "fa fa-font",
        align: "fa fa-align-justify",
        list: "fa fa-list",
        link: "fa fa-chain",
        unlink: "fa fa-chain-broken",
        tabulation: "fa fa-table",
        image: "fa fa-file-image-o",
        hr: "fa fa-minus",
        eraser: "fa fa-eraser",
        undo: "fa-undo fa",
        info: "fa fa-info",
    },
    // 配置图片模块
    image: {
        // 文件最大体积,单位字节  max file size
        sizeLimit: 512 * 1024,
        // 上传参数,默认把图片转为base64而不上传
        upload: {
            url: null,
            headers: {},
            params: {},
            fieldName: {}
        },
        // 压缩参数,默认使用localResizeIMG进行压缩,设置为null禁止压缩
        compress: {
            width: 1600,
            height: 1600,
            quality: 80
        },
        // 响应数据处理,最终返回图片链接
        uploadHandler(responseText){

            var json = JSON.parse(responseText)
            if (!json.ok) {
                alert(json.msg)
            } else {
                return json.data
            }
        }
    },
    // 语言,内建的有英文(en-us)和中文(zh-cn)
    language: "zh-cn",
    // 自定义语言
    i18n: {
        "zh-cn": {
            "align": "对齐方式",
            "image": "图片",
            "list": "列表",
            "link": "链接",
            "unlink": "去除链接",
            "table": "表格",
            "font": "文字",
            "text": "排版",
            "eraser": "格式清除",
            "info": "关于",
            "color": "颜色",
            "please enter a url": "请输入地址",
            "create link": "创建链接",
            "bold": "加粗",
            "italic": "倾斜",
            "underline": "下划线",
            "strike through": "删除线",
            "subscript": "上标",
            "superscript": "下标",
            "heading": "标题",
            "font name": "字体",
            "font size": "文字大小",
            "left justify": "左对齐",
            "center justify": "居中",
            "right justify": "右对齐",
            "ordered list": "有序列表",
            "unordered list": "无序列表",
            "fore color": "前景色",
            "background color": "背景色",
            "row count": "行数",
            "column count": "列数",
            "save": "确定",
            "upload": "上传",
            "progress": "进度",
            "unknown": "未知",
            "please wait": "请稍等",
            "error": "错误",
            "abort": "中断",
            "reset": "重置"
        }
    },
    // 隐藏不想要显示出来的模块

    hiddenModules: [],
    // 自定义要显示的模块,并控制顺序
    visibleModules: [
        "text",
        "color",
        "font",
        "align",
        "list",
        "link",
        "unlink",
        "tabulation",
        "image",
        "hr",
        "eraser",
        "undo",
    ],
    // 扩展模块,具体可以参考examples或查看源码
    modules: {}
};

Vue.use(VueHtml5Editor,options);
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-08-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 复制网络图片时无法粘贴成功
  • 2. 无法从已有的图库中选择图片
  • 3. 插入的图片没有做宽度限制
  • 4. 给图片加超链接
  • 5. 代码实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档