Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
曲幽
Awesome-Markdown-Editor
提交
af823f10
Awesome-Markdown-Editor
项目概览
曲幽
/
Awesome-Markdown-Editor
与 Fork 源项目一致
Fork自
gitcode_dev / Awesome-Markdown-Editor
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Awesome-Markdown-Editor
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
af823f10
编写于
6月 09, 2021
作者:
璃白.
🌻
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor:重构状态管理逻辑
上级
f529497f
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
284 addition
and
245 deletion
+284
-245
src/App.vue
src/App.vue
+63
-14
src/assets/js/utils.js
src/assets/js/utils.js
+0
-11
src/components/content/md-preview.vue
src/components/content/md-preview.vue
+10
-5
src/components/content/md-textarea.vue
src/components/content/md-textarea.vue
+37
-18
src/components/footer/md-footer.vue
src/components/footer/md-footer.vue
+15
-5
src/components/footer/upload-files.vue
src/components/footer/upload-files.vue
+7
-7
src/components/header/md-header.vue
src/components/header/md-header.vue
+113
-4
src/components/header/tool-button.vue
src/components/header/tool-button.vue
+32
-10
src/main.js
src/main.js
+7
-8
src/store/index.js
src/store/index.js
+0
-163
未找到文件。
src/App.vue
浏览文件 @
af823f10
<
template
>
<div
:class=
"['md_container',
{ active: isFocus }]">
<markdown-header
/>
<markdownPreview
v-show=
"showPreview"
/>
<markdown-editor
v-show=
"!showPreview"
/>
<markdown-header
:text.sync=
"text"
:selectionInfo.sync=
"selectionInfo"
:showPreview.sync=
"showPreview"
:isFocus.sync=
"isFocus"
:fullScreen.sync=
"fullScreen"
/>
<markdownPreview
:text=
"text"
:html.sync=
"html"
v-show=
"showPreview"
/>
<markdown-editor
:selectionInfo.sync=
"selectionInfo"
:text.sync=
"text"
:fileList.sync=
"fileList"
:placeholder=
"placeholder"
:isFocus.sync=
"isFocus"
:fullScreen.sync=
"fullScreen"
v-show=
"!showPreview"
/>
<markdown-footer
:fileList.sync=
"fileList"
:canAttachFile=
"canAttachFile"
:isFocus.sync=
"isFocus"
:can-attach-file=
"canAttachFile"
v-if=
"!showPreview && canAttachFile"
/>
...
...
@@ -14,7 +31,7 @@ import markdownHeader from "./components/header/md-header";
import
markdownFooter
from
"
./components/footer/md-footer
"
;
import
markdownEditor
from
"
./components/content/md-textarea
"
;
import
markdownPreview
from
"
./components/content/md-preview
"
;
import
{
mapState
}
from
"
vuex
"
;
import
{
formatText
}
from
"
@/assets/js/utils
"
;
export
default
{
components
:
{
markdownHeader
,
...
...
@@ -22,16 +39,32 @@ export default {
markdownEditor
,
markdownPreview
},
computed
:
{
...
mapState
([
"
showPreview
"
,
"
isFocus
"
,
"
canAttachFile
"
,
"
text
"
,
"
html
"
,
"
fileList
"
])
props
:
{
placeholder
:
{
type
:
String
,
default
:
"
请输入内容
"
}
,
canAttachFile
:
{
type
:
Boolean
,
default
:
true
}
},
data
()
{
return
{
fullScreen
:
false
,
isFocus
:
false
,
showPreview
:
false
,
fileList
:
[],
text
:
""
,
html
:
""
,
selectionInfo
:
{
selectorId
:
""
,
selectionStart
:
""
,
selectionEnd
:
""
}
};
},
watch
:
{
html
:
{
immediate
:
true
,
...
...
@@ -46,7 +79,23 @@ export default {
immediate
:
false
,
deep
:
true
,
handler
:
function
(
val
)
{
this
.
$emit
(
"
upload
"
,
val
);
const
_this
=
this
;
if
(
!
val
.
length
)
return
;
this
.
$emit
(
"
upload
"
,
{
val
:
val
[
0
],
callback
:
function
(
url
)
{
const
originalText
=
_this
.
text
;
const
selectionInfo
=
_this
.
selectionInfo
;
const
newText
=
formatText
(
originalText
,
selectionInfo
,
"
\n\n
![img](
"
,
`
${
url
}
)\n`
);
_this
.
text
=
newText
;
}
});
this
.
fileList
=
[];
}
}
}
...
...
src/assets/js/utils.js
浏览文件 @
af823f10
import
store
from
"
@/store
"
;
// 获取选中文本信息
export
function
getSelectionInfo
(
selectorId
)
{
...
...
@@ -40,15 +38,6 @@ export function formatText(text, selectionInfo, startStr = "", endStr = "") {
return
newText
;
}
//
export
function
updateText
(
startStr
,
endStr
)
{
const
selectionInfo
=
store
.
state
.
selectionInfo
;
const
originalText
=
store
.
state
.
text
;
const
newText
=
formatText
(
originalText
,
selectionInfo
,
startStr
,
endStr
);
if
(
!
newText
)
return
;
store
.
commit
(
"
setText
"
,
newText
);
}
// 初始化样式
export
function
initStyle
({
borderColor
,
...
...
src/components/content/md-preview.vue
浏览文件 @
af823f10
...
...
@@ -4,18 +4,23 @@
</div>
</
template
>
<
script
>
import
{
mapState
,
mapMutations
}
from
"
vuex
"
;
import
marked
from
"
marked
"
;
import
"
highlight.js/styles/github.css
"
;
export
default
{
data
()
{
return
{};
},
computed
:
{
...
mapState
([
"
text
"
,
"
html
"
])
props
:
{
text
:
{
type
:
String
,
default
:
""
},
html
:
{
type
:
String
,
default
:
""
}
},
methods
:
{
...
mapMutations
([
"
setHtml
"
]),
transferMarkdown
(
val
)
{
marked
.
setOptions
({
highlight
:
function
(
code
,
lang
,
callback
)
{
...
...
@@ -25,7 +30,7 @@ export default {
});
if
(
!
val
.
trim
())
return
;
const
html
=
marked
(
val
);
this
.
setHtml
(
html
);
this
.
$emit
(
"
update:html
"
,
html
);
}
},
watch
:
{
...
...
src/components/content/md-textarea.vue
浏览文件 @
af823f10
...
...
@@ -2,7 +2,7 @@
<div
:class=
"['md_textarea',
{ fullScreen }]">
<textarea
:id=
"id"
@
change=
"
setText(
textContent)"
@
change=
"
$emit('update:text',
textContent)"
@
focus=
"setFocus(true)"
@
blur=
"setFocus(false)"
@
paste=
"pasteFile"
...
...
@@ -12,20 +12,44 @@
>
</textarea>
<span
@
click=
"
setFullScreen(
false)"
@
click=
"
$emit('update:fullScreen',
false)"
v-if=
"fullScreen"
class=
"icon iconfont icon-quxiaoquanping_o"
></span>
</div>
</
template
>
<
script
>
import
{
mapState
,
mapMutations
}
from
"
vuex
"
;
import
{
getSelectionInfo
,
getPosition
}
from
"
@/assets/js/utils
"
;
export
default
{
props
:
{
fullScreen
:
{
type
:
Boolean
,
default
:
false
},
isFocus
:
{
type
:
Boolean
,
default
:
false
},
placeholder
:
{
type
:
String
,
default
:
false
},
fileList
:
{
type
:
Array
,
default
:
()
=>
[]
},
text
:
{
type
:
String
,
default
:
''
},
selectionInfo
:
{
type
:
Object
,
default
:
()
=>
{}
}
},
data
()
{
return
{
id
:
new
Date
().
getTime
(),
isFocus
:
false
,
textContent
:
""
};
},
...
...
@@ -43,29 +67,24 @@ export default {
beforeDestroy
()
{
document
.
removeEventListener
(
"
mouseup
"
,
this
.
checkSelection
);
},
computed
:
{
...
mapState
([
"
text
"
,
"
fullScreen
"
,
"
placeholder
"
])
},
methods
:
{
...
mapMutations
([
"
setText
"
,
"
setFullScreen
"
,
"
setSelectionInfo
"
,
"
setFileList
"
,
"
setFocus
"
]),
setFocus
(
val
)
{
this
.
$emit
(
'
update:isFocus
'
,
val
)
},
checkSelection
()
{
const
info
=
getSelectionInfo
(
this
.
id
);
if
(
!
info
)
{
const
cursorPoint
=
getPosition
(
this
.
id
);
this
.
setSelectionInfo
(
{
this
.
$emit
(
'
update:selectionInfo
'
,
{
selectorId
:
this
.
id
,
selectionStart
:
cursorPoint
,
selectionEnd
:
cursorPoint
})
;
})
return
;
}
this
.
setSelectionInfo
(
info
);
this
.
$emit
(
'
update:selectionInfo
'
,
info
)
},
pasteFile
(
event
)
{
let
fileList
=
[];
...
...
@@ -77,7 +96,7 @@ export default {
}
}
if
(
!
fileList
.
length
)
return
;
this
.
setFileList
(
fileList
[
0
]);
this
.
$emit
(
'
update:fileList
'
,
fileList
)
}
}
};
...
...
src/components/footer/md-footer.vue
浏览文件 @
af823f10
<
template
>
<div
:class=
"['md_footer',
{ active: isFocus }]">
<div
class=
"doc"
></div>
<upload-files
v-if=
"canAttachFile"
/>
<upload-files
@
changeFileList=
"$emit('update:fileList', $event)"
:fileList=
"fileList"
v-if=
"canAttachFile"
/>
</div>
</
template
>
<
script
>
import
uploadFiles
from
"
./upload-files
"
;
import
{
mapState
}
from
"
vuex
"
;
export
default
{
components
:
{
uploadFiles
},
computed
:
{
...
mapState
([
"
isFocus
"
,
"
canAttachFile
"
])
}
props
:
{
isFocus
:
{
type
:
Boolean
,
default
:
false
},
canAttachFile
:
{
type
:
Boolean
,
default
:
false
},
fileList
:
{
type
:
Array
,
default
:
()
=>
[]
}
},
};
</
script
>
<
style
lang=
"less"
scoped
>
...
...
src/components/footer/upload-files.vue
浏览文件 @
af823f10
...
...
@@ -13,20 +13,20 @@
</div>
</
template
>
<
script
>
import
{
mapState
,
mapMutations
}
from
"
vuex
"
;
export
default
{
props
:
{
fileList
:
{
type
:
Array
,
default
:
()
=>
[]
}
},
data
()
{
return
{};
},
computed
:
{
...
mapState
([
"
text
"
,
"
selectionInfo
"
])
},
methods
:
{
...
mapMutations
([
"
setText
"
,
"
setFileList
"
]),
upload
(
e
)
{
const
fileList
=
Array
.
from
(
e
.
target
.
files
);
this
.
setFileList
(
fileList
[
0
]
);
this
.
$emit
(
"
changeFileList
"
,
fileList
);
}
}
};
...
...
src/components/header/md-header.vue
浏览文件 @
af823f10
...
...
@@ -17,22 +17,131 @@
<div
class=
"header_tools"
v-if=
"!showPreview"
>
<tool-button
:info=
"item"
:fullScreen=
"fullScreen"
@
setFullScreen=
"$emit('update:fullScreen', true)"
@
updateText=
"updateText"
v-for=
"(item, index) in toolButtonList"
:key=
"index"
:text=
"text"
:selectionInfo=
"selectionInfo"
/>
</div>
</div>
</
template
>
<
script
>
import
toolButton
from
"
./tool-button
"
;
import
{
mapState
,
mapMutations
}
from
"
vuex
"
;
export
default
{
components
:
{
toolButton
},
computed
:
{
...
mapState
([
"
toolButtonList
"
,
"
isFocus
"
,
"
showPreview
"
])
props
:
{
fullScreen
:
{
type
:
Boolean
,
default
:
false
},
isFocus
:
{
type
:
Boolean
,
default
:
false
},
showPreview
:
{
type
:
Boolean
,
default
:
false
},
text
:
{
type
:
String
,
default
:
""
},
selectionInfo
:
{
type
:
Object
,
default
:
()
=>
{}
}
},
data
()
{
return
{
toolButtonList
:
[
{
name
:
"
bold
"
,
icon
:
"
bold
"
,
tip
:
"
粗体
"
,
startStr
:
"
**
"
,
endStr
:
"
**
"
},
{
name
:
"
italic
"
,
icon
:
"
italic
"
,
tip
:
"
斜体
"
,
startStr
:
"
_
"
,
endStr
:
"
_
"
},
{
name
:
"
quote
"
,
icon
:
"
baojiaquotation
"
,
tip
:
"
插入引用
"
,
startStr
:
"
\n
>
"
,
endStr
:
""
},
{
name
:
"
code
"
,
icon
:
"
code
"
,
tip
:
"
插入代码
"
,
startStr
:
"
`
"
,
endStr
:
"
`
"
},
{
name
:
"
link
"
,
icon
:
"
lianjie
"
,
tip
:
"
添加链接
"
,
startStr
:
"
[
"
,
endStr
:
"
](url)
"
},
{
name
:
"
ul
"
,
icon
:
"
unorderedList
"
,
tip
:
"
添加无序列表
"
,
startStr
:
"
\n
-
"
,
endStr
:
""
},
{
name
:
"
ol
"
,
icon
:
"
youxuliebiao
"
,
tip
:
"
添加有序列表
"
,
startStr
:
""
,
endStr
:
""
},
{
name
:
"
task
"
,
icon
:
"
renwu
"
,
tip
:
"
添加任务列表
"
,
startStr
:
"
\n
- [ ]
"
,
endStr
:
""
},
{
name
:
"
table
"
,
icon
:
"
biaoge
"
,
tip
:
"
添加表格
"
,
startStr
:
"
\n\n
| header | header |
\n
| ------ | ------ |
\n
| cell | cell |
\n
| cell | cell |
\n\n
"
,
endStr
:
""
},
{
name
:
"
fullScreen
"
,
icon
:
"
fullScreen
"
,
tip
:
"
全屏模式
"
}
]
};
},
methods
:
{
...
mapMutations
([
"
setShowPreview
"
])
setShowPreview
(
val
)
{
this
.
$emit
(
"
update:showPreview
"
,
val
);
},
updateText
(
val
)
{
this
.
$emit
(
"
update:text
"
,
val
);
this
.
$emit
(
"
update:selectionInfo
"
,
{
selectorId
:
""
,
selectionStart
:
""
,
selectionEnd
:
""
});
}
}
};
</
script
>
...
...
src/components/header/tool-button.vue
浏览文件 @
af823f10
...
...
@@ -8,20 +8,36 @@
</div>
</
template
>
<
script
>
import
{
mapMutations
,
mapState
}
from
"
vuex
"
;
import
{
updateText
}
from
"
@/assets/js/utils
"
;
import
{
formatText
}
from
"
@/assets/js/utils
"
;
export
default
{
props
:
{
info
:
{
type
:
Object
,
default
:
()
=>
{}
},
fullScreen
:
{
type
:
Boolean
,
default
:
false
},
text
:
{
type
:
String
,
default
:
''
},
selectionInfo
:
{
type
:
Object
,
default
:
()
=>
{}
},
uploadPath
:
{
type
:
String
,
default
:
''
}
},
computed
:
{
...
mapState
([
"
selectionInfo
"
,
"
text
"
,
"
ulNum
"
])
data
()
{
return
{
ulNum
:
1
}
},
methods
:
{
...
mapMutations
([
"
setFullScreen
"
,
"
setText
"
,
"
setUlNum
"
]),
handleTool
(
type
,
startStr
,
endStr
)
{
switch
(
type
)
{
case
"
bold
"
:
...
...
@@ -32,20 +48,26 @@ export default {
case
"
ul
"
:
case
"
task
"
:
case
"
table
"
:
updateText
(
startStr
,
endStr
);
this
.
updateText
(
startStr
,
endStr
);
break
;
case
"
ol
"
:
let
ulNum
=
this
.
ulNum
;
updateText
(
`\n
${
ulNum
++
}
. `
,
""
);
this
.
setUlNum
(
ulNum
);
this
.
updateText
(
`\n
${
ulNum
}
. `
,
""
);
this
.
ulNum
++
break
;
case
"
fullScreen
"
:
this
.
setFullScreen
(
true
);
this
.
$emit
(
'
setFullScreen
'
,
true
)
break
;
default
:
break
;
}
}
},
updateText
(
startStr
,
endStr
)
{
const
originalText
=
this
.
text
const
selectionInfo
=
this
.
selectionInfo
const
newText
=
formatText
(
originalText
,
selectionInfo
,
startStr
,
endStr
)
this
.
$emit
(
'
updateText
'
,
newText
)
}
}
};
</
script
>
...
...
src/main.js
浏览文件 @
af823f10
import
Vue
from
"
vue
"
;
import
App
from
"
./App
"
;
import
store
from
"
./store
"
;
import
Vtip
from
"
vtip
"
;
import
"
vtip/lib/index.min.css
"
;
import
{
initStyle
,
isNotEmpty
,
updateText
}
from
"
@/assets/js/utils
"
;
import
{
initStyle
,
isNotEmpty
}
from
"
@/assets/js/utils
"
;
import
"
@/assets/style/global.less
"
;
Vue
.
use
(
Vtip
.
directive
);
...
...
@@ -19,23 +18,23 @@ function initMdEditor(obj) {
}
=
obj
;
if
(
!
el
||
!
document
.
querySelector
(
el
))
throw
new
Error
(
"
请指定容器
"
);
if
(
isNotEmpty
(
themeOptions
))
initStyle
(
themeOptions
);
if
(
isNotEmpty
(
canAttachFile
))
store
.
commit
(
"
setCanAttachFile
"
,
canAttachFile
);
if
(
isNotEmpty
(
placeholder
))
store
.
commit
(
"
setPlaceholder
"
,
placeholder
);
new
Vue
({
store
,
render
:
h
=>
h
(
App
,
{
on
:
{
change
(
val
)
{
onChange
(
val
);
},
upload
(
val
)
{
upload
(
{
val
,
callback
}
)
{
onUpload
(
val
,
function
(
res
)
{
updateText
(
"
\n\n
![img](
"
,
`
${
res
}
)\n`
);
callback
(
res
);
});
}
},
props
:
{
canAttachFile
,
placeholder
}
})
}).
$mount
(
el
);
...
...
src/store/index.js
已删除
100644 → 0
浏览文件 @
f529497f
import
Vue
from
"
vue
"
;
import
Vuex
from
"
vuex
"
;
import
{
formatText
}
from
"
@/assets/js/utils
"
;
Vue
.
use
(
Vuex
);
export
default
new
Vuex
.
Store
({
state
:
{
fullScreen
:
false
,
isFocus
:
false
,
showPreview
:
false
,
placeholder
:
"
请输入内容
"
,
toolButtonList
:
[
{
name
:
"
bold
"
,
icon
:
"
bold
"
,
tip
:
"
粗体
"
,
startStr
:
"
**
"
,
endStr
:
"
**
"
},
{
name
:
"
italic
"
,
icon
:
"
italic
"
,
tip
:
"
斜体
"
,
startStr
:
"
_
"
,
endStr
:
"
_
"
},
{
name
:
"
quote
"
,
icon
:
"
baojiaquotation
"
,
tip
:
"
插入引用
"
,
startStr
:
"
\n
>
"
,
endStr
:
""
},
{
name
:
"
code
"
,
icon
:
"
code
"
,
tip
:
"
插入代码
"
,
startStr
:
"
`
"
,
endStr
:
"
`
"
},
{
name
:
"
link
"
,
icon
:
"
lianjie
"
,
tip
:
"
添加链接
"
,
startStr
:
"
[
"
,
endStr
:
"
](url)
"
},
{
name
:
"
ul
"
,
icon
:
"
unorderedList
"
,
tip
:
"
添加无序列表
"
,
startStr
:
"
\n
-
"
,
endStr
:
""
},
{
name
:
"
ol
"
,
icon
:
"
youxuliebiao
"
,
tip
:
"
添加有序列表
"
,
startStr
:
""
,
endStr
:
""
},
{
name
:
"
task
"
,
icon
:
"
renwu
"
,
tip
:
"
添加任务列表
"
,
startStr
:
"
\n
- [ ]
"
,
endStr
:
""
},
{
name
:
"
table
"
,
icon
:
"
biaoge
"
,
tip
:
"
添加表格
"
,
startStr
:
"
\n\n
| header | header |
\n
| ------ | ------ |
\n
| cell | cell |
\n
| cell | cell |
\n\n
"
,
endStr
:
""
},
{
name
:
"
fullScreen
"
,
icon
:
"
fullScreen
"
,
tip
:
"
全屏模式
"
}
],
fileList
:
""
,
ulNum
:
1
,
// text: `
// # 标题一标题一标题一
// ## 标题二标题二
// 666\`行内代码\`666
// \`\`\`js
// // 是注释呀
// /**
// * @params x
// */
// function fn() {
// return null;
// }
// \`\`\`
// **粗体文字**
// _斜体文字_
// > 这段是引用的内容\n
// > 这段是引用的内容
// > 这段是引用的内容
// [链接](url)
// - 无序列表
// - 无序列表
// - 无序列表
// 1. 有序列表
// 2. 有序列表
// 3. 有序列表
// - [ ] 任务列表
// - [x] 任务列表
// - [ ] 任务列表
// | header | header |
// | ------ | ------ |
// | cell | cell |
// | cell | cell |`,
selectionInfo
:
""
,
text
:
""
,
html
:
""
,
canAttachFile
:
true
},
mutations
:
{
setFullScreen
(
state
,
val
)
{
state
.
fullScreen
=
val
;
},
setShowPreview
(
state
,
val
)
{
state
.
showPreview
=
val
;
},
setFocus
(
state
,
val
)
{
state
.
isFocus
=
val
;
},
setText
(
state
,
val
)
{
state
.
text
=
val
;
state
.
selectionInfo
=
""
;
},
setSelectionInfo
(
state
,
val
)
{
state
.
selectionInfo
=
val
;
},
setHtml
(
state
,
val
)
{
state
.
html
=
val
;
},
setUlNum
(
state
,
val
)
{
state
.
ulNum
=
val
;
},
setCanAttachFile
(
state
,
val
)
{
state
.
canAttachFile
=
val
;
},
setFileList
(
state
,
val
)
{
state
.
fileList
=
val
;
},
setPlaceholder
(
state
,
val
)
{
state
.
placeholder
=
val
;
}
}
});
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录