利用marked 和 highlight.js开发markdown组件html
实现效果图以下:vue
markdown组件已这种形式<Markdown v-model="markdown"></Markdown>
来绑定markdown的值
咱们能够经过 value prop 和 input事件来达到这个效果用法详情ios
代码部分:git
<Markdown v-model="markdown"></Markdown>
1.响应v-modelgithub
// 经过监听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语法axios
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 = `` 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(); } }
经过 setCursorPosition
跟 insertAtCursor
方法 插入光标所在位置并设置光标位置segmentfault
<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键markdown
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上抠下来的app
完整代码,点此获取博客地址dom