這是最近用Vue寫的一個Markeddown編輯器, 主要目的是擴充套件Vue-Manager的編輯器功能。核心功能引入了Marked外掛,將Markedown文件解析為html。樣式基本沿用了vm-editor,並增加了多種主題選擇的功能。
專案已經打包上傳到npm,歡迎使用。
預覽地址 | luosijie.github.io/vm-markdown… |
---|---|
原始碼地址 | github.com/luosijie/vm… |
安裝
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語法使用者的使用體驗。
主要功能可以分為:
- 將Markdown文字插入編輯框
- 將Mardown文字解析為html,並實時預覽
- 將Makdown解析的html加入自定義樣式
- 實現表格的的快速輸入功能
- 實現編輯區域的縮放功能
Markdown文字插入
相容Firefox瀏覽器的文字插入函式
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) 事件
...
<VmMarkdownButton icon="iconfont icon-bold" @click.native="insertText(' **Bold** ')"></VmMarkdownButton>
<VmMarkdownButton icon="iconfont icon-italic" @click.native="insertText(' *Italic* ')"></VmMarkdownButton>
...複製程式碼
Markdown文字解析為html
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 解析, 並實時預覽
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字串
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借用圖形化的操作實現快捷輸入
<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函式
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