使用deitormd
实现步骤
- 准备一个添加页面的静态页面
- 把添加页面对应样式和css和js进行对应引入,同时把vue/jquery引入
- 添加springmvc的理由跳转到添加页面
- 在首页添加一个新增文章的按钮,跳转到springmvc指定的路由
- 引入md编辑器
- 实现保存文章的功能
- 实现md编辑器的文章上传的功能。
- 下载md编辑器 -
准备工作
官网:editormd地址
下载:https://pandao.github.io/editor.md/
官网案例
<link rel="stylesheet" href="editormd/css/editormd.css" />
<div id="test-editor">
<textarea style="display:none;">### 关于 Editor.md
**Editor.md** 是一款开源的、可嵌入的 Markdown 在线编辑器(组件),基于 CodeMirror、jQuery 和 Marked 构建。
</textarea>
</div>
<script src="https://cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<script src="editormd/editormd.min.js"></script>
<script type="text/javascript">
$(function() {
var editor = editormd("test-editor", {
// width : "100%",
// height : "100%",
path : "/editormd/lib/"
});
});
</script>
- 准备一个添加页面的静态页面
- 把添加页面对应样式和css和js进行对应引入,同时把vue引入
- 添加springmvc的理由跳转到添加页面
@Controller
@Slf4j
public class BlogController {
@GetMapping("/blog/add")
public ModelAndView toAdd(){
// 3: 定义模型视图
ModelAndView modelAndView = new ModelAndView();
// 2: 指定跳转的页面
modelAndView.setViewName("/blog/add");
return modelAndView;
}
}
上面代码一定要注意:注解一定是@Controller。如果有异步的方法,就在需要异步的方法上增加@ResponseBody.+
访问:http://localhost:8888/blog/add
注意css/js路径一定要增加/
<link rel="stylesheet" type="text/css" href="/editormd/css/editormd.css" /> <script src="/js/jquery.min.js"></script> <script src="/editormd/editormd.js"></script>
editormd的路径记得修改一下:
path: '/editormd/lib/',
- 在首页添加一个新增文章的按钮,跳转到springmvc指定的路由
<div class="square-operation-detail" style="position: relative">
<div style="position:absolute;right:0;z-index: 110"><a href="/blog/add">添加文章</a></div>
</div>
- 实现保存文章的功能
添加后端新增文章的接口
/**
* 新增和添加文章接口
*
* @param blog
* @return
*/
@PostMapping("/api/blog/saveupdate")
@ResponseBody
public Blog saveBlog(@RequestBody Blog blog) {
boolean flag = blogService.saveOrUpdate(blog);
return flag ? blog : null;
}
注意1:添加是一种异步交互处理,所以一定要记得增加@ResponseBody
注意2:axios的默认的post参数的接受是一种:application/json的类型,所以如果接口的参数一个bean就必须在签名增加@RequestBody才能将参数注入到对象中。JQuery不需要,因为JQuery默认的 post参数是:application/xxxx-form-urlencoding,所以springmvc参数注入对象不不需要增加@RequestBody。
定义一个div#app
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title></title>
<link rel="stylesheet" type="text/css" href="/editormd/css/editormd.css" />
<link rel="stylesheet" type="text/css" href="/css/add.css" />
</head>
<body>
<div id="app">
<div id="main" class="yykk_editbox">
<div class="article-head clearfix">
<select name="topicCategoryId" class="article-title" id="category" style="width: 180px;">
<option value="1">程序人生</option>
<option value="10">面试</option>
<option value="11">数据库</option>
<option value="12">安全</option>
<option value="13">测试</option>
<option value="2">管理</option>
<option value="3">教程</option>
<option value="4" selected="selected">学习笔记</option>
<option value="5">踩坑记录</option>
<option value="6">架构</option>
<option value="7">后台</option>
<option value="8">前端</option>
<option value="9">问答</option>
</select>
<input type="text" id="article_title" class="article-title" placeholder="请在此输入标题" style="width: 28%; ">
<input type="text" id="article_title-desc" class="article-title" placeholder="用一句话描述此文章" style="width: 50%; font-weight:400;font-size: 12px;position: relative;top:-2px;">
<span class="publish-btn js-article-publish">发表</span>
</div>
<!-- 文章的主体内容 textarea -->
<div id="article-content"> </div>
</div>
</div>
<script src="/js/jquery.min.js"></script>
<script src="/editormd/editormd.js"></script>
<script src="/js/vue.global.js"></script>
<script src="/js/axios.min.js"></script>
<script src="/js/blog/add.js"></script>
</body>
</html>
定义add.js并初始化一个vue实例
const vm = Vue.createApp({
// 数据模型
data(){
return {
}
},
// 生命周期
mounted(){
},
// 事件定义
methods:{
}
}).mount("#app");
如何获取md的html和md标记格式内容
// 1:获取文本编辑器的内容
this.blog.htmlcontent = testEditor.getHTML();
this.blog.content = testEditor.getMarkdown();
// 2:获取分类标题名称
this.blog.categoryTitle = this.getCategoryTitle(this.blog.categoryId);
通过axios进入异步请求保存文章到数据库中
// 3: 执行异步请求
axios.post("/api/blog/saveupdate",this.blog).then(res=>{
console.log(res)
})
完整的JS
//初始化编辑器
var testEditor;
$(function() {
testEditor = editormd("article-content", {
width: "100%",
height: "82vh",
path: '/editormd/lib/',
theme: "white",
previewTheme: "white",
editorTheme: "pastel-on-white",
markdown: "",
codeFold: true,
saveHTMLToTextarea: true, // 保存 HTML 到 Textarea
searchReplace: true,
//watch : false, // 关闭实时预览
htmlDecode: "style,script,iframe|on*", // 开启 HTML 标签解析,为了安全性,默认不开启
//toolbar : false, //关闭工具栏
//previewCodeHighlight : false, // 关闭预览 HTML 的代码块高亮,默认开启
emoji: true,
taskList: true,
tocm: true, // Using [TOCM]
tex: true, // 开启科学公式TeX语言支持,默认关闭
flowChart: true, // 开启流程图支持,默认关闭
sequenceDiagram: true, // 开启时序/序列图支持,默认关闭,
dialogLockScreen: false, // 设置弹出层对话框不锁屏,全局通用,默认为true
dialogShowMask: false, // 设置弹出层对话框显示透明遮罩层,全局通用,默认为true
dialogDraggable: false, // 设置弹出层对话框不可拖动,全局通用,默认为true
dialogMaskOpacity: 0.4, // 设置透明遮罩层的透明度,全局通用,默认值为0.1
dialogMaskBgColor: "#000", // 设置透明遮罩层的背景颜色,全局通用,默认为#fff
imageUpload: true,
imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
imageUploadURL: "/Center/RichTextUpload",
onload: function() {
// this.fullscreen();
// this.unwatch();
// this.watch().fullscreen();
//
// this.setMarkdown("#PHP");
// this.width("100%");
// this.height(480);
// this.resize("100%", 640);
//获取编辑器内容
// testEditor.gotoLine(90); //转到第90行
//
// testEditor.show(); //显示编辑器
//
// testEditor.hide(); //隐藏编辑器
//
// alert(testEditor.getMarkdown()); //获取编辑器内容(不含html)
//
// alert(testEditor.getHTML()); //获取编辑器html内容
//
// testEditor.watch(); //开启双窗口对比
//
// testEditor.unwatch(); //取消双窗口对比
//
// testEditor.previewing(); //预览效果
//
// testEditor.fullscreen(); //全屏(按ESC取消)
//
// testEditor.showToolbar(); //显示工具栏
//
// testEditor.hideToolbar(); //隐藏工具栏
//
// testEditor.config({
// tocDropdown: true,
// tocTitle: "目录 Table of Contents",
// }); //TOC下拉菜单
//
// testEditor.config("tocDropdown", false); //TOC默认
}
});
});
const vm = Vue.createApp({
// 数据模型
data(){
return {
blog:{
id:"",//新增的时候是null,修改时候是有具体的id
title:"",
categoryId:"1",
categoryTitle:"程序人生",
htmlcontent:"",
content:"",
description:""
},
categoryList:[
{id:1,name:"程序人生",checked:false},
{id:2,name:"Java",checked:false},
{id:3,name:"Web",checked:'selected'},
{id:4,name:"数据库",checked:false}
]
}
},
// 生命周期
mounted(){
},
// 事件定义
methods:{
// 这个方法就是专门获取分类名称
changeCategory(ev){
var selectIndex = ev.target.selectedIndex;
var options = ev.target.options;
this.blog.categoryId = options[selectIndex].value;
this.blog.categoryTitle = options[selectIndex].text;
},
getCategoryTitle(categoryId){
// var obj = {};
// // 根据数据库查询出来的分类组合对象
// for(let i=0;i<this.categoryList.length;i++){
// obj[this.categoryList[i].id] = this.categoryList[i].name;
// }
// // 目的是方便获取
// return obj[categoryId];
// 根据数据库查询出来的分类组合对象
var title = "";
for(let i=0;i<this.categoryList.length;i++){
if(this.categoryList[i].id == categoryId){
title = this.categoryList[i].name;
break;
}
}
// 目的是方便获取
return title;
},
saveBlog:function(){
// 1:获取文本编辑器的内容
this.blog.htmlcontent = testEditor.getHTML();
this.blog.content = testEditor.getMarkdown();
// 2:获取分类标题名称
this.blog.categoryTitle = this.getCategoryTitle(this.blog.categoryId);
// 3: 执行异步请求
axios.post("/api/blog/saveupdate",this.blog).then(res=>{
console.log(res)
})
}
}
}).mount("#app");
总结
- 修改和添加它们其实是可以公用一个页面的。它的区别只在一个:是否有id,如果有id就是修改,如果没有id就是新增。