Vue实现markdown编辑器

安装 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();
                })();
            };
        }

效果图

在这里插入图片描述

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值