這是最近用Vue寫的一個Markeddown編輯器, 主要目的是擴展Vue-Manager的編輯器功能。核心功能引入了Marked插件,將Markedown文檔解析爲html。樣式基本沿用了vm-editor,並增長了多種主題選擇的功能。html
項目已經打包上傳到npm,歡迎使用。vue
預覽地址 | https://luosijie.github.io/vm-markdown/ |
---|---|
源碼地址 | https://github.com/luosijie/vm-markdown |
npm install --save vm-markdwon
import VmMarkdown from 'vm-markdwon' export default { ... components: { VmMarkdown }, methods: { showHtml (data) { console.log(data) } } ... }
<VmMarkdown :theme="theme" width="1000px" height="600px" v-on:getHtml="showHtml" :defaultText="intro"> </VmMarkdown>
vm-markdown做爲一款 以簡潔易用爲目標 的編輯器, 核心解析功能由 Marked 來完成, 而其餘功能主要爲優化部分不熟悉Markdown語法用戶的使用體驗。
主要功能能夠分爲:git
兼容Firefox瀏覽器的文本插入函數github
function insertText(dom,string) { if (document.execCommand('insertText', false, string)) { return }else{ let start = dom.selectionStart let end = dom.selectionEnd dom.value = dom.value.substring(0, start) + string + dom.value.substring(end, dom.value.length) dom.selectionStart = start + string.length; dom.selectionEnd = start + string.length; dom.focus() } } export default insertText
import insertText from '../assets/js/insertText.js' ... methods: { insertText(string){ let content = document.querySelector('.vm-markdown-content') insertText(content, string) this.$emit('textChange', content.value) } }
按鈕綁定 insertText(string) 事件npm
... <VmMarkdownButton icon="iconfont icon-bold" @click.native="insertText(' **Bold** ')"></VmMarkdownButton> <VmMarkdownButton icon="iconfont icon-italic" @click.native="insertText(' *Italic* ')"></VmMarkdownButton> ...
Dom結構瀏覽器
... <div class="vm-markdown-edit" :style="{backgroundColor: themeValue.bgLeft}"> // 輸入部分 <textarea v-focus class="content-markdown" v-model="markdString"></textarea> </div> // 實時預覽部分 <div class="vm-markdown-html" v-html="htmlString" :style="{backgroundColor: themeValue.bgRight}"> </div> ...
引入 Marked 解析, 並實時預覽bash
import marked from 'marked' watch: { markdString(value){ marked.setOptions({ renderer: new marked.Renderer(), gfm: true, tables: true, breaks: true, pedantic: false, sanitize: false, smartLists: true, smartypants: false }) this.htmlString = marked(value) ... } },
由於 Marked 解析出來的html,是不帶任何樣式的,因此須要自定義樣式,並確保最後輸出帶樣式的html字符串markdown
parseHtml: function () { let style = { ul: ` margin: 10px 20px; list-style-type: square; padding: 0; `, ol: ` margin: 10px 20px; list-style-type: decimal; padding: 0; `, li: ` display: list-item; padding: 0; `, hr: ` margin: 15px 0; border-top: 1px solid #eeeff1; `, pre: ` display: block; margin: 10px 0; padding: 8px; border-radius: 4px; background-color: #f2f2f2; color: #656565; font-size: 14px; `, blockquote: ` display: block; border-left: 4px solid #ddd; margin: 15px 0; padding: 0 15px; `, img: ` margin: 20px 0; `, a: ` color: #41b883; `, table: ` border: 1px solid #eee; border-collapse: collapse; `, tr: ` border: 1px solid #eee; `, th: ` padding: 8px 30px; border-right: 1px solid #eee; background-color: #f2f2f2; `, td: ` padding: 8px 30px; border-right: 1px solid #eee; ` } let html = document.getElementsByClassName('vm-markdown-html')[0] let tagNames = Object.keys(style) for (let i = 0; i < tagNames.length; i++) { let _tagNames = html.getElementsByTagName(tagNames[i]) if (_tagNames.length > 0) { for (let j = 0; j < _tagNames.length; j++) { _tagNames[j].style = style[tagNames[i]] } } } }, getHtml: function () { let html = document.querySelector('.vm-markdown-html') this.$emit('getHtml', html.innerHTML) } },
Markdown的表格是相對繁瑣的輸入,vm-markown借用圖形化的操做實現快捷輸入app
<ul class="vm-markdown-table" v-insertTable:color="filterColor"> </ul>
directives:{ insertTable: { inserted: function(el,binding){ // 定義總單元格數目 4*6 = 24 let length = 24 // 鼠標所在的單元格的座標 let x = 0, y = 0 // 每一個單元格賦值:行和列的座標 for(let i=0; i<length; i++){ let setx = i%6 + 1 let sety = parseInt(i/6) + 1 let li = document.createElement('li') li.setAttribute('data-x', setx) li.setAttribute('data-y', sety) el.appendChild(li) } // 鼠標滑過改變顏色 el.addEventListener('mouseover', function(evt){ if (evt.target.tagName === 'LI') { x= evt.target.getAttribute('data-x') y= evt.target.getAttribute('data-y') let lis = el.querySelectorAll('li') for(let i=0; i<lis.length; i++){ lis[i].style.backgroundColor = '#e0e0e0' if(lis[i].dataset.x <= x && lis[i].dataset.y <= y){ lis[i].style.backgroundColor = binding.value } } } }) // 單擊插入表格字符串 el.addEventListener('click', function(evt){ if(x && y){ let th = '| Head ' let td = '| Data ' let tl = '| --- ' let str = '' let ths = '', tls = '', tds = '' for(let i=0; i<x; i++){ ths = ths.concat(th) tls = tls.concat(tl) } for(let j=0; j<y; j++){ for(let k=0; k<x; k++){ tds = tds.concat(td) } tds += ' |\n' } ths += ' |\n' tls += ' |\n' str += ths + tls + tds document.execCommand('insertText', false, str) } }) } } }
實現縮放的layout函數dom
layout: function (event) { let VmMarkdown = document.querySelector('.vm-markdown') let VmMarkdownEdit = document.querySelector('.vm-markdown-edit') function classHas(str){ return event.target.classList.contains(str) } if(classHas('icon-layout-zoom')){ if (VmMarkdown.style.position === 'fixed') { VmMarkdown.style = 'width:' + this.width + ';' + 'height:' + this.height + ';' }else{ VmMarkdown.style.position = 'fixed' VmMarkdown.style.left = '0' VmMarkdown.style.top = '0' VmMarkdown.style.margin = '0' VmMarkdown.style.width = '100%' VmMarkdown.style.height = '100%' } }else if (classHas('icon-layout-left')) { VmMarkdownEdit.style.width = '0' }else if (classHas('icon-layout-right')) { VmMarkdownEdit.style.width = '100%' }else if (classHas('icon-layout-default')) { VmMarkdownEdit.style.width = '50%' } },
將layout綁定到頂部菜單的點擊事件中
<VmMarkdownMenu @click.native="layout"></VmMarkdownMenu>
先這樣了 歡迎star