利用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 = `![圖片描述](${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(); } }
經過 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