美文网首页IT全栈圈
VUE自定义富文本编辑器

VUE自定义富文本编辑器

作者: 渝聆墨 | 来源:发表于2019-07-06 21:45 被阅读16次

需求分析

1.开发一个富文本编辑器,包含功能:编辑标题,编辑内容,编辑图片,拥有保存,发布功能。
思路:
1.markdown编辑模式,字符替换实现富文本。
2.上传图片
3.可以插入html标签等

HTML

<template >
    <div class="write-content-boxs">
        <div class="write-header">
            <div class="write-title">
                <input class="edit-title" v-model.lazy="title" type="text" placeholder="请输入标题" />
            </div>
            <div class="write-tools">
                <span class="item-tool" @click="chooseType">插入图片</span>
                <span class="item-tool" @click="onSaveArticle">保存文章</span>
                <span class="item-tool" @click="onIssueArticle">发布文章</span>
            </div>
        </div>
        <div class="write-content-box">
            <div id="mediaedit" class="write-content" contenteditable="true" @mouseup="selectText()">

            </div>
        </div>
        <input type="file" id="upload_file" class="input-file" style="display: none;" name="avatar" ref="avatarInput" @change="fileChange($event)"
         accept="image/gif,image/jpeg,image/jpg,image/png">
    </div>
</template>

CSS

<style scoped="scoped">
    .write-content-boxs{
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        background-color: #FFFFFF;
        overflow-x: hidden;
    }

    .write-content-box {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        background-color: #FFFFFF;
        overflow-x: hidden;
        overflow-y: hidden;
        
    
    }

    .edit-title {
        width: 100%;
        padding: 1.8rem;
        font-size: 1.5rem;
        border: none;
    }
    
    .write-title {
        border-bottom: solid 1px gainsboro;
    }
    
    
    
    .write-tools {
        background-color: #545c64;
        width: 100%;
        text-align: center;
        line-height: 1rem;
        padding: 1rem;
    }
    
    .write-tools span {
        color: white;
        font-size: 1rem;
        border-right: solid 1px white;
        padding-left: 0.5rem;
        padding-right: 0.5rem;
    }
    
    .write-content {
        width: 98%;
        text-align: left;
        font-size: 1.2rem;
        -webkit-overflow-scrolling: touch;
        overflow-x: scroll;
        padding: 1rem;
    
    }

</style>

JS

<script>
    export default {
        name:'write-content',
        data() {
            return {
                imgList: [],
                size: 0,
                limit: 6, //限制图片上传的数量
                tempImgs: [],
                desc:'',
                text:this.content
            }
        },
        watch: {
            //普通的watch监听
            title(val, oldVal) {
                
            },
            content(val, oldVal) {
                // console.log("a: " + val, this.selectArticleIndex);
            }
        },
        props:{
            title:{
                type:String,
                default:''
            },
            content:{
                type:String,
                default:''
            }
        },
        mounted() {
            var that = this;
            var mediaedit = document.getElementById("mediaedit");
            mediaedit.addEventListener(
                "DOMSubtreeModified",
                function(evt) {
                    that.text = mediaedit.innerHTML;
                    
                },
                false
            );
        },
        methods: {
            onSaveArticle: function() {
                let param={
                    title:this.title,
                    content:this.text
                }
                this.$emit('onsave', param);
            },
            onIssueArticle: function() {
                let param={
                    title:this.title,
                    content:this.text
                }
                this.$emit('onissue', param);
            },transformText:function(text){
                //行
                let line='<div><br></div>';
                //空格
                let block='&nbsp;';
                let header='#';
                var reg = "/"+ch+"/g";
                var reg="^"+header+"[\s\S]+?"+line+"$";
                var objExp = new RegExp(reg);
                if (objExp.test(str) == true) {
                    text=text.replace(header, '<h1>');
                } 
            },
            addImage: function(imageSrc) {
                var scope = document.getElementById("mediaedit");
                var frameDiv = document.createElement("img");
                frameDiv.src = imageSrc;
                frameDiv.style.width = "80%";
                scope.appendChild(frameDiv);
            },
            chooseType() {
                document.getElementById("upload_file").click();
            },
            fileChange(el) {
                if (!el.target.files[0].size) return;
                this.fileList(el.target);
                el.target.value = "";
            },
            fileList(fileList) {
                let files = fileList.files;
                for (let i = 0; i < files.length; i++) {
                    //判断是否为文件夹
                    if (files[i].type != "") {
                        this.fileAdd(files[i]);
                    } else {
                        //文件夹处理
                        this.folders(fileList.items[i]);
                    }
                }
            },
            //文件夹处理
            folders(files) {
                let _this = this; //判断是否为原生file
                if (files.kind) {
                    files = files.webkitGetAsEntry();
                }
                files.createReader().readEntries(function(file) {
                    for (let i = 0; i < file.length; i++) {
                        if (file[i].isFile) {
                            _this.foldersAdd(file[i]);
                        } else {
                            _this.folders(file[i]);
                        }
                    }
                });
            },
            foldersAdd(entry) {
                let _this = this;
                entry.file(function(file) {
                    if (_this.limit !== undefined) _this.limit--;
                    if (_this.limit !== undefined && _this.limit < 0) return; //总大小
                    _this.size = _this.size + file.size;
                    _this.fileAdd(file);
                });
            },
            fileAdd(file) {
                //判断是否为图片文件
                if (file.type.indexOf("image") == -1) {
                    this.$dialog.toast({
                        mes: "请选择图片文件"
                    });
                } else {
                    let reader = new FileReader();
                    let image = new Image();
                    let _this = this;
                    reader.readAsDataURL(file);
                    reader.onload = function() {
                        file.src = this.result;
                        image.onload = function() {
                            let width = image.width;
                            let height = image.height;
                            file.width = width;
                            file.height = height;
                            _this.imgList.push({
                                file
                            });
                            console.log(_this.imgList);
                        };
                        image.src = file.src;
                        _this.$emit('loadimg', file.src);
                    };
                }
            },
            delImg(index) {
                this.size = this.size - this.imgList[index].file.size;
                //总大小
                this.imgList.splice(index, 1);
                if (this.limit !== undefined) this.limit = 6 - this.imgList.length;
            },
            selectText: function() {
                if (document.Selection) {
                    //ie浏览器
                    this.desc = document.selection.createRange().text;
                } else {
                    //标准浏览器
                    this.desc = window.getSelection().toString();
                }
            }
        }
    }
</script>

测试

<template>
    <div>
          <writetool :title="title" :content="content" @onsave="onSaveArticle" @onissue="onIssueArticle" @loadimg="selectImg"></writetool>
    </div>
</template>
<script>
    import writetool from '../element/WriteTool.vue'
    export default {
        components: {
            writetool
        },data() {
            return {
                            title:'标题',
                            content:'文章内容'
                        }
                },methods: {
                      onSaveArticle: function(data) {
                          console.log(data);
                      },  onIssueArticle: function(data) {
                          console.log(data);
                      },  selectImg: function(img) {
                          console.log(img);
                      }
                }
         }
<script>

小结

这次先把编辑器的基础功能编辑好了,初步实现了监听标题与内容,接下来继续完善,包含图片的上传,markdown语法的替换。明天继续加油!

相关文章

网友评论

    本文标题:VUE自定义富文本编辑器

    本文链接:https://www.haomeiwen.com/subject/rsimhctx.html