利用marked 和 highlight.js开发markdown组件

实现效果图如下:

938b4748d2e28.gif

markdown组件已这种形式<Markdown v-model="markdown"></Markdown>来绑定markdown的值
我们可以通过 value prop 和 input事件来达到这个效果用法详情

代码部分:

<Markdown v-model="markdown"></Markdown>

markdown组件

1.响应v-model

// 通过监听input事件 触发handleModelInput方法
<textarea v-model="val" @input="handleModelInput" ref="text" @keydown.tab="tabMarkdown"></textarea>

import marked from 'marked'
import highlightJs from 'highlight.js'
export default {
    props: ['value'],
    data() {
        return {
            val: this.value
        }
    },
    methods: {
        handleModelInput() {// 通过$emit来把值返回给父组件
            this.$emit('input', this.val)
        }
    }
}

2.插入markdown语法

async insertImg(e) { // 插入图片
    let formData = new FormData(),
        img = '';
    formData.append('img', e.target.files[0]);
    try {
        let data = await this.axios({
            method: 'post',
            url: 'http://localhost:3000/markdown_upload_img',
            data: formData
        })
        img = data.data.img
    } catch (e) {
        console.log(e)
    }
    
    let val = `![图片描述](${img})`
    this.setCursorPosition(this.$refs.text, val, 6)
},
insertLink () { //插入链接
    this.maskBol = false
    let val = `[链接描述](${this.link})`
    this.setCursorPosition(this.$refs.text, val, 5)
},
setCursorPosition (dom,val,posLen) { // 设置光标位置
    var cursorPosition = 0;
    if(dom.selectionStart){
        cursorPosition = dom.selectionStart;
    }
    this.insertAtCursor(dom,val);
    dom.focus();
    dom.setSelectionRange(dom.value.length,cursorPosition + (posLen || val.length));
    this.val = dom.value
},
insertAtCursor(dom, val) { // 光标所在位置插入字符
    if (document.selection){
        dom.focus();
        sel = document.selection.createRange();
        sel.text = val;
        sel.select();
    }else if (dom.selectionStart || dom.selectionStart == '0'){
        let startPos = dom.selectionStart;
        let endPos = dom.selectionEnd;
        let restoreTop = dom.scrollTop;
        dom.value = dom.value.substring(0, startPos) + val + dom.value.substring(endPos, dom.value.length);
        if (restoreTop > 0){
            dom.scrollTop = restoreTop;
        }
        dom.focus();
        dom.selectionStart = startPos + val.length;
        dom.selectionEnd = startPos + val.length;
    } else {
        dom.value += val;
        dom.focus();
    }
}

通过 setCursorPositioninsertAtCursor方法 插入光标所在位置并设置光标位置

  1. 转化markdown语法显示区域
<div class="render fmt" v-html="renderHtml"></div>

// 实时转化textarea里面的markdown语法
computed: {
    renderHtml() {
        marked.setOptions({
            renderer: new marked.Renderer(),
            gfm: true, //允许 Git Hub标准的markdown.
            tables: true, //允许支持表格语法。该选项要求 gfm 为true。
            breaks: true, //允许回车换行。该选项要求 gfm 为true。
            pedantic: false, //尽可能地兼容 markdown.pl的晦涩部分。不纠正原始模型任何的不良行为和错误。
            sanitize: true, //对输出进行过滤(清理),将忽略任何已经输入的html代码(标签)
            smartLists: true, //使用比原生markdown更时髦的列表。 旧的列表将可能被作为pedantic的处理内容过滤掉.
            smartypants: false, //使用更为时髦的标点,比如在引用语法中加入破折号。
            highlight: function (code) {
                return highlightJs.highlightAuto(code).value;
            }
        });
        return marked(this.val)
    }
}

因为习惯使用tab缩进,所以在textarea里面输入的时候 按tab会切换元素,不会进行缩进, 所有我们得处理下tab键

tabMarkdown (e) { // 禁止tabs键的默认事件,并设置tab等于4个空格
    e.preventDefault()
    let indent = '    '
    let start = this.textarea.selectionStart
    let end = this.textarea.selectionEnd
    let selected = window.getSelection().toString()
    selected = indent + selected.replace(/\n/g, '\n' + indent)
    this.textarea.value = this.textarea.value.substring(0, start) + selected
            + this.textarea.value.substring(end);
    this.textarea.setSelectionRange(start + indent.length, start
            + selected.length)
}

markdown样式我是直接从 segmentfault上抠下来的

完整代码,点此获取

博客地址


咚子
3.3k 声望12.5k 粉丝

一个前端