发布1.4.0版本

This commit is contained in:
zhaoxh 2019-10-28 14:57:03 +08:00
parent 952d702fff
commit b8b636f34d
32 changed files with 2017 additions and 1806 deletions

13
.editorconfig Normal file → Executable file
View File

@ -1,9 +1,16 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
indent_size = 4
end_of_line = lf
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab

4
.eslintignore Normal file
View File

@ -0,0 +1,4 @@
# Created by .ignore support plugin (hsz.mobi)
src/markdown/font/*.js
src/doc.js
src/markdown/js/hljs.js

22
.eslintrc.json Executable file
View File

@ -0,0 +1,22 @@
{
"rules": {},
"env": {
"es6": true,
"browser": true
},
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"extends": [
"eslint:recommended",
"plugin:vue/essential"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"plugins": [
"vue"
]
}

5
dist/build.js vendored

File diff suppressed because one or more lines are too long

BIN
dist/build.js.gz vendored

Binary file not shown.

1
dist/build.js.map vendored

File diff suppressed because one or more lines are too long

BIN
dist/build.js.map.gz vendored

Binary file not shown.

BIN
dist/iconfont.eot vendored

Binary file not shown.

BIN
dist/iconfont.eot.gz vendored

Binary file not shown.

9
dist/iconfont.svg vendored
View File

@ -41,6 +41,9 @@ Created by iconfont
<glyph glyph-name="download" unicode="&#59054;" d="M391.38165448 725.93326272l240.95928598 0 0-64.1844201-240.95928598 0 0 64.1844201ZM391.38165448 788.7264396l240.95928598 0 0-33.48092532-240.95928598 0 0 33.48092532ZM861.69471958 252.86553432999995L833.07556085 93.04951446999996 190.59307034 93.04951446999996 162.00173642 252.86553432999995 90.5339419 252.86553432999995 90.5339419-1.8628535200000442 933.85644986-1.8628535200000442 933.85644986 252.86553432999995ZM843.99050449 537.55120495L632.34094046 537.55120495 632.34094046 629.63133654 391.38165448 629.63133654 391.38165448 536.8294444 182.40918149 536.8294444 511.15260556 176.78976975Z" horiz-adv-x="1024" />
<glyph glyph-name="close" unicode="&#58960;" d="M822.00345 119.17756599999996l0.022513 0.022513L246.50423 694.6829250000001c-5.78782 5.791913-13.785981 9.374508-22.621207 9.374508-17.662265 0-31.980365-14.3181-31.980365-31.980365 0-8.834202 3.582595-16.832364 9.373485-22.620184L776.11226 74.66067599999997c5.838985-6.277984 14.166651-10.209526 23.416316-10.209526 17.662265 0 31.980365 14.3181 31.980365 31.980365C831.508941 105.33223299999997 827.871087 113.37951299999997 822.00345 119.17756599999996zM776.783549 694.551942l-0.022513 0.022513L201.278189 119.05272200000002c-5.791913-5.78782-9.374508-13.785981-9.374508-22.621207 0-17.662265 14.3181-31.980365 31.980365-31.980365 8.834202 0 16.832364 3.582595 22.620184 9.373485l574.797231 574.836117c6.277984 5.838985 10.209526 14.166651 10.209526 23.416316 0 17.662265-14.3181 31.980365-31.980365 31.980365C790.628882 704.057433 782.580578 700.41958 776.783549 694.551942z" horiz-adv-x="1024" />
<glyph glyph-name="group" unicode="&#58951;" d="M34.45656213 145.22855360000005l397.95204694 0L432.408608 622.7725376000001 34.45656213 622.7725376000001 34.45656213 145.22855360000005zM87.5167616 569.71233813l291.83055467 0 0-371.4224928-291.83055467 0L87.5167616 569.71233813zM591.58920853 622.7725376000001l0-477.543984 397.95313814 0L989.54234667 622.7725376000001 591.58920853 622.7725376000001zM936.4832384 198.28875413000003l-291.83055467 0L644.65268373 569.71233813l291.83055467 0L936.4832384 198.28875413000003zM565.0585632 808.48378347c0 29.302032-23.73088 53.06020053-53.05910827 53.06020053-29.27583573 0-53.06020053-23.75816853-53.06020053-53.06020053 0-19.63110613 10.68167893-36.75934187 26.53064533-45.93689707L485.46989973 5.454204799999957c-15.8489664-9.17755627-26.53064533-26.3068832-26.53064533-45.93689707 0-29.3031232 23.7843648-53.06020053 53.06020053-53.06020053 29.32822827 0 53.05910827 23.75816853 53.05910827 53.06020053 0 19.63983787-10.66748907 36.77571413-26.53064533 45.95108694L538.5279168 762.5326965300001C554.39107307 771.70697813 565.0585632 788.8428544 565.0585632 808.48378347z" horiz-adv-x="1024" />
@ -77,6 +80,9 @@ Created by iconfont
<glyph glyph-name="checked" unicode="&#58896;" d="M883.37066667 806.34346667H177.03786667c-43.69066667 0-80.0992-36.4096-80.0992-80.10026667V12.629333330000009c0-43.69066667 36.40853333-80.0992 80.0992-80.0992h713.61493333c43.69066667 0 80.0992 36.40853333 80.0992 80.0992V726.2432c-7.28213333 43.69066667-43.69066667 80.10026667-87.38133333 80.10026667z m29.12746666-786.432c0-14.56426667-14.56426667-29.12746667-29.12746666-29.12746667H177.03786667c-14.5632 0-29.1264 14.5632-29.1264 29.12746667V726.2432c0 14.56426667 14.5632 29.12746667 29.1264 29.12746667h713.61493333c14.5632 0 29.1264-14.5632 29.1264-29.12746667v-706.33173333h-7.28106667zM468.30933333 143.70133333c-14.5632 0-29.12746667 7.28213333-36.40853333 14.5632l-174.76266667 174.76266667c-21.84533333 21.84533333-21.84533333 58.25493333 0 80.10026667 21.84533333 21.84533333 58.25386667 21.84533333 80.0992 0l167.48053334-167.4816c21.84533333-21.84533333 21.84533333-58.25386667 0-80.0992-7.28106667-14.5632-21.84533333-21.84533333-36.40853334-21.84533334zM468.30933333 143.70133333c-14.5632 0-29.12746667 7.28213333-36.40853333 14.5632-29.12746667 29.12746667-29.12746667 58.25493333 0 80.10026667L766.86186667 580.608c21.84533333 21.84533333 58.25493333 21.84533333 80.10026666 0 21.84533333-21.84533333 21.84533333-58.25386667 0-80.0992L504.71786667 158.26453332999995c-7.28106667-7.28106667-21.84533333-14.5632-36.40853334-14.5632z" horiz-adv-x="1024" />
<glyph glyph-name="clear" unicode="&#58921;" d="M118.25 110.49999998999999h787.5v-56.25H118.25zM884.70019531 524.30664062L645.11035156 764.40624999a70.76953125 70.76953125 0 0 1-49.86914062 21.09375c-15.99609375 0-31.57910156-5.79199219-43.26855469-17.51660156L135.67871094 350.34472655c-24.609375-24.67089844-22.96582031-66.64746094 3.61230469-93.28710937L229.4140625 166.74999999h395.5078125l263.39941406 264.26953125c24.59179688 24.67089844 22.95703125 66.64746094-3.62109375 93.28710938zM601.55175781 222.99999999H252.72265625l-73.63476563 73.828125c-5.2734375 5.32617188-5.35253906 12.08496094-3.59472656 13.84277344L404.68554687 540.54003905l257.10644532-257.09765625z" horiz-adv-x="1024" />
<glyph glyph-name="ul" unicode="&#58916;" d="M149.3 746.7c47.1 0 85.3-38.2 85.3-85.3 0-47.1-38.2-85.3-85.3-85.3S64 614.2 64 661.3c0 47.2 38.2 85.4 85.3 85.4zM149.3 469.3c47.1 0 85.3-38.2 85.3-85.3s-38.2-85.3-85.3-85.3S64 336.9 64 384s38.2 85.3 85.3 85.3zM149.3 192c47.1 0 85.3-38.2 85.3-85.3 0-47.1-38.2-85.3-85.3-85.3S64 59.5 64 106.70000000000005c0 47.1 38.2 85.3 85.3 85.3zM362.7 704h554.7c23.6 0 42.7-19.1 42.7-42.7s-19.1-42.7-42.7-42.7H362.7c-23.6 0-42.7 19.1-42.7 42.7s19.1 42.7 42.7 42.7zM362.7 426.7h554.7c23.6 0 42.7-19.1 42.7-42.7s-19.1-42.7-42.7-42.7H362.7c-23.6 0-42.7 19.1-42.7 42.7s19.1 42.7 42.7 42.7zM362.7 149.29999999999995h554.7c23.6 0 42.7-19.1 42.7-42.7s-19.1-42.7-42.7-42.7H362.7c-23.6 0-42.7 19.1-42.7 42.7s19.1 42.7 42.7 42.7z" horiz-adv-x="1024" />
@ -92,6 +98,9 @@ Created by iconfont
<glyph glyph-name="ol" unicode="&#59121;" d="M349.29890773 763.63588267h542.33697494a54.23369707 54.23369707 0 0 0 0-108.4673952h-542.33697494a54.23369707 54.23369707 0 0 0 0 108.4673952z m0-325.4021856h542.33697494a54.23369707 54.23369707 0 0 0 0-108.46739414h-542.33697494a54.23369707 54.23369707 0 0 0 0 108.46739414z m0-325.40218454h542.33697494a54.23369707 54.23369707 0 0 0 0-108.4673952h-542.33697494a54.23369707 54.23369707 0 0 0 0 108.4673952zM97.1122144 760.3818602700001v25.48983786a167.03978773 167.03978773 0 0 1 24.9475008 0 35.25190293 35.25190293 0 0 1 18.43945707 10.30440214 33.08255573 33.08255573 0 0 1 7.59271786 13.55842453 31.45554453 31.45554453 0 0 1 0 7.59271787H182.801456v-189.27560427h-40.67527253V760.3818602700001z m0-420.3111552a108.4673952 108.4673952 0 0 0 37.96358827 40.6752736 279.8458784 279.8458784 0 0 1 33.6248928 26.57451093 39.59059947 39.59059947 0 0 1 11.93141333 27.65918613 30.3708704 30.3708704 0 0 1-6.50804373 20.06646827 23.86282667 23.86282667 0 0 1-19.5241312 8.13505387 23.3204896 23.3204896 0 0 1-26.03217494-12.4737504 63.45342613 63.45342613 0 0 1-4.33869546-23.3204896h-35.251904a92.7396224 92.7396224 0 0 0 8.677392 39.59059946 54.23369707 54.23369707 0 0 0 54.23369706 28.7438592 67.7921216 67.7921216 0 0 0 48.26799147-16.81244586 58.5723936 58.5723936 0 0 0 17.89712-44.471632 60.7417408 60.7417408 0 0 0-12.4737504-37.96358827 126.90685227 126.90685227 0 0 0-27.65918613-24.40516373l-15.18543467-10.8467392-19.5241312-14.64309867a42.8446208 42.8446208 0 0 1-8.677392-10.30440213h83.5198944v-33.08255574H86.80781227a90.02793813 90.02793813 0 0 0 8.67739093 37.4212512z m27.11684907-304.2510432a43.38695787 43.38695787 0 0 1 3.7963584-18.98179414 25.48983787 25.48983787 0 0 1 24.9475008-14.10076053 27.65918613 27.65918613 0 0 1 17.35478293 5.4233696 28.2015232 28.2015232 0 0 1 8.13505493 21.6934784 24.9475008 24.9475008 0 0 1-15.18543466 25.48983787 78.0965248 78.0965248 0 0 1-27.11684907 7.0503808v27.11684906a71.58848107 71.58848107 0 0 1 25.48983787 3.7963584 22.23581547 22.23581547 0 0 1 12.4737504 23.32049067 24.9475008 24.9475008 0 0 1-6.50804374 17.89712 23.3204896 23.3204896 0 0 1-17.89712 7.0503808 22.77815253 22.77815253 0 0 1-19.5241312-8.677392 35.79424 35.79424 0 0 1-5.96570666-22.77815253h-35.251904a94.90897067 94.90897067 0 0 0 4.8810336 27.116848 61.28407787 61.28407787 0 0 0 14.6430976 20.60880533 50.97967573 50.97967573 0 0 0 17.354784 10.30440213 76.4695136 76.4695136 0 0 0 24.9475008 2.71168534 66.70744747 66.70744747 0 0 0 44.47163093-14.1007616 47.18331627 47.18331627 0 0 0 16.81244693-37.96358827 42.30228373 42.30228373 0 0 0-10.3044032-28.7438592 34.16722987 34.16722987 0 0 0-13.01608746-9.76206613 27.11684907 27.11684907 0 0 0 14.64309866-8.67739094 47.18331627 47.18331627 0 0 0 14.64309867-36.33657706 61.28407787 61.28407787 0 0 0-16.81244587-42.84462187 64.53810027 64.53810027 0 0 0-49.89500266-18.43945707 60.7417408 60.7417408 0 0 0-54.23369707 26.574512 79.18119787 79.18119787 0 0 0-9.219728 36.87891414z" horiz-adv-x="1024" />
<glyph glyph-name="save" unicode="&#58952;" d="M788.69067383 752.15185547h-26.03759766v0.65917969H261.42932128v-0.65917969h-26.03759764c-50.92163086 0-92.20275879-41.19873047-92.2027588-92.12036133v-552.72216797c0-50.92163086 41.28112793-92.12036133 92.2027588-92.12036133h553.29895019c50.92163086 0 92.20275879 41.28112793 92.20275879 92.12036133V660.03149414c0 50.8392334-41.36352539 92.12036133-92.20275879 92.12036133z m-467.93518067-58.58459473H703.16210938v-118.48754882c0-21.83532715-19.03381348-39.55078125-42.51708985-39.55078125H363.272583c-23.48327637 0-42.51708984 17.71545411-42.51708983 39.55078125V693.5672607500001z m501.47094727-575.46386719c0-24.38964844-19.85778809-44.24743653-44.32983399-44.24743652H246.02099609c-24.4720459 0-44.32983398 19.77539063-44.32983398 44.24743652V649.31982422c0 24.38964844 19.85778809 44.24743653 44.32983398 44.24743653h15.32592774V568.5703125c0-50.92163086 40.78674317-92.12036133 91.1315918-92.12036133h318.96057129c50.34484864 0 91.1315918 41.28112793 91.13159179 92.12036133V693.5672607500001h15.24353027c24.4720459 0 44.32983398-19.77539063 44.32983399-44.24743653v-531.21643067zM607.58105469 568.2407226600001c16.31469727 0 29.66308594 13.34838867 29.66308593 29.66308593v32.95898438c0 16.31469727-13.34838867 29.66308594-29.66308593 29.66308594s-29.66308594-13.34838867-29.66308594-29.66308594v-32.95898438c0-16.31469727 13.34838867-29.66308594 29.66308594-29.66308593z" horiz-adv-x="1024" />
</font>

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 33 KiB

BIN
dist/iconfont.svg.gz vendored

Binary file not shown.

BIN
dist/iconfont.ttf vendored

Binary file not shown.

BIN
dist/iconfont.ttf.gz vendored

Binary file not shown.

BIN
dist/iconfont.woff vendored

Binary file not shown.

View File

@ -1,7 +1,7 @@
{
"name": "vue-meditor",
"description": "一款使用marked和highlight.js开发的一款markdown编辑器",
"version": "1.3.1",
"version": "1.4.1",
"author": "zhaoxuhui<1258835133@qq.com>",
"license": "MIT",
"main": "build/index.js",
@ -13,7 +13,10 @@
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules",
"build:npm": "cross-env NODE_ENV=npm webpack --progress --hide-modules"
"build:npm": "cross-env NODE_ENV=npm webpack --progress --hide-modules",
"analyzer": "cross-env analyzer=true NODE_ENV=npm webpack --progress --hide-modules",
"lint": "eslint --ext .js src ",
"lint:fix": "eslint --fix --ext .js src"
},
"dependencies": {
"highlight.js": "^9.12.0",
@ -31,17 +34,23 @@
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.0",
"babel-preset-stage-3": "^6.24.1",
"compression-webpack-plugin": "^1.1.11",
"cross-env": "^5.2.0",
"css-loader": "^0.28.11",
"compression-webpack-plugin": "^1.1.11",
"eslint": "^6.6.0",
"eslint-plugin-vue": "^5.2.3",
"file-loader": "^1.1.4",
"less": "^3.0.4",
"less-loader": "^4.1.0",
"vue-loader": "^13.0.5",
"vue-template-compiler": "^2.4.4",
"webpack": "^3.6.0",
"webpack-bundle-analyzer": "^3.6.0",
"webpack-dev-server": "^2.9.1"
},
"readmeFilename": "README.md",
"files":["build","README.md"]
"files": [
"build",
"README.md"
]
}

View File

@ -1,86 +1,101 @@
<template>
<div id="app">
<div class="container">
<h1>vue-markdown编辑器组件</h1>
<a target="_blank" href="https://github.com/zhaoxuhui1122/vue-markdown">使用文档</a>
<div class="content">
<mark-down @on-paste-image="handlePasteImage" @on-save="save" :theme="theme" :initialValue="initialValue" :markedOptions="{baseUrl:'http://smalleyes.oss-cn-shanghai.aliyuncs.com/'}"></mark-down>
</div>
<div id="app">
<div class="container">
<h1>vue-markdown编辑器组件</h1>
<a target="_blank" href="https://github.com/zhaoxuhui1122/vue-markdown">使用文档</a>
<div class="content">
<mark-down
@on-paste-image="handlePasteImage"
@on-save="save"
:theme="theme"
v-model="value"
@on-theme-change="onThemeChange"
:markedOptions="{baseUrl:'http://smalleyes.oss-cn-shanghai.aliyuncs.com/'}"/>
</div>
</div>
</div>
</div>
</template>
<script>
import MarkDown from './markdown/index' //
// import MarkDown from "../build"; //
// import MarkDown from 'vue-meditor';
import MarkDown from './markdown/index' //
// import MarkDown from "../build"; //
// import MarkDown from 'vue-meditor';
import doc from './doc';
export default {
name: "app",
components: {
MarkDown
},
data() {
return {
initialValue: "",
theme: 'OneDark'
};
},
methods: {
save(res) {
console.log(res);
},
handlePasteImage(res) {
console.log(res);
}
},
mounted() {
setTimeout(() => {
this.initialValue = doc;
}, 1000);
import doc from './doc';
}
};
export default {
name: "app",
components: {
MarkDown
},
data() {
return {
value: "",
theme: 'OneDark'
};
},
methods: {
save(res) {
console.log(res);
},
handlePasteImage(res) {
console.log(res);
},
onThemeChange(theme) {
console.log(theme)
}
},
mounted() {
setTimeout(() => {
this.value = doc;
}, 1000);
},
watch: {
value() {
console.log(this.value)
}
}
};
</script>
<style scoped lang="less">
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 1200px;
margin: 0 auto;
h1 {
font-size: 26px;
font-weight: 400;
margin: 12px 0;
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
a {
display: inline-block;
background-color: #f8f8f9;
border-radius: 4px;
padding: 8px 16px;
border: 1px solid #edeff0;
border-radius: 4px;
margin-bottom: 20px;
text-decoration: none;
color: #2d8cf0;
}
.container {
width: 80vw;
margin: 0 auto;
ul {
list-style: none;
}
h1 {
font-size: 26px;
font-weight: 400;
margin: 12px 0;
}
.content {
border: 1px solid #ccc;
a {
display: inline-block;
background-color: #f8f8f9;
border-radius: 4px;
padding: 8px 16px;
border: 1px solid #edeff0;
border-radius: 4px;
margin-bottom: 20px;
text-decoration: none;
color: #2d8cf0;
}
ul {
list-style: none;
}
.content {
/*border: 1px solid #ccc;*/
}
}
}
</style>

View File

@ -37,7 +37,7 @@ components:{
...
<template>
<mark-down/>
<mark-down v-model="value"/>
</template>
\`\`\`
@ -45,14 +45,16 @@ components:{
名称 | 类型|说明|默认值
---|---|---|---
initialValue|String|编辑器初始化内容
value|NumberString|输入框内的值支持数据双向绑定1.4.0新增|''
width|Number|编辑器宽度|
height|Number|编辑器高度单位 px|600
theme|String|代码块主题配置共有四个值分别为LightDarkOneDarkGitHub|Light
autoSave|Boolean|是否自动保存|true
autoSave|Boolean|是否自动保存|false
interval|Number|自动保存频率单位毫秒|10000
toolbars|Object|工具栏配置具体功能详见工具栏功能配置表
exportFileName|String|导出文件的名称|未命名文件
bordered|Boolean|是否存在边框1.4.0新增|true
isPreview|Boolean|是否是预览模式预览模式工具栏将不会显示单纯的用作展示md文件1.4.0新增|false
### 5.events
@ -60,6 +62,9 @@ exportFileName|String|导出文件的名称|未命名文件
---|---
on-save|自动保存或者手动保存时触发返回当前编辑器内原始输入内容和转以后的内容
on-paste-image|粘贴图片返回当前粘贴的file文件
on-theme-change|切换主题时触发返回当前主题名称
on-copy|复制代码后触发|返回复制的内容
### 6.工具栏配置
名称 | 说明 | 默认显示
@ -83,20 +88,23 @@ image|image|是
table |表格|
checked|已完成列表|
notChecked |未完成列表|
shift|预览|
preview|预览|
split|分屏模式切换|
print |打印|
theme|主题切换|
fullscreen |全屏|
exportmd|导出为*.md文件|
importmd|导入本地*.md文件|
save|保存按钮|
clear|清空内容|
### 7.其他说明
**关于保存时返回值**
\`\`\`
value // 编辑器输入的原始内容
html // 右侧现实的问转义后的内容
theme // 保存时的主题名字
{
value, // 编辑器输入的原始内容
theme, // 保存时的主题名字
}
\`\`\`
**标题配置**
@ -125,6 +133,13 @@ const config = {
### 更新日志
**1.4.0**
- 支持输入值双向数据绑定
- 支持预览模式
- 支持复制代码块
- 工具栏增加增加清空内容保存分屏预览功能
**1.3.0**
- 支持配置marked的markedOptions感谢[dkvirus](https://github.com/dkvirus)提出的[issues#12](https://github.com/zhaoxuhui1122/vue-markdown/issues/12)和具体的解决办法
@ -159,5 +174,4 @@ const config = {
- 修复主题无法更新的问题
- 修复文档初始化值无法动态切换的问题
`

View File

@ -5,129 +5,134 @@
// Dark
.Dark {
pre {
display: block;
padding: 20px !important;
border-radius: 4px;
margin: 20px 0 !important;
background: #1e1e1e;
color: #DCDCDC;
overflow-y: hidden !important;
overflow-x: auto !important;
font-family: Menlo, Consolas, "Courier New", Courier, FreeMono, monospace !important;
* {
line-height: 1.6 !important;
font-size: 14px;
font-family: Menlo, Consolas, "Courier New", Courier, FreeMono, monospace !important;
pre {
display: block;
padding: 15px 20px !important;
border-radius: 4px;
margin: 20px 0 !important;
background: #1e1e1e;
color: #DCDCDC;
overflow-y: hidden !important;
overflow-x: auto !important;
font-family: Menlo, Consolas, "Courier New", Courier, FreeMono, monospace !important;
* {
line-height: 1.6 !important;
font-size: 14px;
font-family: Menlo, Consolas, "Courier New", Courier, FreeMono, monospace !important;
}
}
code {
padding: 0 !important;
margin: 0 !important;
}
}
code {
padding: 0 !important;
margin: 0 !important;
}
.hljs-literal,
.hljs-name,
.hljs-symbol {
color: #659bd1;
}
.hljs-keyword{
color: #bc89bd;
}
.hljs-link {
color: #569CD6;
text-decoration: underline;
}
.hljs-literal,
.hljs-name,
.hljs-symbol {
color: #659bd1;
}
.hljs-built_in,
.hljs-type {
color: #4EC9B0;
}
.hljs-keyword {
color: #bc89bd;
}
.hljs-class,
.hljs-number {
color: #B8D7A3;
}
.hljs-link {
color: #569CD6;
text-decoration: underline;
}
.hljs-meta-string,
.hljs-string {
color: #D69D85;
}
.hljs-built_in,
.hljs-type {
color: #4EC9B0;
}
.hljs-regexp,
.hljs-template-tag {
color: #9A5334;
}
.hljs-class,
.hljs-number {
color: #B8D7A3;
}
.hljs-formula,
.hljs-function,
.hljs-params,
.hljs-subst,
.hljs-title {
color: #DCDCDC;
}
.hljs-meta-string,
.hljs-string {
color: #D69D85;
}
.hljs-comment,
.hljs-quote {
color: #57A64A;
font-style: italic;
}
.hljs-regexp,
.hljs-template-tag {
color: #9A5334;
}
.hljs-doctag {
color: #608B4E;
}
.hljs-formula,
.hljs-function,
.hljs-params,
.hljs-subst,
.hljs-title {
color: #DCDCDC;
}
.hljs-meta,
.hljs-meta-keyword,
.hljs-tag {
color: #9B9B9B;
}
.hljs-comment,
.hljs-quote {
color: #57A64A;
font-style: italic;
}
.hljs-template-variable,
.hljs-variable {
color: #BD63C5;
}
.hljs-doctag {
color: #608B4E;
}
.hljs-attr,
.hljs-attribute,
.hljs-builtin-name {
color: #9CDCFE;
}
.hljs-meta,
.hljs-meta-keyword,
.hljs-tag {
color: #9B9B9B;
}
.hljs-section {
color: gold;
}
.hljs-template-variable,
.hljs-variable {
color: #BD63C5;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-attr,
.hljs-attribute,
.hljs-builtin-name {
color: #9CDCFE;
}
.hljs-strong {
font-weight: bold;
}
.hljs-section {
color: gold;
}
.hljs-bullet,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id,
.hljs-selector-pseudo,
.hljs-selector-tag {
color: #D7BA7D;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-addition {
background-color: #144212;
display: inline-block;
width: 100%;
}
.hljs-strong {
font-weight: bold;
}
.hljs-deletion {
background-color: #600;
display: inline-block;
width: 100%;
}
.hljs-comment{
font-style: normal;
}
.hljs-bullet,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id,
.hljs-selector-pseudo,
.hljs-selector-tag {
color: #D7BA7D;
}
.hljs-addition {
background-color: #144212;
display: inline-block;
width: 100%;
}
.hljs-deletion {
background-color: #600;
display: inline-block;
width: 100%;
}
.hljs-comment {
font-style: normal;
}
}

View File

@ -5,8 +5,8 @@
// gitHub 风格
.GitHub {
pre {
padding: 20px 20px 30px !important;
display: block;
padding:15px 20px!important;
display: block;
overflow-x: auto;
color: #333;
background: #f7f8fa !important;

File diff suppressed because one or more lines are too long

View File

@ -4,107 +4,129 @@
*/
// 默认风格
.Light {
pre {
font-size: 14px !important;
line-height: 1.6 !important;
word-break: break-all;
word-wrap: break-word;
border: 0 !important;
border-radius: 0 !important;
background: #f7f8fb !important;
padding: 20px !important;
border-radius: 4px !important;
overflow-y: hidden !important;
overflow-x: auto !important;
margin: 20px 0 !important;
code {
line-height: @line-height !important;
font-family: Consolas !important;
font-size: 13px;
line-height: @line-height !important;
color: #444;
pre {
font-size: 14px !important;
line-height: 1.6 !important;
word-break: break-all;
word-wrap: break-word;
border: 0 !important;
border-radius: 0 !important;
background: #f7f8fb !important;
padding: 15px 20px !important;
border-radius: 4px !important;
overflow-y: hidden !important;
overflow-x: auto !important;
margin: 20px 0 !important;
code {
line-height: @line-height !important;
font-family: Consolas !important;
font-size: 13px;
line-height: @line-height !important;
color: #444;
}
}
* {
-webkit-font-smoothing: antialiased;
}
.hljs {
display: block;
overflow-x: auto;
color: #525252;
padding: 15px;
-webkit-text-size-adjust: none;
}
.hljs-doctype {
color: #999;
}
.hljs-tag {
color: #3e76f6;
}
.hljs-attribute {
color: #e96900;
}
.hljs-value {
color: #42b983;
}
.hljs-keyword {
color: #e96900;
}
.hljs-string {
color: #42b983;
}
.hljs-comment {
color: #b3b3b3;
}
.hljs-operator .hljs-comment {
color: #525252;
}
.hljs-regexp {
color: #af7dff;
}
.hljs-built_in {
color: #2db7f5;
}
.css .hljs-class {
color: #e96900;
}
.css .hljs-number,
.javascript .hljs-number {
color: #fc1e70;
}
.css .hljs-attribute {
color: #af7dff;
}
.css .hljs-important {
color: red;
}
.actionscript .hljs-literal,
.javascript .hljs-literal {
color: #fc1e70;
}
pre {
padding: 0;
margin: 0;
background: @background !important;
}
code {
display: inline-block;
background: #f7f7f7;
font-family: Consolas, Monaco, Andale Mono, Ubuntu Mono, monospace;
margin: 0 3px;
padding: 1px 5px;
border-radius: 3px;
color: #666;
border: 1px solid #eee;
}
pre code {
display: inline;
margin: 0;
padding: 0;
border: none;
background: transparent;
}
pre.bg code {
background: #f7f7f7;
}
}
* {
-webkit-font-smoothing: antialiased;
}
.hljs {
display: block;
overflow-x: auto;
color: #525252;
padding: 15px;
-webkit-text-size-adjust: none;
}
.hljs-doctype {
color: #999;
}
.hljs-tag {
color: #3e76f6;
}
.hljs-attribute {
color: #e96900;
}
.hljs-value {
color: #42b983;
}
.hljs-keyword {
color: #e96900;
}
.hljs-string {
color: #42b983;
}
.hljs-comment {
color: #b3b3b3;
}
.hljs-operator .hljs-comment {
color: #525252;
}
.hljs-regexp {
color: #af7dff;
}
.hljs-built_in {
color: #2db7f5;
}
.css .hljs-class {
color: #e96900;
}
.css .hljs-number,
.javascript .hljs-number {
color: #fc1e70;
}
.css .hljs-attribute {
color: #af7dff;
}
.css .hljs-important {
color: red;
}
.actionscript .hljs-literal,
.javascript .hljs-literal {
color: #fc1e70;
}
pre {
padding: 0;
margin: 0;
background: @background !important;
}
code {
display: inline-block;
background: #f7f7f7;
font-family: Consolas, Monaco, Andale Mono, Ubuntu Mono, monospace;
margin: 0 3px;
padding: 1px 5px;
border-radius: 3px;
color: #666;
border: 1px solid #eee;
}
pre code {
display: inline;
margin: 0;
padding: 0;
border: none;
background: transparent;
}
pre.bg code {
background: #f7f7f7;
}
}

View File

@ -4,7 +4,7 @@
*/
.OneDark {
pre {
padding: 20px 20px 30px !important;
padding:15px 20px!important;
display: block;
color: #abb2bf;
font-family: Menlo, Consolas, "Courier New", Courier, FreeMono, monospace;

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -41,6 +41,9 @@ Created by iconfont
<glyph glyph-name="download" unicode="&#59054;" d="M391.38165448 725.93326272l240.95928598 0 0-64.1844201-240.95928598 0 0 64.1844201ZM391.38165448 788.7264396l240.95928598 0 0-33.48092532-240.95928598 0 0 33.48092532ZM861.69471958 252.86553432999995L833.07556085 93.04951446999996 190.59307034 93.04951446999996 162.00173642 252.86553432999995 90.5339419 252.86553432999995 90.5339419-1.8628535200000442 933.85644986-1.8628535200000442 933.85644986 252.86553432999995ZM843.99050449 537.55120495L632.34094046 537.55120495 632.34094046 629.63133654 391.38165448 629.63133654 391.38165448 536.8294444 182.40918149 536.8294444 511.15260556 176.78976975Z" horiz-adv-x="1024" />
<glyph glyph-name="close" unicode="&#58960;" d="M822.00345 119.17756599999996l0.022513 0.022513L246.50423 694.6829250000001c-5.78782 5.791913-13.785981 9.374508-22.621207 9.374508-17.662265 0-31.980365-14.3181-31.980365-31.980365 0-8.834202 3.582595-16.832364 9.373485-22.620184L776.11226 74.66067599999997c5.838985-6.277984 14.166651-10.209526 23.416316-10.209526 17.662265 0 31.980365 14.3181 31.980365 31.980365C831.508941 105.33223299999997 827.871087 113.37951299999997 822.00345 119.17756599999996zM776.783549 694.551942l-0.022513 0.022513L201.278189 119.05272200000002c-5.791913-5.78782-9.374508-13.785981-9.374508-22.621207 0-17.662265 14.3181-31.980365 31.980365-31.980365 8.834202 0 16.832364 3.582595 22.620184 9.373485l574.797231 574.836117c6.277984 5.838985 10.209526 14.166651 10.209526 23.416316 0 17.662265-14.3181 31.980365-31.980365 31.980365C790.628882 704.057433 782.580578 700.41958 776.783549 694.551942z" horiz-adv-x="1024" />
<glyph glyph-name="group" unicode="&#58951;" d="M34.45656213 145.22855360000005l397.95204694 0L432.408608 622.7725376000001 34.45656213 622.7725376000001 34.45656213 145.22855360000005zM87.5167616 569.71233813l291.83055467 0 0-371.4224928-291.83055467 0L87.5167616 569.71233813zM591.58920853 622.7725376000001l0-477.543984 397.95313814 0L989.54234667 622.7725376000001 591.58920853 622.7725376000001zM936.4832384 198.28875413000003l-291.83055467 0L644.65268373 569.71233813l291.83055467 0L936.4832384 198.28875413000003zM565.0585632 808.48378347c0 29.302032-23.73088 53.06020053-53.05910827 53.06020053-29.27583573 0-53.06020053-23.75816853-53.06020053-53.06020053 0-19.63110613 10.68167893-36.75934187 26.53064533-45.93689707L485.46989973 5.454204799999957c-15.8489664-9.17755627-26.53064533-26.3068832-26.53064533-45.93689707 0-29.3031232 23.7843648-53.06020053 53.06020053-53.06020053 29.32822827 0 53.05910827 23.75816853 53.05910827 53.06020053 0 19.63983787-10.66748907 36.77571413-26.53064533 45.95108694L538.5279168 762.5326965300001C554.39107307 771.70697813 565.0585632 788.8428544 565.0585632 808.48378347z" horiz-adv-x="1024" />
@ -77,6 +80,9 @@ Created by iconfont
<glyph glyph-name="checked" unicode="&#58896;" d="M883.37066667 806.34346667H177.03786667c-43.69066667 0-80.0992-36.4096-80.0992-80.10026667V12.629333330000009c0-43.69066667 36.40853333-80.0992 80.0992-80.0992h713.61493333c43.69066667 0 80.0992 36.40853333 80.0992 80.0992V726.2432c-7.28213333 43.69066667-43.69066667 80.10026667-87.38133333 80.10026667z m29.12746666-786.432c0-14.56426667-14.56426667-29.12746667-29.12746666-29.12746667H177.03786667c-14.5632 0-29.1264 14.5632-29.1264 29.12746667V726.2432c0 14.56426667 14.5632 29.12746667 29.1264 29.12746667h713.61493333c14.5632 0 29.1264-14.5632 29.1264-29.12746667v-706.33173333h-7.28106667zM468.30933333 143.70133333c-14.5632 0-29.12746667 7.28213333-36.40853333 14.5632l-174.76266667 174.76266667c-21.84533333 21.84533333-21.84533333 58.25493333 0 80.10026667 21.84533333 21.84533333 58.25386667 21.84533333 80.0992 0l167.48053334-167.4816c21.84533333-21.84533333 21.84533333-58.25386667 0-80.0992-7.28106667-14.5632-21.84533333-21.84533333-36.40853334-21.84533334zM468.30933333 143.70133333c-14.5632 0-29.12746667 7.28213333-36.40853333 14.5632-29.12746667 29.12746667-29.12746667 58.25493333 0 80.10026667L766.86186667 580.608c21.84533333 21.84533333 58.25493333 21.84533333 80.10026666 0 21.84533333-21.84533333 21.84533333-58.25386667 0-80.0992L504.71786667 158.26453332999995c-7.28106667-7.28106667-21.84533333-14.5632-36.40853334-14.5632z" horiz-adv-x="1024" />
<glyph glyph-name="clear" unicode="&#58921;" d="M118.25 110.49999998999999h787.5v-56.25H118.25zM884.70019531 524.30664062L645.11035156 764.40624999a70.76953125 70.76953125 0 0 1-49.86914062 21.09375c-15.99609375 0-31.57910156-5.79199219-43.26855469-17.51660156L135.67871094 350.34472655c-24.609375-24.67089844-22.96582031-66.64746094 3.61230469-93.28710937L229.4140625 166.74999999h395.5078125l263.39941406 264.26953125c24.59179688 24.67089844 22.95703125 66.64746094-3.62109375 93.28710938zM601.55175781 222.99999999H252.72265625l-73.63476563 73.828125c-5.2734375 5.32617188-5.35253906 12.08496094-3.59472656 13.84277344L404.68554687 540.54003905l257.10644532-257.09765625z" horiz-adv-x="1024" />
<glyph glyph-name="ul" unicode="&#58916;" d="M149.3 746.7c47.1 0 85.3-38.2 85.3-85.3 0-47.1-38.2-85.3-85.3-85.3S64 614.2 64 661.3c0 47.2 38.2 85.4 85.3 85.4zM149.3 469.3c47.1 0 85.3-38.2 85.3-85.3s-38.2-85.3-85.3-85.3S64 336.9 64 384s38.2 85.3 85.3 85.3zM149.3 192c47.1 0 85.3-38.2 85.3-85.3 0-47.1-38.2-85.3-85.3-85.3S64 59.5 64 106.70000000000005c0 47.1 38.2 85.3 85.3 85.3zM362.7 704h554.7c23.6 0 42.7-19.1 42.7-42.7s-19.1-42.7-42.7-42.7H362.7c-23.6 0-42.7 19.1-42.7 42.7s19.1 42.7 42.7 42.7zM362.7 426.7h554.7c23.6 0 42.7-19.1 42.7-42.7s-19.1-42.7-42.7-42.7H362.7c-23.6 0-42.7 19.1-42.7 42.7s19.1 42.7 42.7 42.7zM362.7 149.29999999999995h554.7c23.6 0 42.7-19.1 42.7-42.7s-19.1-42.7-42.7-42.7H362.7c-23.6 0-42.7 19.1-42.7 42.7s19.1 42.7 42.7 42.7z" horiz-adv-x="1024" />
@ -92,6 +98,9 @@ Created by iconfont
<glyph glyph-name="ol" unicode="&#59121;" d="M349.29890773 763.63588267h542.33697494a54.23369707 54.23369707 0 0 0 0-108.4673952h-542.33697494a54.23369707 54.23369707 0 0 0 0 108.4673952z m0-325.4021856h542.33697494a54.23369707 54.23369707 0 0 0 0-108.46739414h-542.33697494a54.23369707 54.23369707 0 0 0 0 108.46739414z m0-325.40218454h542.33697494a54.23369707 54.23369707 0 0 0 0-108.4673952h-542.33697494a54.23369707 54.23369707 0 0 0 0 108.4673952zM97.1122144 760.3818602700001v25.48983786a167.03978773 167.03978773 0 0 1 24.9475008 0 35.25190293 35.25190293 0 0 1 18.43945707 10.30440214 33.08255573 33.08255573 0 0 1 7.59271786 13.55842453 31.45554453 31.45554453 0 0 1 0 7.59271787H182.801456v-189.27560427h-40.67527253V760.3818602700001z m0-420.3111552a108.4673952 108.4673952 0 0 0 37.96358827 40.6752736 279.8458784 279.8458784 0 0 1 33.6248928 26.57451093 39.59059947 39.59059947 0 0 1 11.93141333 27.65918613 30.3708704 30.3708704 0 0 1-6.50804373 20.06646827 23.86282667 23.86282667 0 0 1-19.5241312 8.13505387 23.3204896 23.3204896 0 0 1-26.03217494-12.4737504 63.45342613 63.45342613 0 0 1-4.33869546-23.3204896h-35.251904a92.7396224 92.7396224 0 0 0 8.677392 39.59059946 54.23369707 54.23369707 0 0 0 54.23369706 28.7438592 67.7921216 67.7921216 0 0 0 48.26799147-16.81244586 58.5723936 58.5723936 0 0 0 17.89712-44.471632 60.7417408 60.7417408 0 0 0-12.4737504-37.96358827 126.90685227 126.90685227 0 0 0-27.65918613-24.40516373l-15.18543467-10.8467392-19.5241312-14.64309867a42.8446208 42.8446208 0 0 1-8.677392-10.30440213h83.5198944v-33.08255574H86.80781227a90.02793813 90.02793813 0 0 0 8.67739093 37.4212512z m27.11684907-304.2510432a43.38695787 43.38695787 0 0 1 3.7963584-18.98179414 25.48983787 25.48983787 0 0 1 24.9475008-14.10076053 27.65918613 27.65918613 0 0 1 17.35478293 5.4233696 28.2015232 28.2015232 0 0 1 8.13505493 21.6934784 24.9475008 24.9475008 0 0 1-15.18543466 25.48983787 78.0965248 78.0965248 0 0 1-27.11684907 7.0503808v27.11684906a71.58848107 71.58848107 0 0 1 25.48983787 3.7963584 22.23581547 22.23581547 0 0 1 12.4737504 23.32049067 24.9475008 24.9475008 0 0 1-6.50804374 17.89712 23.3204896 23.3204896 0 0 1-17.89712 7.0503808 22.77815253 22.77815253 0 0 1-19.5241312-8.677392 35.79424 35.79424 0 0 1-5.96570666-22.77815253h-35.251904a94.90897067 94.90897067 0 0 0 4.8810336 27.116848 61.28407787 61.28407787 0 0 0 14.6430976 20.60880533 50.97967573 50.97967573 0 0 0 17.354784 10.30440213 76.4695136 76.4695136 0 0 0 24.9475008 2.71168534 66.70744747 66.70744747 0 0 0 44.47163093-14.1007616 47.18331627 47.18331627 0 0 0 16.81244693-37.96358827 42.30228373 42.30228373 0 0 0-10.3044032-28.7438592 34.16722987 34.16722987 0 0 0-13.01608746-9.76206613 27.11684907 27.11684907 0 0 0 14.64309866-8.67739094 47.18331627 47.18331627 0 0 0 14.64309867-36.33657706 61.28407787 61.28407787 0 0 0-16.81244587-42.84462187 64.53810027 64.53810027 0 0 0-49.89500266-18.43945707 60.7417408 60.7417408 0 0 0-54.23369707 26.574512 79.18119787 79.18119787 0 0 0-9.219728 36.87891414z" horiz-adv-x="1024" />
<glyph glyph-name="save" unicode="&#58952;" d="M788.69067383 752.15185547h-26.03759766v0.65917969H261.42932128v-0.65917969h-26.03759764c-50.92163086 0-92.20275879-41.19873047-92.2027588-92.12036133v-552.72216797c0-50.92163086 41.28112793-92.12036133 92.2027588-92.12036133h553.29895019c50.92163086 0 92.20275879 41.28112793 92.20275879 92.12036133V660.03149414c0 50.8392334-41.36352539 92.12036133-92.20275879 92.12036133z m-467.93518067-58.58459473H703.16210938v-118.48754882c0-21.83532715-19.03381348-39.55078125-42.51708985-39.55078125H363.272583c-23.48327637 0-42.51708984 17.71545411-42.51708983 39.55078125V693.5672607500001z m501.47094727-575.46386719c0-24.38964844-19.85778809-44.24743653-44.32983399-44.24743652H246.02099609c-24.4720459 0-44.32983398 19.77539063-44.32983398 44.24743652V649.31982422c0 24.38964844 19.85778809 44.24743653 44.32983398 44.24743653h15.32592774V568.5703125c0-50.92163086 40.78674317-92.12036133 91.1315918-92.12036133h318.96057129c50.34484864 0 91.1315918 41.28112793 91.13159179 92.12036133V693.5672607500001h15.24353027c24.4720459 0 44.32983398-19.77539063 44.32983399-44.24743653v-531.21643067zM607.58105469 568.2407226600001c16.31469727 0 29.66308594 13.34838867 29.66308593 29.66308593v32.95898438c0 16.31469727-13.34838867 29.66308594-29.66308593 29.66308594s-29.66308594-13.34838867-29.66308594-29.66308594v-32.95898438c0-16.31469727 13.34838867-29.66308594 29.66308594-29.66308593z" horiz-adv-x="1024" />
</font>

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,160 +1,172 @@
<template lang="html">
<div
:class="isFullscreen?'markdown fullscreen':'markdown' "
ref="markdown"
:style="{width:editorWidth+'px',height:editorHeight+'px'}"
>
<!-- 头部工具栏 -->
<ul class="markdown-toolbars">
<li><slot name="title"/></li>
<li v-if="tools.strong" name="粗体">
<span @click="insertStrong" class="iconfont icon-strong"></span>
</li>
<li v-if="tools.italic" name="斜体">
<span @click="insertItalic" class="iconfont icon-italic"></span>
</li>
<li v-if="tools.overline" name="删除线">
<span @click="insertOverline" class="iconfont icon-overline"></span>
</li>
<li v-if="tools.h1" name="标题1">
<span style="font-size: 16px;" @click="insertTitle(1)">h1</span>
</li>
<li v-if="tools.h2" name="标题2">
<span style="font-size: 16px;" @click="insertTitle(2)">h2</span>
</li>
<li v-if="tools.h3" name="标题3">
<span style="font-size: 16px;" @click="insertTitle(3)">h3</span>
</li>
<li v-if="tools.h4" name="标题4">
<span style="font-size: 16px;" @click="insertTitle(4)">h4</span>
</li>
<li v-if="tools.h5" name="标题5">
<span style="font-size: 16px;" @click="insertTitle(5)">h5</span>
</li>
<li v-if="tools.h6" name="标题6">
<span style="font-size: 16px;" @click="insertTitle(6)">h6</span>
</li>
<li v-if="tools.hr" name="分割线">
<span @click="insertLine" class="iconfont icon-horizontal"></span>
</li>
<li v-if="tools.quote" name="引用">
<span style="font-size: 16px;" @click="insertQuote" class="iconfont icon-quote"></span>
</li>
<li v-if="tools.ul" name="无序列表">
<span @click="insertUl" class="iconfont icon-ul"></span>
</li>
<li v-if="tools.ol" name="有序列表">
<span @click="insertOl" class="iconfont icon-ol"></span>
</li>
<li v-if="tools.code" name="代码块">
<span @click="insertCode" class="iconfont icon-code"></span>
</li>
<li v-if="tools.notChecked" name="未完成列表">
<span @click="insertNotFinished" class="iconfont icon-checked-false"></span>
</li>
<li v-if="tools.checked" name="已完成列表">
<span @click="insertFinished" class="iconfont icon-checked"></span>
</li>
<li v-if="tools.link" name="链接">
<span @click="insertLink" class="iconfont icon-link"></span>
</li>
<li v-if="tools.image" name="图片">
<span @click="insertImage" class="iconfont icon-img"></span>
</li>
<li v-if="tools.table" name="表格">
<span @click="insertTable" class="iconfont icon-table"></span>
</li>
<li v-if="tools.print" name="打印">
<span class="iconfont icon-dayin" @click="print"></span>
</li>
<li v-if="tools.theme" class="shift-theme" name="代码块主题">
<div>
<span class="iconfont icon-yanse" @click="themeSlideDown=!themeSlideDown"></span>
<ul :class="{active:themeSlideDown}" @mouseleave="themeSlideDown=false">
<li @click="setThemes('Light')">Light</li>
<li @click="setThemes('Dark')">VS Code</li>
<li @click="setThemes('OneDark')">Atom OneDark</li>
<li @click="setThemes('GitHub')">GitHub</li>
</ul>
</div>
</li>
<li name="导入本地文件" class="import-file" v-show="tools.importmd">
<span class="iconfont icon-daoru" @click="importFile"></span>
<input type="file" @change="importFile($event)" accept="text/markdown">
</li>
<li name="保存到本地" v-show="tools.exportmd">
<span class="iconfont icon-download" @click="exportMd"></span>
</li>
<li v-if="tools.shift&&preview==2" name="全屏编辑">
<span @click="preview=3" class="iconfont icon-md"></span>
</li>
<li v-if="tools.shift&&preview==3" name="分屏显示">
<span @click="preview=1" class="iconfont icon-group"></span>
</li>
<li v-if="tools.shift&&preview==1" name="预览">
<span @click="preview=2" class="iconfont icon-preview"></span>
</li>
<li :name="scrolling?'同步滚动:开':'同步滚动:关'">
<span @click="scrolling=!scrolling" v-show="scrolling" class="iconfont icon-on"></span>
<span @click="scrolling=!scrolling" v-show="!scrolling" class="iconfont icon-off"></span>
</li>
<li class="empty"></li>
<div :class="`markdown ${fullscreen?'fullscreen':'' } ${bordered?'border':''}`"
ref="markdown"
:style="{width:editorWidth+'px',height:editorHeight+'px'}">
<!-- 头部工具栏 -->
<ul class="markdown-toolbars" v-show="!preview">
<li>
<slot name="title"/>
</li>
<li v-if="tools.strong" name="粗体">
<span @click="insertStrong" class="iconfont icon-strong"></span>
</li>
<li v-if="tools.italic" name="斜体">
<span @click="insertItalic" class="iconfont icon-italic"></span>
</li>
<li v-if="tools.overline" name="删除线">
<span @click="insertOverline" class="iconfont icon-overline"></span>
</li>
<li v-if="tools.h1" name="标题1">
<span style="font-size: 16px;" @click="insertTitle(1)">h1</span>
</li>
<li v-if="tools.h2" name="标题2">
<span style="font-size: 16px;" @click="insertTitle(2)">h2</span>
</li>
<li v-if="tools.h3" name="标题3">
<span style="font-size: 16px;" @click="insertTitle(3)">h3</span>
</li>
<li v-if="tools.h4" name="标题4">
<span style="font-size: 16px;" @click="insertTitle(4)">h4</span>
</li>
<li v-if="tools.h5" name="标题5">
<span style="font-size: 16px;" @click="insertTitle(5)">h5</span>
</li>
<li v-if="tools.h6" name="标题6">
<span style="font-size: 16px;" @click="insertTitle(6)">h6</span>
</li>
<li v-if="tools.hr" name="分割线">
<span @click="insertLine" class="iconfont icon-horizontal"></span>
</li>
<li v-if="tools.quote" name="引用">
<span style="font-size: 16px;" @click="insertQuote" class="iconfont icon-quote"></span>
</li>
<li v-if="tools.ul" name="无序列表">
<span @click="insertUl" class="iconfont icon-ul"></span>
</li>
<li v-if="tools.ol" name="有序列表">
<span @click="insertOl" class="iconfont icon-ol"></span>
</li>
<li v-if="tools.code" name="代码块">
<span @click="insertCode" class="iconfont icon-code"></span>
</li>
<li v-if="tools.notChecked" name="未完成列表">
<span @click="insertNotFinished" class="iconfont icon-checked-false"></span>
</li>
<li v-if="tools.checked" name="已完成列表">
<span @click="insertFinished" class="iconfont icon-checked"></span>
</li>
<li v-if="tools.link" name="链接">
<span @click="insertLink" class="iconfont icon-link"></span>
</li>
<li v-if="tools.image" name="图片">
<span @click="insertImage" class="iconfont icon-img"></span>
</li>
<li v-if="tools.table" name="表格">
<span @click="insertTable" class="iconfont icon-table"></span>
</li>
<li v-if="tools.print" name="打印">
<span class="iconfont icon-dayin" @click="print"></span>
</li>
<li v-if="tools.theme" class="shift-theme" name="代码块主题">
<div>
<span class="iconfont icon-yanse" @click="themeSlideDown=!themeSlideDown"></span>
<ul :class="{active:themeSlideDown}" @mouseleave="themeSlideDown=false">
<li @click="setThemes('Light')">Light</li>
<li @click="setThemes('Dark')">VS Code</li>
<li @click="setThemes('OneDark')">Atom OneDark</li>
<li @click="setThemes('GitHub')">GitHub</li>
</ul>
</div>
</li>
<li name="导入本地文件" class="import-file" v-show="tools.importmd">
<span class="iconfont icon-daoru" @click="importFile"></span>
<input type="file" @change="importFile($event)" accept="text/markdown">
</li>
<li name="保存到本地" v-show="tools.exportmd">
<span class="iconfont icon-download" @click="exportMd"></span>
</li>
<li v-if="tools.split&&split" name="全屏编辑">
<span @click="split=false" class="iconfont icon-md"></span>
</li>
<li v-if="tools.split&&!split" name="分屏显示">
<span @click="split=true" class="iconfont icon-group"></span>
</li>
<li v-if="tools.preview" name="预览">
<span @click="preview=true" class="iconfont icon-preview"></span>
</li>
<li v-if="tools.clear" name="清空" @click="value=''">
<span class="iconfont icon-clear"></span>
</li>
<li v-if="tools.save" name="保存" @click="value=''">
<span class="iconfont icon-save"></span>
</li>
<li :name="scrolling?'同步滚动:开':'同步滚动:关'">
<span @click="scrolling=!scrolling" v-show="scrolling" class="iconfont icon-on"></span>
<span @click="scrolling=!scrolling" v-show="!scrolling" class="iconfont icon-off"></span>
</li>
<li class="empty"></li>
<li v-if="tools.fullscreen&&!isFullscreen" name="全屏">
<span @click="isFullscreen=!isFullscreen" class="iconfont icon-full-screen"></span>
</li>
<li v-if="tools.fullscreen&&isFullscreen" name="退出全屏">
<span @click="isFullscreen=!isFullscreen" class="iconfont icon-exit-full-screen"></span>
</li>
</ul>
<!-- 编辑器 -->
<div class="markdown-content" :style="{background:preview==2?'#fff':''}">
<div v-show="preview===1||preview===3" class="markdown-editor" ref="markdownContent"
@scroll="markdownScroll"
@mouseenter="mousescrollSide('markdown')">
<ul class="index" ref="index" :style="{height:scrollHeight?`${scrollHeight}px`:'100%'}">
<li v-for="(item,index) in indexLenth">{{index+1}}</li>
<li v-if="tools.fullscreen&&!fullscreen" name="全屏">
<span @click="fullscreen=!fullscreen" class="iconfont icon-full-screen"></span>
</li>
<li v-if="tools.fullscreen&&fullscreen" name="退出全屏">
<span @click="fullscreen=!fullscreen" class="iconfont icon-exit-full-screen"></span>
</li>
</ul>
<textarea
v-model="value"
@keydown.tab="tab"
@keyup.enter="enter"
@keyup.delete="onDelete"
ref="textarea"
:style="{height:scrollHeight?`${scrollHeight}px`:'100%'}"
></textarea>
</div>
<div v-show="preview==1" class="empty" style="width:12px;"></div>
<div
v-show="preview===1||preview===2"
:class="`markdown-preview ${themeName}`"
ref="preview"
@scroll="previewScroll"
@mouseenter="mousescrollSide('preview')">
<div v-html="html"
ref="previewInner" ></div>
</div>
<!-- 关闭预览按钮 -->
<div class="close-preview" v-show="preview&&!isPreview" @click="preview=false">
<span class="iconfont icon-close"></span>
</div>
<!-- 编辑器 -->
<div class="markdown-content" :style="{background:preview?'#fff':''}">
<div
v-show="!preview"
class="markdown-editor"
ref="markdownContent"
@scroll="markdownScroll"
@mouseenter="mousescrollSide('markdown')">
<ul class="index" ref="index" :style="{height:scrollHeight?`${scrollHeight}px`:'100%'}">
<li v-for="(item,index) in indexLenth">{{index+1}}</li>
</ul>
<textarea
v-model="currentValue"
@keydown.tab="tab"
@keyup.enter="enter"
@keyup.delete="onDelete"
ref="textarea"
:style="{height:scrollHeight?`${scrollHeight}px`:'100%'}"></textarea>
</div>
<div v-show="!preview&&split" class="empty"></div>
<div v-show="preview?preview:split"
:class="`markdown-preview ${themeName}`"
ref="preview"
@scroll="previewScroll"
@mouseenter="mousescrollSide('preview')">
<div v-html="html" ref="previewInner"></div>
</div>
</div>
<!-- 预览图片-->
<div :class="['preview-img',previewImgModal?'active':'']">
<span class="close icon-close iconfont" @click="previewImgModal=false"></span>
<img :src="previewImgSrc" :class="[previewImgMode]" alt="">
</div>
</div>
<!-- 预览图片-->
<div :class="['preview-img',previewImgModal?'active':'']">
<span class="close" @click="previewImgModal=false">关闭</span>
<img :src="previewImgSrc" :class="[previewImgMode]" alt="">
</div>
</div>
</template>
<script>
import markdown from './markdown';
import markdown from './markdown';
export default markdown;
export default markdown;
</script>
<style lang="less">
@import "font/iconfont.css";
@import "./css/theme";
@import "css/light";
@import "css/dark";
@import "css/one-dark";
@import "css/gitHub";
@import "css/index";
@import "font/iconfont.css";
@import "./css/theme";
@import "css/light";
@import "css/dark";
@import "css/one-dark";
@import "css/gitHub";
@import "css/index";
</style>

View File

@ -2,29 +2,32 @@
* 默认头部菜单配置
* */
export default {
strong : true,
italic : true,
overline : true,
h1 : true,
h2 : true,
h3 : true,
h4 : false,
h5 : false,
h6 : false,
hr : true,
quote : true,
ul : true,
ol : true,
code : true,
link : true,
image : true,
table : true,
checked : true,
notChecked : true,
shift : true,
fullscreen : true,
print : false,
theme : true,
exportmd : true,
importmd : true
strong: true,
italic: true,
overline: true,
h1: true,
h2: true,
h3: true,
h4: false,
h5: false,
h6: false,
hr: true,
quote: true,
ul: true,
ol: true,
code: true,
link: true,
image: true,
table: true,
checked: true,
notChecked: true,
split: true,
preview: true,
fullscreen: true,
print: false,
theme: true,
exportmd: true,
importmd: true,
save: false,
clear: false
}

View File

@ -1,7 +1,7 @@
import hljs from './js/hljs';
import marked from 'marked';
import {
saveFile
saveFile
} from "./js/utils";
import defaultTools from './js/tools';
@ -9,478 +9,498 @@ hljs.initHighlightingOnLoad();
const renderer = new marked.Renderer();
marked.setOptions({
renderer,
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: false,
smartLists: true,
highlight: function (code) {
return hljs.highlightAuto(code).value;
}
renderer,
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: false,
smartLists: true,
highlight: function (code) {
return hljs.highlightAuto(code).value;
}
});
export default {
name: 'markdown',
props: {
initialValue: {
type:String,
default:''
}, // 初始化内容
theme: { // 默认主题
type: String,
default: 'Light'
name: 'markdown',
props: {
value: {
type: [String, Number],
default: ''
},
initialValue: {// 初始化内容
type: String,
default: ''
},
theme: { // 默认主题
type: String,
default: 'Light'
},
width: { // 初始化宽度
type: [Number, String],
default: 'auto'
},
height: { // 初始化高度
type: Number,
default: 600
}, // 宽度
toolbars: { // 工具栏
type: Object,
default() {
return {};
}
},
bordered: {//是否有边框
type: Boolean,
default: true
},
autoSave: { // 是否自动保存
type: Boolean,
default: false
},
interval: { // 自动保存间隔 mm
type: Number,
default: 100000
},
exportFileName: { // 默认导出文件名称
type: String,
default: '未命名文件'
},
markedOptions: {//marked.js配置项
type: Object,
default() {
return {};
}
},
isPreview: {//是否是预览模式
type: Boolean,
default: false
}
},
width: { // 初始化宽度
type: [Number, String],
default: 'auto'
data() {
return {
currentValue: '', // 输入框内容
timeoutId: null,
indexLenth: 100,
html: '',
preview: false, // 是否是预览状态
split: true,//分屏显示
fullscreen: false, // 是否是全屏
scrollHeight: null,
scroll: 'markdown', // 哪个半栏在滑动
themeName: '', // 主题名称
lastInsert: '',//最后一次插入的内容
timerId: null, // 定时器id
themeSlideDown: false,
imgs: [],
scrolling: true, // 同步滚动
editorHeight: '',
editorWidth: '',
previewImgModal: false,
previewImgSrc: '',
previewImgMode: ''
};
},
height: { // 初始化高度
type: Number,
default: 600
}, // 宽度
toolbars: { // 工具栏
type: Object,
default () {
return {};
}
computed: {
tools() {
const {
toolbars = {}
} = this;
return {
...defaultTools,
...toolbars
}
}
},
autoSave: { // 是否自动保存
type: Boolean,
default: true
mounted() {
this.init();
},
interval: { // 自动保存间隔 mm
type: Number,
default: 100000
methods: {
init() {
this.currentValue = this.value;
this.themeName = this.theme;
this.editorHeight = this.height;
this.editorWidth = this.width;
this.preview = this.isPreview;
if (this.isPreview) {
return;
}
setTimeout(() => {
const textarea = this.$refs.textarea;
textarea.focus();
textarea.addEventListener('keydown', e => {
if (e.keyCode === 83) {
if (e.metaKey || e.ctrlKey) {
e.preventDefault();
this.handleSave();
}
}
})
textarea.addEventListener('paste', this.handlePaste);
if (this.autoSave) {
this.timerId = setInterval(() => {
this.handleSave();
}, this.interval);
}
}, 20)
},
handlePaste(e) { // 粘贴图片
const {
clipboardData = {}
} = e;
const {
types = [], items
} = clipboardData;
let item = null;
for (let i = 0; i < types.length; i++) {
if (types[i] === 'Files') {
item = items[i];
break;
}
}
if (item) {
const file = item.getAsFile();
if (/image/ig.test(file.type)) {
this.$emit('on-paste-image', file);
e.preventDefault();
}
}
},
markdownScroll() {
const {scrolling} = this;
if (!scrolling) {
return;
}
if (this.scroll === 'markdown') {
const markdownContent = this.$refs.markdownContent;
const preview = this.$refs.preview;
const markdownScrollHeight = markdownContent.scrollHeight;
const markdownScrollTop = markdownContent.scrollTop;
const previewScrollHeight = preview.scrollHeight;
preview.scrollTop = parseInt(markdownScrollTop / markdownScrollHeight * previewScrollHeight, 0);
}
},
previewScroll() {
const {scrolling} = this;
if (!scrolling) {
return;
}
if (this.scroll === 'preview') {
const markdownContent = this.$refs.markdownContent;
const preview = this.$refs.preview;
const markdownScrollHeight = markdownContent.scrollHeight;
const previewScrollHeight = preview.scrollHeight;
const previewScrollTop = preview.scrollTop;
markdownContent.scrollTop = parseInt(previewScrollTop / previewScrollHeight * markdownScrollHeight, 0);
}
},
mousescrollSide(side) { // 设置究竟是哪个半边在主动滑动
this.scroll = side;
},
insertContent(initStr) { // 插入文本
this.lastInsert = initStr;
const point = this.getCursortPosition();
const lastChart = this.currentValue.substring(point - 1, point);
const lastFourCharts = this.currentValue.substring(point - 4, point);
if (lastChart !== '\n' && this.currentValue !== '' && lastFourCharts !== ' ') {
const str = '\n' + initStr;
this.insertAfterText(str);
} else {
this.insertAfterText(initStr);
}
},
getCursortPosition() { // 获取光标位置
const textDom = this.$refs.textarea;
let cursorPos = 0;
if (document.selection) {
textDom.focus();
let selectRange = document.selection.createRange();
selectRange.moveStart('character', -this.currentValue.length);
cursorPos = selectRange.text.length;
} else if (textDom.selectionStart || parseInt(textDom.selectionStart, 0) === 0) {
cursorPos = textDom.selectionStart;
}
return cursorPos;
},
insertAfterText(value) { // 插入文本
const textDom = this.$refs.textarea;
let selectRange;
if (document.selection) {
textDom.focus();
selectRange = document.selection.createRange();
selectRange.text = value;
textDom.focus();
} else if (textDom.selectionStart || parseInt(textDom.selectionStart, 0) === 0) {
const startPos = textDom.selectionStart;
const endPos = textDom.selectionEnd;
const scrollTop = textDom.scrollTop;
textDom.value = textDom.value.substring(0, startPos) + value + textDom.value.substring(endPos, textDom.value.length);
textDom.focus();
textDom.selectionStart = startPos + value.length;
textDom.selectionEnd = startPos + value.length;
textDom.scrollTop = scrollTop;
} else {
textDom.value += value;
textDom.focus();
}
this.$set(this, 'currentValue', textDom.value);
},
setCaretPosition(position) { // 设置光标位置
const textDom = this.$refs.textarea;
if (textDom.setSelectionRange) {
textDom.focus();
textDom.setSelectionRange(position, position);
} else if (textDom.createTextRange) {
let range = textDom.createTextRange();
range.collapse(true);
range.moveEnd('character', position);
range.moveStart('character', position);
range.select();
}
},
insertQuote() { // 引用
this.insertContent('\n> ');
},
insertUl() { // 无需列表
this.insertContent('- ');
},
insertOl() { // 有序列表
this.insertContent('1. ');
},
insertFinished() { // 已完成列表
this.insertContent('- [x] ');
},
insertNotFinished() { // 未完成列表
this.insertContent('- [ ] ');
},
insertLink() { // 插入链接
this.insertContent('\n[插入链接](href)');
},
insertImage() { // 插入图片
this.insertContent('\n![image](imgUrl)');
},
insertTable() { // 插入表格
this.insertContent('\nheader 1 | header 2\n---|---\nrow 1 col 1 | row 1 col 2\nrow 2 col 1 | row 2 col 2\n\n');
},
insertCode() { // 插入code
const point = this.getCursortPosition();
const lastChart = this.currentValue.substring(point - 1, point);
this.insertContent('\n```\n\n```');
if (lastChart !== '\n' && this.currentValue !== '') {
this.setCaretPosition(point + 5);
} else {
this.setCaretPosition(point + 5);
}
},
insertStrong() { // 粗体
const point = this.getCursortPosition();
const lastChart = this.currentValue.substring(point - 1, point);
this.insertContent('****');
if (lastChart !== '\n' && this.currentValue !== '') {
this.setCaretPosition(point + 2);
} else {
this.setCaretPosition(point + 2);
}
},
insertItalic() { // 斜体
const point = this.getCursortPosition();
const lastChart = this.currentValue.substring(point - 1, point);
this.insertContent('**');
if (lastChart !== '\n' && this.currentValue !== '') {
this.setCaretPosition(point + 1);
} else {
this.setCaretPosition(point + 1);
}
},
insertBg() { // 背景色
const point = this.getCursortPosition();
const lastChart = this.currentValue.substring(point - 1, point);
this.insertContent('====');
if (lastChart !== '\n' && this.currentValue !== '') {
this.setCaretPosition(point + 5);
} else {
this.setCaretPosition(point + 5);
}
},
insertUnderline() { // 下划线
const point = this.getCursortPosition();
const lastChart = this.currentValue.substring(point - 1, point);
this.insertContent('<u></u>');
if (lastChart !== '\n' && this.currentValue !== '') {
this.setCaretPosition(point + 3);
} else {
this.setCaretPosition(point + 5);
}
},
insertOverline() { // overline
const point = this.getCursortPosition();
const lastChart = this.currentValue.substring(point - 1, point);
this.insertContent('~~~~');
if (lastChart !== '\n' && this.currentValue !== '') {
this.setCaretPosition(point + 2);
} else {
this.setCaretPosition(point + 2);
}
},
insertTitle(level) { // 插入标题
const titleLevel = {
1: '# ',
2: '## ',
3: '### ',
4: '#### ',
5: '##### ',
6: '###### '
};
this.insertContent(titleLevel[level]);
},
tab(e) { // 屏蔽teatarea tab默认事件
this.insertContent(' ', this);
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false;
}
},
handleSave() { // 保存操作
const {currentValue, themeName} = this;
this.$emit('on-save', {
theme: themeName,
value: currentValue,
});
},
insertLine() { // 插入分割线
this.insertContent('\n----\n');
},
toggleSlideDown() { // 显示主题选项
this.slideDown = !this.slideDown;
},
setThemes(name) { // 设置主题
this.themeName = name;
this.themeSlideDown = false;
this.$emit('on-theme-change', name);
},
enter() { // 回车事件
const {lastInsert} = this;
const list = ['- ', '1. ', '- [ ] ', '- [x] ']
if (list.includes(lastInsert)) {
this.insertContent(lastInsert);
}
},
onDelete() { // 删除时,以回车为界分割,如果数组最后一个元素为''时,将行一次插入的共嗯那个置为空,避免回车时再次插入
const lines = this.currentValue.split('\n');
if (lines[lines.length - 1] === '') {
this.lastInsert = '';
}
},
exportMd() { // 导出为.md格式
saveFile(this.currentValue, this.exportFileName + '.md');
},
importFile(e) { // 导入本地文件
const file = e.target.files[0];
if (!file) {
return;
}
const {type} = file;
if (type !== 'text/markdown') {
this.$Notice.error('文件格式有误!');
return;
}
const reader = new FileReader();
reader.readAsText(file, {
encoding: 'utf-8'
});
reader.onload = () => {
this.currentValue = reader.result;
e.target.value = '';
}
},
addImageClickListener() { // 监听查看大图
const {imgs} = this;
if (imgs.length > 0) {
for (let i = 0, len = imgs.length; i < len; i++) {
imgs[i].onclick = null;
}
}
setTimeout(() => {
this.imgs = this.$refs.preview.querySelectorAll('img');
for (let i = 0, len = this.imgs.length; i < len; i++) {
this.imgs[i].onclick = () => {
const src = this.imgs[i].getAttribute('src');
this.previewImage(src);
}
}
}, 600);
},
previewImage(src) { // 预览图片
const img = new Image();
img.src = src;
img.onload = () => {
const width = img.naturalWidth;
const height = img.naturalHeight;
if ((height / width) > 1.4) {
this.previewImgMode = 'horizontal';
} else {
this.previewImgMode = 'vertical';
}
this.previewImgSrc = src;
this.previewImgModal = true;
}
},
addCopyListener() { // 监听复制操作
setTimeout(() => {
const btns = document.querySelectorAll('.code-block .copy-code');
this.btns = btns;
for (let i = 0, len = btns.length; i < len; i++) {
btns[i].onclick = () => {
const code = btns[i].parentNode.querySelectorAll('pre')[0].innerText;
const aux = document.createElement('input');
aux.setAttribute('value', code);
document.body.appendChild(aux);
aux.select();
document.execCommand('copy');
document.body.removeChild(aux);
this.$emit('on-copy',code);
};
}
}, 600);
}
},
exportFileName: { // 默认导出文件名称
type: String,
default: '未命名文件'
watch: {
currentValue() {
clearTimeout(this.timeoutId);
this.timeoutId = setTimeout(() => {
const {currentValue} = this;
this.html = marked(currentValue, {
sanitize: false,
...this.markedOptions
}).replace(/href="/ig, 'target="_blank" href="')
.replace(/<pre>/g, '<div class="code-block"><span class="copy-code">复制代码</span><pre>')
.replace(/<\/pre>/g, '</pre></div>');
this.indexLenth = this.currentValue.split('\n').length;
const height1 = this.indexLenth * 22;
const height2 = this.$refs.textarea.scrollHeight;
const height3 = this.$refs.preview.scrollHeight;
this.scrollHeight = Math.max(height1, height2, height3);
this.indexLenth = parseInt(this.scrollHeight / 22, 0) - 1;
this.addImageClickListener();
this.addCopyListener();
this.$emit('input', currentValue);
}, 300)
},
value() {
this.currentValue = this.value;
},
theme() {
this.themeName = this.theme;
},
height() {
this.editorHeight = this.height;
},
width() {
this.editorWidth = this.width;
}
},
markedOptions: {
type: Object,
default () {
return {};
}
destroyed() { // 销毁时清除定时器
clearInterval(this.timerId);
}
},
data() {
return {
value: '', // 输入框内容
timeoutId: null,
indexLenth: 100,
html: '',
preview: 1, // 是否是预览状态
isFullscreen: false, // 是否是全屏
scrollHeight: null,
scroll: 'markdown', // 哪个半栏在滑动
themeName: '', // 主题名称
lastInsert: '',
timerId: null, // 定时器id
themeSlideDown: false,
imgs: [],
scrolling: true, // 同步滚动
editorHeight: '',
editorWidth: '',
previewImgModal: false,
previewImgSrc: '',
previewImgMode: ''
};
},
computed: {
tools() {
const {
toolbars = {}
} = this;
return {
...defaultTools,
...toolbars
}
}
},
mounted() {
this.init();
setTimeout(() => {
const textarea = this.$refs.textarea;
textarea.focus();
textarea.addEventListener('keydown', e => {
if (e.keyCode === 83) {
if (e.metaKey || e.ctrlKey) {
e.preventDefault();
this.handleSave();
}
}
})
textarea.addEventListener('paste', this.handlePaste);
if (this.autoSave) {
this.timerId = setInterval(() => {
this.handleSave();
}, this.interval);
}
}, 20)
},
methods: {
init() {
this.value = this.initialValue;
this.themeName = this.theme;
this.editorHeight = this.height;
this.editorWidth = this.width;
},
handlePaste(e) { // 粘贴图片
const {
clipboardData = {}
} = e;
const {
types = [], items
} = clipboardData;
let item = null;
for (let i = 0; i < types.length; i++) {
if (types[i] === 'Files') {
item = items[i];
break;
}
}
if (item) {
const file = item.getAsFile();
if (/image/ig.test(file.type)) {
this.$emit('on-paste-image', file);
e.preventDefault();
}
}
},
markdownScroll() {
const {
scrolling
} = this;
if (!scrolling) {
return;
}
if (this.scroll === 'markdown') {
const markdownContent = this.$refs.markdownContent;
const preview = this.$refs.preview;
const markdownScrollHeight = markdownContent.scrollHeight;
const markdownScrollTop = markdownContent.scrollTop;
const previewScrollHeight = preview.scrollHeight;
preview.scrollTop = parseInt(markdownScrollTop / markdownScrollHeight * previewScrollHeight, 0);
}
},
previewScroll() {
const {
scrolling
} = this;
if (!scrolling) {
return;
}
if (this.scroll === 'preview') {
const markdownContent = this.$refs.markdownContent;
const preview = this.$refs.preview;
const markdownScrollHeight = markdownContent.scrollHeight;
const previewScrollHeight = preview.scrollHeight;
const previewScrollTop = preview.scrollTop;
markdownContent.scrollTop = parseInt(previewScrollTop / previewScrollHeight * markdownScrollHeight, 0);
}
},
mousescrollSide(side) { // 设置究竟是哪个半边在主动滑动
this.scroll = side;
},
insertContent(initStr) { // 插入文本
const {
preview
} = this;
if (preview === 2) {
return;
}
this.lastInsert = initStr;
const point = this.getCursortPosition();
const lastChart = this.value.substring(point - 1, point);
const lastFourCharts = this.value.substring(point - 4, point);
if (lastChart !== '\n' && this.value !== '' && lastFourCharts !== ' ') {
const str = '\n' + initStr;
this.insertAfterText(str);
} else {
this.insertAfterText(initStr);
}
},
getCursortPosition() { // 获取光标位置
const textDom = this.$refs.textarea;
let cursorPos = 0;
if (document.selection) {
textDom.focus();
let selectRange = document.selection.createRange();
selectRange.moveStart('character', -this.value.length);
cursorPos = selectRange.text.length;
} else if (textDom.selectionStart || parseInt(textDom.selectionStart, 0) === 0) {
cursorPos = textDom.selectionStart;
}
return cursorPos;
},
insertAfterText(value) { // 插入文本
const textDom = this.$refs.textarea;
let selectRange;
if (document.selection) {
textDom.focus();
selectRange = document.selection.createRange();
selectRange.text = value;
textDom.focus();
} else if (textDom.selectionStart || parseInt(textDom.selectionStart, 0) === 0) {
const startPos = textDom.selectionStart;
const endPos = textDom.selectionEnd;
const scrollTop = textDom.scrollTop;
textDom.value = textDom.value.substring(0, startPos) + value + textDom.value.substring(endPos, textDom.value.length);
textDom.focus();
textDom.selectionStart = startPos + value.length;
textDom.selectionEnd = startPos + value.length;
textDom.scrollTop = scrollTop;
} else {
textDom.value += value;
textDom.focus();
}
this.$set(this, 'value', textDom.value);
},
setCaretPosition(position) { // 设置光标位置
const textDom = this.$refs.textarea;
if (textDom.setSelectionRange) {
textDom.focus();
textDom.setSelectionRange(position, position);
} else if (textDom.createTextRange) {
let range = textDom.createTextRange();
range.collapse(true);
range.moveEnd('character', position);
range.moveStart('character', position);
range.select();
}
},
insertQuote() { // 引用
this.insertContent('\n> ');
},
insertUl() { // 无需列表
this.insertContent('- ');
},
insertOl() { // 有序列表
this.insertContent('1. ');
},
insertFinished() { // 已完成列表
this.insertContent('- [x] ');
},
insertNotFinished() { // 未完成列表
this.insertContent('- [ ] ');
},
insertLink() { // 插入链接
this.insertContent('\n[插入链接](href)');
},
insertImage() { // 插入图片
this.insertContent('\n![image](imgUrl)');
},
insertTable() { // 插入表格
this.insertContent('\nheader 1 | header 2\n---|---\nrow 1 col 1 | row 1 col 2\nrow 2 col 1 | row 2 col 2\n\n');
},
insertCode() { // 插入code
const point = this.getCursortPosition();
const lastChart = this.value.substring(point - 1, point);
this.insertContent('\n```\n\n```');
if (lastChart !== '\n' && this.value !== '') {
this.setCaretPosition(point + 5);
} else {
this.setCaretPosition(point + 5);
}
},
insertStrong() { // 粗体
const point = this.getCursortPosition();
const lastChart = this.value.substring(point - 1, point);
this.insertContent('****');
if (lastChart !== '\n' && this.value !== '') {
this.setCaretPosition(point + 2);
} else {
this.setCaretPosition(point + 2);
}
},
insertItalic() { // 斜体
const point = this.getCursortPosition();
const lastChart = this.value.substring(point - 1, point);
this.insertContent('**');
if (lastChart !== '\n' && this.value !== '') {
this.setCaretPosition(point + 1);
} else {
this.setCaretPosition(point + 1);
}
},
insertBg() { // 背景色
const point = this.getCursortPosition();
const lastChart = this.value.substring(point - 1, point);
this.insertContent('====');
if (lastChart !== '\n' && this.value !== '') {
this.setCaretPosition(point + 5);
} else {
this.setCaretPosition(point + 5);
}
},
insertUnderline() { // 下划线
const point = this.getCursortPosition();
const lastChart = this.value.substring(point - 1, point);
this.insertContent('<u></u>');
if (lastChart !== '\n' && this.value !== '') {
this.setCaretPosition(point + 3);
} else {
this.setCaretPosition(point + 5);
}
},
insertOverline() { // overline
const point = this.getCursortPosition();
const lastChart = this.value.substring(point - 1, point);
this.insertContent('~~~~');
if (lastChart !== '\n' && this.value !== '') {
this.setCaretPosition(point + 2);
} else {
this.setCaretPosition(point + 2);
}
},
insertTitle(level) { // 插入标题
const titleLevel = {
1: '# ',
2: '## ',
3: '### ',
4: '#### ',
5: '##### ',
6: '###### '
};
this.insertContent(titleLevel[level]);
},
tab(e) { // 屏蔽teatarea tab默认事件
this.insertContent(' ', this);
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false;
}
},
handleSave() { // 保存操作
const {
value,
html,
themeName
} = this;
this.$emit('on-save', {
theme: themeName,
value,
html
});
},
insertLine() { // 插入分割线
this.insertContent('\n----\n');
},
toggleSlideDown() { // 显示主题选项
this.slideDown = !this.slideDown;
},
setThemes(name) { // 设置主题
this.themeName = name;
this.themeSlideDown = false;
},
enter() { // 回车事件
const {
lastInsert
} = this;
const list = ['- ', '1. ', '- [ ] ', '- [x] ']
if (list.includes(lastInsert)) {
this.insertContent(lastInsert);
}
},
onDelete() { // 删除时,以回车为界分割,如果数组最后一个元素为''时,将行一次插入的共嗯那个置为空,避免回车时再次插入
const lines = this.value.split('\n');
if (lines[lines.length - 1] === '') {
this.lastInsert = '';
}
},
exportMd() { // 导出为.md格式
saveFile(this.value, this.exportFileName + '.md');
},
importFile(e) { // 导入本地文件
const file = e.target.files[0];
if (!file) {
return;
}
const {
type
} = file;
if (type !== 'text/markdown') {
this.$Notice.error('文件格式有误!');
return;
}
const reader = new FileReader();
reader.readAsText(file, {
encoding: 'utf-8'
});
reader.onload = () => {
this.value = reader.result;
e.target.value = '';
}
},
addImageClickListener() { // 监听查看大图
const {
imgs
} = this;
if (imgs.length > 0) {
for (let i = 0, len = imgs.length; i < len; i++) {
imgs[i].onclick = null;
}
}
setTimeout(() => {
this.imgs = this.$refs.preview.querySelectorAll('img');
for (let i = 0, len = this.imgs.length; i < len; i++) {
this.imgs[i].onclick = () => {
const src = this.imgs[i].getAttribute('src');
this.previewImage(src);
}
}
}, 600);
},
previewImage(src) { // 预览图片
const img = new Image();
img.src = src;
img.onload = () => {
const width = img.naturalWidth;
const height = img.naturalHeight;
if ((height / width) > 1.4) {
this.previewImgMode = 'horizontal';
} else {
this.previewImgMode = 'vertical';
}
this.previewImgSrc = src;
this.previewImgModal = true;
}
}
},
watch: {
initialValue() {
this.value = this.initialValue;
},
value() {
clearTimeout(this.timeoutId);
this.timeoutId = setTimeout(() => {
this.html = marked(this.value, {
sanitize: false,
...this.markedOptions
});
}, 30)
this.indexLenth = this.value.split('\n').length;
const height1 = this.indexLenth * 22;
const height2 = this.$refs.textarea.scrollHeight;
const height3 = this.$refs.preview.scrollHeight;
this.scrollHeight = Math.max(height1, height2, height3);
this.indexLenth = parseInt(this.scrollHeight / 22, 0) - 1;
this.addImageClickListener();
},
theme() {
this.themeName = this.theme;
},
height() {
this.editorHeight = this.height;
},
width() {
this.editorWidth = this.width;
}
},
destroyed() { // 销毁时清除定时器
clearInterval(this.timerId);
}
};

View File

@ -2,86 +2,74 @@ var path = require('path')
var webpack = require('webpack')
const NODE_ENV = process.env.NODE_ENV;
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const isDev = process.env.NODE_ENV === 'development';
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
let analyzerPlugin = [];
if(process.env.analyzer==='true'){
analyzerPlugin.push(new BundleAnalyzerPlugin())
}
module.exports = {
entry: NODE_ENV==='npm'?'./src/index.js':'./src/main.js',
output: {
path: path.resolve(__dirname, NODE_ENV==='npm'?'./build':'./dist'),
publicPath:NODE_ENV==='npm'? '/build/':'/dist/',
filename: NODE_ENV==='npm'?'index.js':'build.js',
libraryTarget: 'umd',
library: 'markdown-vue',
umdNamedDefine: true
},
devtool: NODE_ENV==='develop'?'cheap-module-eval-source-map':'cheap-module-source-map',
module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
}, {
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
entry: NODE_ENV === 'npm' ? './src/index.js' : './src/main.js',
output: {
path: path.resolve(__dirname, NODE_ENV === 'npm' ? './build' : './dist'),
publicPath: NODE_ENV === 'npm' ? '/build/' : '/dist/',
filename: NODE_ENV === 'npm' ? 'index.js' : 'build.js',
libraryTarget: 'umd',
library: 'markdown-vue',
umdNamedDefine: true
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
devtool: isDev ? 'cheap-module-eval-source-map' : 'cheap-module-source-map',
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
}, {
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {}
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
plugins: [
...analyzerPlugin,
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
]
}
if (NODE_ENV === 'production'||NODE_ENV==='npm') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
}),
new CompressionWebpackPlugin({
algorithm: 'gzip'
})
])
}