需求分析
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=' ';
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语法的替换。明天继续加油!
网友评论