富文本编辑器:editor.md

富文本编辑器

Editormd

简介

Editor.md——功能非常丰富的编辑器,左端编辑,右端预览,非常方便,完全免费

  • 官网:https://pandao.github.io/editor.md/

在这里插入图片描述

主要特征
  • 支持“标准” Markdown / CommonMark 和 Github 风格的语法,也可变身为代码编辑器;

  • 支持实时预览、图片(跨域)上传、预格式文本/代码/表格插入、代码折叠、搜索替换、只读模式、自定义样式主题和多语言语法高亮等功能;

  • 支持 ToC 目录(Table of Contents)、Emoji 表情Task lists@链接等 Markdown 扩展语法;

  • 支持 TeX 科学公式(基于 KaTeX)、流程图 Flowchart 和 时序图 Sequence Diagram;

  • 支持识别和解析 HTML 标签,并且支持自定义过滤标签解析,具有可靠的安全性和几乎无限的扩展性;

  • 支持 AMD / CMD 模块化加载(支持 Require.js & Sea.js),并且支持自定义扩展插件;

  • 兼容主流的浏览器(IE8+)和 Zepto.js,且支持 iPad 等平板设备;

  • 支持自定义主题样式;

注:这里我们使用 SpringBoot 集成 Editor.md

下载安装

我们可以在官网下载它:https://pandao.github.io/editor.md/ , 得到它的压缩包!

解压以后,在examples目录下面,可以看到他的很多案例使用!学习,其实就是看人家怎么写的,然后进行模仿就好了!

我们可以将整个解压的文件倒入我们的项目,将一些无用的测试和案例删掉即可!

在这里插入图片描述

  • 下载好的目录解压

在这里插入图片描述

创建数据库

数据库设计

  • article:文章表
字段备注
idint文章的唯一ID
authorvarchar作者
titlevarchar标题
contentlongtext文章的内容
  • 建表SQL:
CREATE TABLE `article` (
  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'int文章的唯一ID',
  `author` varchar(50) NOT NULL COMMENT '作者',
  `title` varchar(100) NOT NULL COMMENT '标题',
  `content` longtext NOT NULL COMMENT '文章的内容',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

基础项目搭建

  • 引入依赖
<!-- mysql依赖 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- jdbc依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- druid依赖 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.17</version>
</dependency>
<!-- lombok依赖 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<!-- mybatis-plus依赖 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.2</version>
</dependency>
  • 配置 application.xml
# 配置端口
server:
  port: 8001

spring:
  # 配置数据源
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
    username: root
    password: 123456
  # 配置静态资源访问
  resources:
    static-locations: classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/, classpath:/templates/
  # 配置Thymeleaf模板
  thymeleaf:
    cache: false

# 配置mybatisPlus
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  • 实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Article {
    /**
     * 文章的唯一ID
     */
    private int id;
    /**
     * 作者名
     */
    private String author;
    /**
     * 标题
     */
    private String title;
    /**
     * 文章的内容
     */
    private String content;

}
  • mapper 接口
@Mapper
public interface ArticleMapper extends BaseMapper<Article> {

}
  • service 接口
public interface ArticleService extends IService<Article> {
    
}
  • impl 实现类
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {
    
}

编写Controller测试一下是否OK?

文章编辑整合(重点)

1、 导入 editor.md 资源,删除多余文件。

在这里插入图片描述

2、 编辑文章页面 editor.html,需要映入jQuery;

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>文章发布</title>
</head>
<link rel="stylesheet" th:href="@{/editormd/css/editormd.css}"/>
<body>
    <div>
        <!-- 文章发布表单 -->
        <form id="mdEditorForm">
            <div>
                标题:<input type="text" name="title">
            </div>
            <div>
                作者:<input type="text" name="author">
            </div>
            <!-- Editor.md 富文本编辑器 -->
            <div id="article-content">
                <textarea name="content" id="content" style="display:none;"></textarea>
            </div>
        </form>
    </div>
</body>
<script th:src="@{/js/jquery.min.js}"></script>
<script th:src="@{/editormd/js/editormd.js}"></script>
<script>
    $(function() {
        var editor = editormd("article-content", {
            width: "95%",   // 宽
            height: "400px",    // 高
            path : "/editormd/lib/"    // 加载编辑器lib路径
        });
    });
</script>
</html>

3、 编辑Controller,进行跳转;

@Controller
public class ArticleController {
    
    /**
     * 文章页面跳转
     * @return editor.html
     */
    @GetMapping("/toEditor")
    public String toEditor(){
        return "editor";
    }

}

4、 访问 http://localhost:8001/toEditor,结果显示:

在这里插入图片描述

Editor.md 参数解析

  • 常用参数
width: "95%",   // 宽
height: "400px",    // 高
path : "/editormd/lib/",   // 加载编辑器lib路径
syncScrolling: "single",    // 设置同步显示,三个选项[ true| false| "single",默认为true
saveHTMLToTextarea : true,    // 保存 HTML 到 Textarea
emoji: true,    // 是否开启表情功能,默认为false
tex : true, // 开启科学公式TeX语言支持,默认关闭
flowChart : true,   // 开启流程图支持,默认关闭
sequenceDiagram : true, // 开启时序/序列图支持,默认关闭,
//图片上传
imageUpload : true, // 开启图片上传
imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],    // 图片上传的类型
imageUploadURL : "",    // 图片上传路径
// 初始化函数
onload : function() {
    // alert("初始化函数");
},
/*指定需要显示的功能按钮*/
toolbarIcons : function() {
    return ["undo","redo","|",
        "bold","del","italic","quote","ucwords","uppercase","lowercase","|",
        "h1","h2","h3","h4","h5","h6","|",
        "list-ul","list-ol","hr","|",
        "link","reference-link","image","code","preformatted-text",
        "code-block","table","datetime","emoji","html-entities","pagebreak","|",
        "goto-line","watch","preview","fullscreen","clear","search","|",
        "help","releaseIcon", "index"]
},
/*自定义功能按钮*/
toolbarIconTexts : {
    
},
/*给自定义按钮指定回调函数*/
toolbarHandlers:{
    
}

图片上传问题

  • 前端 js 中添加配置
//图片上传
imageUpload : true, // 开启图片上传
imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],    // 图片上传的类型
imageUploadURL : "/fileUpload",    // 图片上传路径
  • 后端接口请求,接收保存图片!
@RestController
public class ArticleApi {

    @PostMapping("/fileUpload")
    public Map fileUpload(@RequestParam("editormd-image-file") MultipartFile file, String guid) throws IOException {
        Map<String, Object> hashMap = new LinkedHashMap<>();

        // 获得后缀类型
        String type = file.getOriginalFilename().substring(file.getOriginalFilename().indexOf("."), file.getOriginalFilename().length());
        // 获得文件上传路径
        String path = System.getProperty("user.dir")+"/EditorText/src/main/resources/static/image/";
        // 将路径传给 File 对象
        File realPath = new File(path);
        // 判断路径上的文件夹是否存在,不存在就创建
        if (!realPath.exists()){
            realPath.mkdir();
        }
        // 设置上传的文件名字
        String filename = guid + type;
         //通过CommonsMultipartFile的方法直接写文件
        file.transferTo(new File(realPath +"/"+ filename));

        // 返回上传路径
        hashMap.put("url","/image/" + filename);
        // 返回是否成功
        hashMap.put("success", 1);
        // 返回信息提示
        hashMap.put("message", "upload success!");
        return hashMap;
    }

}

参数 @RequestParam(“editormd-image-file”) MultipartFile file 是隐藏参数,在请求头中不会显示

在这里插入图片描述

  • 解决文件回显显示的问题,设置虚拟目录映射!
@Configuration
public class MyWebConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        String property = System.getProperty("user.dir");
        registry.addResourceHandler("/image/**")
                .addResourceLocations("file:"+property+"/EditorText/src/main/resources/static/image/");
    }
}

表情包问题

在外面设置图片虚拟路径显示后,图片显示没问题了,但表情包就出现了Bug!

  • 解决

在图片虚拟路径后面接着添加

registry.addResourceHandler("/editormd/**")
                .addResourceLocations("file:"+property+"/EditorText/src/main/resources/static/editormd/");

配置 editormd 的虚拟路径即可!

推荐静态资源中的文件都配置虚拟路径,缓存清理掉后,静态资源文件可能会找不到

@Configuration
public class MyWebConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        String property = System.getProperty("user.dir");
        registry.addResourceHandler("/image/**")
                .addResourceLocations("file:"+property+"/EditorText/src/main/resources/static/image/");
        registry.addResourceHandler("/editormd/**")
                .addResourceLocations("file:"+property+"/EditorText/src/main/resources/static/editormd/");
        registry.addResourceHandler("/js/**")
                .addResourceLocations("file:"+property+"/EditorText/src/main/resources/static/js/");
        registry.addResourceHandler("/layui/**")
                .addResourceLocations("file:"+property+"/EditorText/src/main/resources/static/layui/");
    }
}

添加文章

  • 前端 js 中添加配置, 定义发布文章和返回首页按钮
/*自定义功能按钮,下面我自定义了2个,一个是发布,一个是返回首页*/
toolbarIconTexts : {
    releaseIcon : "<span bgcolor=\"gray\">发布</span>",
    index : "<span bgcolor=\"red\">返回首页</span>"
},
/*给自定义按钮指定回调函数*/
toolbarHandlers:{
    releaseIcon : function(cm, icon, cursor, selection) {
        //表单提交
        $.ajax({
            url: "",
            type: "POST",
            data: mdEditorForm.serialize(),
            success: function (result) {
                alert(result.magger);
            }
        });
    },
    index : function(){
        window.location.href = '/';
    }
}
  • 后端接口请求,接收前端表单存入数据库!
@PostMapping("/addArticle")
public Map addArticle(Article article) {
    Map<String, Object> hashMap = new LinkedHashMap<>();
    boolean save = articleService.save(article);
    if (save) {
        hashMap.put("magger", "添加成功");
    } else{
        hashMap.put("magger", "添加失败");
    }
    return hashMap;
}

测试一下,看是否能添加成功!

文章展示

1、 Controller中添加方法

// 查看文章
@GetMapping("/toArticle/{id}")
public String toArticle(@PathVariable("id") Integer id, Model model){
    Article article = articleService.getById(id);
    model.addAttribute("article",article);
    return "article";
}

2、 编写页面 article.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>文章展示</title>
</head>
<link rel="stylesheet" th:href="@{/editormd/css/editormd.css}"/>
<body>

<div>
    <h2 style="margin: auto 0" th:text="${article.title}"></h2>
    作者:<span style="float: left" th:text="${article.author}"></span>

    <!--文章主体内容-->
    <div id="doc-content">
        <textarea style="display:none;" placeholder="markdown" th:text="${article.content}"></textarea>
    </div>
</div>

</body>
<script th:src="@{/js/jquery.min.js}"></script>
<script th:src="@{/editormd/js/editormd.js}"></script>
<script th:src="@{/editormd/lib/marked.min.js}"></script>
<script th:src="@{/editormd/lib/prettify.min.js}"></script>
<script th:src="@{/editormd/lib/raphael.min.js}"></script>
<script th:src="@{/editormd/lib/underscore.min.js}"></script>
<script th:src="@{/editormd/lib/sequence-diagram.min.js}"></script>
<script th:src="@{/editormd/lib/flowchart.min.js}"></script>
<script th:src="@{/editormd/lib/jquery.flowchart.min.js}"></script>

<script>
    $(function () {
        var testEditor = editormd.markdownToHTML("doc-content", {//注意:这里是上面DIV的id
            htmlDecode: "style,script,iframe",
            emoji: true,
            taskList: true,
            tocm: true,
            tex: true, // 默认不解析
            flowChart: true, // 默认不解析
            sequenceDiagram: true, // 默认不解析
            codeFold: true
        });
    });
</script>
</html>

重启项目,访问进行测试!大功告成!

在Vue.js中使用

基础vue工程搭建

1、 打开控制命令符,选择创建位置

在这里插入图片描述

2、 创建 vue 工程

vue init webpack vuedemo5

在这里插入图片描述

  • 创建完成显示

在这里插入图片描述

3、 安装、运行工程,测试是否成功

  • 进入工程目录
cd vuedemo5
  • 安装

i 是 install 的简写

npm install
或者
npm i
  • 运行
npm run dev

显示:

在这里插入图片描述

打开浏览器输入网址:http://localhost:8080

在这里插入图片描述

初始化 vue 工程成功!

使用 idea 接管工程!

文章编辑整合(重点)

1、 导入 edtior.md 文件,以及 jquery.js

在这里插入图片描述

2、 打开 Terminal,安装插件

在这里插入图片描述

  • 安装 scriptjs
npm i scriptjs
  • 安装 aixos
npm install --save vue-axios

main.js中引用

import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)

3、 创建 Edtior.vue,并配置路由

<template>
  <div>
    <link rel="stylesheet" href="/static/editormd/css/editormd.css"/>
    <!-- 文章发布表单 -->
    <form id="mdEditorForm">
      <div>
        标题:<input type="text" name="title">
      </div>
      <div>
        作者:<input type="text" name="author">
      </div>
      <!-- Editor.md 富文本编辑器 -->
      <div id="article-content">
        <textarea name="content" id="content" style="display:none;"></textarea>
      </div>
    </form>
  </div>
</template>

<script>
  import scriptjs from 'scriptjs'
    export default {
        name: "Edtior",
        mounted(){
          var _this = this;
          (async () =>{
            await _this.loadJs("/static/js/jquery.min.js");
            await _this.loadJs("/static/editormd/js/editormd.js");
            _this.jsLoadOver = true;
            editormd("article-content", {
              width: "95%",   // 宽
              height: "400px",    // 高
              path : "/static/editormd/lib/",    // 加载编辑器lib路径
              syncScrolling: "single",    // 设置同步显示,三个选项[ true| false| "single",默认为true
              saveHTMLToTextarea : true,    // 保存 HTML 到 Textarea
              emoji: true,    // 开启表情功能,默认为false
              // theme: "dark",//工具栏主题
              // previewTheme: "dark",//预览主题
              // editorTheme: "pastel-on-dark",//编辑主题
              tex : true, // 开启科学公式TeX语言支持,默认关闭
              flowChart : true,   // 开启流程图支持,默认关闭
              sequenceDiagram : true, // 开启时序/序列图支持,默认关闭,
              //图片上传
              imageUpload : true, // 开启图片上传
              imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],    // 图片上传的类型
              imageUploadURL : "http://localhost:8001/fileUpload", // 图片上传路径
              /*指定需要显示的功能按钮*/
              toolbarIcons : function() {
                return ["undo","redo","|",
                  "bold","del","italic","quote","ucwords","uppercase","lowercase","|",
                  "h1","h2","h3","h4","h5","h6","|",
                  "list-ul","list-ol","hr","|",
                  "link","reference-link","image","code","preformatted-text",
                  "code-block","table","datetime","emoji","html-entities","pagebreak","|",
                  "goto-line","watch","preview","fullscreen","clear","search","|",
                  "help","releaseIcon", "index"]
              },
              /*自定义功能按钮,下面我自定义了2个,一个是发布,一个是返回首页*/
              toolbarIconTexts : {
                releaseIcon : "<span bgcolor=\"gray\">发布</span>",
                index : "<span bgcolor=\"red\">返回首页</span>"
              },
              /*给自定义按钮指定回调函数*/
              toolbarHandlers:{
                releaseIcon : function(cm, icon, cursor, selection) {
                  _this.axios({
                    method: 'post',
                    url: 'http://localhost:8001/addArticle',
                    data: $("#mdEditorForm").serialize()
                  }).then(function (response) {
                    console.log(response)
                  })
                },
                index : function(){
                  window.location.href = '/';
                }
              }
            })
          })();
        },
        methods: {
          loadJs: function (url) {
            return new Promise((resolve) => {
              scriptjs(url, () =>{
                resolve();
              })
            })
          }
        }
    }
</script>

<style scoped>

</style>

  • 路由配置
import Vue from 'vue'
import Router from 'vue-router'

import editor from '../components/Edtior'

Vue.use(Router)

export default new Router({
  mode: 'history',
  routes: [
    {path:"/", name: editor, component:editor}
  ]
})

4、 启动项目

npm run dev
  • 结果显示
在这里插入图片描述

参考文章:https://www.kuangstudy.com/bbs/1366420418474299393

  • 解决

找到 static/editormd/plugins/image-dialog/image-dialog.js 文件

查找 submitHandler 函数

将函数里面的内容修改为

var form = dialog.find("[enctype=\"multipart/form-data\"]")[0];
                      var formData = new FormData(form);
                      $.ajax({
                        type: 'post',
                        // url: "http://localhost:8001/fileUpload", // 你的服务器端的图片上传接口。如果你设置了 imageUploadURL,那么可以使用下面的方式
                        url: settings.imageUploadURL + (settings.imageUploadURL.indexOf("?") >= 0 ? "&" : "?") + "guid=" + guid,
                        data: formData,
                        cache: false,
                        processData: false,
                        contentType: false,
                        success: function(data, textStatus, jqXHR) {
                          // console.log(data);
                          // console.log(textStatus);
                          // console.log(jqXHR);
                          if (data.success === 1) { // 上传成功
                            dialog.find("[data-url]").val(data.url); // 设置图片地址
                          }
                          else {
                            alert(data.message); // 上传失败,弹出警告信息
                          }
                        },
                        error: function(XMLHttpRequest, textStatus, errorThrown) {
                          // console.log(XMLHttpRequest);
                          // console.log(textStatus);
                          // console.log(errorThrown);
                        }
                      });
                      loading(false);
                      return false;

函数后面的

dialog.find("[type=\"submit\"]").bind("click", submitHandler).trigger("click"); 

修改为

dialog.bind("click", submitHandler).trigger("click");

重启测试~问题解决!

文章展示

1、 编写页面 article.vue

<template>
  <div>
    <h2 style="margin: auto 0">{{articles.title}}</h2>
    作者:<span style="float: left">{{articles.author}}</span>
    <!--文章主体内容-->
    <div id="doc-content">
      <textarea style="display:none;" placeholder="markdown" >{{articles.content}}</textarea>
    </div>
  </div>
</template>

<script>
  import scriptjs from 'scriptjs'
    export default {
        props: ['id'],
        name: "Article",
        data(){
          return{
            articles: {
              title: "",
              author: "",
              content: ""
            }
          }
        },
      mounted(){
        var _this = this;
        (async () => {
          await _this.loadJs("/static/js/jquery.min.js");
          await _this.loadJs("/static/editormd/js/editormd.js");
          await _this.loadJs("/static/editormd/lib/marked.min.js");
          await _this.loadJs("/static/editormd/lib/prettify.min.js");
          await _this.loadJs("/static/editormd/lib/raphael.min.js");
          await _this.loadJs("/static/editormd/lib/underscore.min.js");
          await _this.loadJs("/static/editormd/lib/sequence-diagram.min.js");
          await _this.loadJs("/static/editormd/lib/flowchart.min.js");
          await _this.loadJs("/static/editormd/lib/jquery.flowchart.min.js");
          _this.jsLoadOver = true;
          var testEditor = editormd.markdownToHTML("doc-content", {//注意:这里是上面DIV的id
            htmlDecode: "style,script,iframe",
            emoji: true,
            taskList: true,
            tocm: true,
            tex: true, // 默认不解析
            flowChart: true, // 默认不解析
            sequenceDiagram: true, // 默认不解析
            codeFold: true
          });
        })()

        _this.axios({
          method: 'get',
          url: 'http://localhost:8001/getArticle/'+ _this.id
        }).then(function (response) {
          _this.articles = response.data.article;
        })
      },
      methods:{
        loadJs: function (url) {
          return new Promise((resolve) => {
            scriptjs(url, () =>{
              resolve();
            })
          })
        }
      }
    }
</script>

<style scoped>

</style>

2、 配置路由

{path:"/article/:id", name: article, component:article, props: true}

3、 网站输入http://localhost:8004/article/2

测试成功~富文本编辑器搞定!
emoji: true,
taskList: true,
tocm: true,
tex: true, // 默认不解析
flowChart: true, // 默认不解析
sequenceDiagram: true, // 默认不解析
codeFold: true
});
})()

    _this.axios({
      method: 'get',
      url: 'http://localhost:8001/getArticle/'+ _this.id
    }).then(function (response) {
      _this.articles = response.data.article;
    })
  },
  methods:{
    loadJs: function (url) {
      return new Promise((resolve) => {
        scriptjs(url, () =>{
          resolve();
        })
      })
    }
  }
}

2、 配置路由

```java
{path:"/article/:id", name: article, component:article, props: true}

3、 网站输入http://localhost:8004/article/2

测试成功~富文本编辑器搞定!

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值