安装 mavon-editor
npm install mavon-editor --save
引入mavonEditor
import Vue from 'vue'
import mavonEditor from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
// use
Vue.use(mavonEditor)
html代码
<div style="width: 100%; height: 100%;">
<div class="header">
<a-icon type="left" />
文章管理
<a-input size="large" placeholder="请输入文章标题" :maxLength="maxLength" v-model="inputValue" @change="inputChange"/>
<span class="suffix">{{number + '/' +numberSum}}</span>
<div class="headerRight">
<a-button type="danger" ghost class="hrMange">
保存草稿
</a-button>
<a-button type="danger" class="hrMange" @click="showModal">
发布文章
</a-button>
<a-avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" class="hrMange"/>
</div>
</div>
<mavon-editor v-model="context"
:toolbars="toolbars"
@change="change"
style="height: 100%;z-index:9;"
/>
<article class="markdown-body" v-html="contexts"></article>
<template>
<!--发布文章-->
<div>
<a-modal v-model="visible" title="发布文章" on-ok="handleOk">
<template slot="footer">
<a-button key="back" @click="handleCancel">
取消
</a-button>
<a-button key="submit" type="danger" ghost :loading="loading" @click="handleOk">
发布文章
</a-button>
</template>
<a-form :form="form" @submit="handleSubmit" :label-col="{ span: 5 }" :wrapper-col="{ span: 12 }">
<a-form-item label="文章标签">
<div>
<template v-for="(tag, index) in tags">
<a-tooltip v-if="tag.length > 20" :key="tag" :title="tag">
<a-tag :key="tag" :closable="true" @close="() => handleClose(tag)">
{{ `${tag.slice(0, 20)}...` }}
</a-tag>
</a-tooltip>
<a-tag v-else :key="tag" :closable="true" :color="color[index]" @close="() => handleClose(tag)">
{{ tag }}
</a-tag>
</template>
<a-input
v-if="inputVisible"
ref="input"
type="text"
size="small"
:style="{ width: '78px' }"
:value="inputValues"
@change="handleInputChange"
@blur="handleInputConfirm"
@keyup.enter="handleInputConfirm"
/>
<a-tag v-else style="background: #fff; borderStyle: dashed;" @click="showInput">
<a-icon type="plus" /> 添加文章标签
</a-tag>
</div>
</a-form-item>
<a-form-item label="分类专栏">
<div>
<template v-for="(tag, index) in sortTags">
<a-tooltip v-if="tag.length > 20" :key="tag" :title="tag">
<a-tag :key="tag" :closable="true" @close="() => sortHandleClose(tag)">
{{ `${tag.slice(0, 20)}...` }}
</a-tag>
</a-tooltip>
<a-tag v-else :key="tag" :closable="true" :color="color[index]" @close="() => sortHandleClose(tag)">
{{ tag }}
</a-tag>
</template>
<a-input
v-if="sortVisible"
ref="input"
type="text"
size="small"
:style="{ width: '78px' }"
:value="sortValues"
@change="sortHandleInputChange"
@blur="sortHandleInputConfirm"
@keyup.enter="sortHandleInputConfirm"
/>
<a-tag v-else style="background: #fff; borderStyle: dashed;" @click="sortShowInput">
<a-icon type="plus" /> 添加分类专栏
</a-tag>
</div>
</a-form-item>
<a-form-item label="文章类型">
<a-select placeholder="请选择" style="width: 150px" @change="handleChange" v-decorator="['type', { rules: [{ required: true, message: '请选择文章类型!' }] }]">
<a-select-option value="jack">
原创
</a-select-option>
<a-select-option value="lucy">
转载
</a-select-option>
<a-select-option value="Yiminghe">
翻译
</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="发布形式">
<a-radio-group @change="onChange" v-decorator="['modus']">
<a-radio :value="1">
公开
</a-radio>
<a-radio :value="2">
私密
</a-radio>
<a-radio :value="3">
粉丝可见
</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
<!--<template>
<div>
<template v-for="(tag, index) in tags">
<a-tooltip v-if="tag.length > 20" :key="tag" :title="tag">
<a-tag :key="tag" :closable="true" @close="() => handleClose(tag)">
{{ `${tag.slice(0, 20)}...` }}
</a-tag>
</a-tooltip>
<a-tag v-else :key="tag" :closable="true" :color="color[index]" @close="() => handleClose(tag)">
{{ tag }}
</a-tag>
</template>
<a-input
v-if="inputVisible"
ref="input"
type="text"
size="small"
:style="{ width: '78px' }"
:value="inputValues"
@change="handleInputChange"
@blur="handleInputConfirm"
@keyup.enter="handleInputConfirm"
/>
<a-tag v-else style="background: #fff; borderStyle: dashed;" @click="showInput">
<a-icon type="plus" /> New Tag
</a-tag>
</div>
</template>-->
</a-modal>
</div>
</template>
</div>
css代码
<style>
.markdown-body code {
margin: 0;
font-size: 100% !important;
background-color: rgba(27,31,35,.05);
border-radius: 3px;
}
.header {
width: 100%;
height: 56px;
font-size: 18px;
}
.header input {
width: 50%;
}
.suffix {
margin-left: -52px;
position: absolute;
margin-top: 7px;
}
.ant-input-affix-wrapper{
width: 80%;
}
.headerRight{
float: right;
margin-top: 5px;
}
.hrMange{
margin-right: 20px;
}
.ant-col-12 {
display: block;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 75%;
}
</style>
js代码
export default {
data(){
return {
formLayout: 'horizontal',
form: this.$form.createForm(this, { name: 'coordinated' }),
/*发布文章*/
loading: false,
visible: false,
color: ['pink','red','orange','green','cyan'],
//文章标签
inputVisible: false,
inputValues: '',
tags: [],
//分类专栏
sortVisible: false,
sortValues: '',
sortTags: [],
/*浏览器窗口大小*/
clientWidth: '',
number: 0,
numberSum: 100,
maxLength: 100,
/*markdown*/
inputValue: '',
contexts: '',
context: '',//输入的数据,
toolbars: {
bold: true, // 粗体
italic: true, // 斜体
header: true, // 标题
underline: true, // 下划线
strikethrough: true, // 中划线
mark: true, // 标记
superscript: true, // 上角标
subscript: true, // 下角标
quote: true, // 引用
ol: true, // 有序列表
ul: true, // 无序列表
link: true, // 链接
imagelink: true, // 图片链接
code: true, // code
table: true, // 表格
fullscreen: true, // 全屏编辑
readmodel: true, // 沉浸式阅读
htmlcode: true, // 展示html源码
help: true, // 帮助
/* 1.3.5 */
undo: true, // 上一步
redo: true, // 下一步
trash: true, // 清空
save: true, // 保存(触发events中的save事件)
/* 1.4.2 */
navigation: true, // 导航目录
/* 2.1.8 */
alignleft: true, // 左对齐
aligncenter: true, // 居中
alignright: true, // 右对齐
/* 2.2.1 */
subfield: true, // 单双栏模式
preview: true, // 预览
}
};
},
methods: {
handleSubmit(e) {
e.preventDefault();
this.form.validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
},
/**
* 动态生成标签 start
*/
handleClose(removedTag) {
console.log(removedTag, 808080);
const tags = this.tags.filter(tag => tag !== removedTag);
console.log(tags);
this.tags = tags;
},
showInput() {
this.inputVisible = true;
this.$nextTick(function() {
this.$refs.input.focus();
});
},
handleInputChange(e) {
this.inputValues = e.target.value;
},
handleInputConfirm() {
const inputValue = this.inputValues;
let tags = this.tags;
if (inputValue && tags.indexOf(inputValue) === -1) {
tags = [...tags, inputValue];
}
console.log(tags);
Object.assign(this, {
tags,
inputVisible: false,
inputValues: '',
});
},
/**
* 动态生成标签 end
*/
/**
* 动态生成分类专栏 start
*/
sortHandleClose(removedTag) {
console.log(removedTag, 808080);
const sortTags = this.sortTags.filter(tag => tag !== removedTag);
console.log(sortTags);
this.sortTags = sortTags;
},
sortShowInput() {
this.sortVisible = true;
this.$nextTick(function() {
this.$refs.input.focus();
});
},
sortHandleInputChange(e) {
this.sortValues = e.target.value;
},
sortHandleInputConfirm() {
const sortValues = this.sortValues;
let sortTags = this.sortTags;
if (sortValues && sortTags.indexOf(sortValues) === -1) {
sortTags = [...sortTags, sortValues];
}
console.log(sortTags);
Object.assign(this, {
sortTags,
sortVisible: false,
sortValues: '',
});
},
/**
* 动态生成分类专栏 end
*/
/**
* 发布文章弹出窗口 start
*/
onChange(e) {
console.log('radio checked', e.target.value);
},
handleChange(value) {
console.log(`selected ${value}`);
},
showModal() {
this.visible = true;
setTimeout(() => {
this.form.setFieldsValue({
'modus': 1
})
}, 100);
},
alertManage(count) {
this.$message.warning(count);
},
handleOk(e) {
let title = this.inputValue==""?this.alertManage("文章标题不能为空!!!"):true;
let tags = title==true?(this.tags.length==0?this.alertManage("请选择文章标签!!!"):true):false;
let sortTags = tags==true?(this.sortTags.length==0?this.alertManage("请选择分类专栏!!!"):true):false;
if (tags == true && sortTags == true) {
this.form.validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
this.loading = true;
setTimeout(() => {
this.loading = false;
}, 3000);
}
},
handleCancel(e) {
this.visible = false;
},
change(val, render) {
this.contexts = render;
},
/**
* 发布文章弹出窗口 end
*/
/**
* 浏览器窗口大小调整start
*/
inputChange() {
this.number = this.inputValue.length;
this.numberSum = 100 - this.inputValue.length;
},
clientWidths() {
if (this.clientWidth <= 801 && this.clientWidth > 582) {
$(".header input").css("width", "30%");
} else if (this.clientWidth <= 582) {
$(".header input").css("width", "16%");
} else {
$(".header input").css("width", "50%");
}
}
/**
* 浏览器窗口大小调整 end
*/
},
mounted() {
this.clientWidth = document.body.clientWidth;
this.clientWidths();
window.onresize = () => {
return (() => {
this.clientWidth = document.body.clientWidth;
console.log(document.body.clientWidth);
this.clientWidths();
})();
};
}