编程日记03|个人网站 文本编辑器

简介: 编程日记03|个人网站 文本编辑器
 <div>
    <el-input
  type="text"
  placeholder="在此输入标题"
  v-model="title"
  maxlength="60"
  show-word-limit
>
</el-input>
<br>   <br>
  </div>
  <quill-editor
    v-model="editContent"
    ref="myQuillEditor"
    :options="editorOption"
    @blur="onEditorBlur($event)"
    @focus="onEditorFocus($event)"
    @change="onEditorChange($event)"
  >
  </quill-editor>
          <!-- 添加发布和定时发布按钮  v-debounce="3000"设定延时 三秒钟内按下多次只会触发一次事件-->
          <br>
          <el-button :disabled="isPublishing" @click="publish" type="primary" v-debounce="3000">发布</el-button>
  <!-- <hr /> -->
 
  <!-- 读取展示 -->
  <!-- <div class="ql-container ql-snow">
    <div class="ql-editor">
      {{ conversion }}
    </div>
  </div> -->
 
  </div>
</template>
 
<script>
import axios from 'axios'
import { quillEditor } from 'vue-quill-editor' // 调用编辑器
import * as Quill from 'quill'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
// 设置字体大小
const fontSizeStyle = Quill.import('attributors/style/size') // 引入这个后会把样式写在style上
fontSizeStyle.whitelist = [
  '12px',
  '14px',
  '16px',
  '18px',
  '20px',
  '24px',
  '28px',
  '32px',
  '36px'
]
Quill.register(fontSizeStyle, true)
// 设置字体样式
const Font = Quill.import('attributors/style/font') // 引入这个后会把样式写在style上
const fonts = ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong']
Font.whitelist = fonts // 将字体加入到白名单
Quill.register(Font, true)
// 工具栏
const toolbarOptions = [
  ['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线 -----['bold', 'italic', 'underline', 'strike']
  [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色-----[{ color: [] }, { background: [] }]
  [{ align: [] }], // 对齐方式-----[{ align: [] }]
  [{ size: fontSizeStyle.whitelist }], // 字体大小-----[{ size: ['small', false, 'large', 'huge'] }]
  [{ font: fonts }], // 字体种类-----[{ font: [] }]
  [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
  [{ direction: 'ltl' }], // 文本方向-----[{'direction': 'rtl'}]
  [{ direction: 'rtl' }], // 文本方向-----[{'direction': 'rtl'}]
  [{ indent: '-1' }, { indent: '+1' }], // 缩进-----[{ indent: '-1' }, { indent: '+1' }]
  [{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表-----[{ list: 'ordered' }, { list: 'bullet' }]
  [{ script: 'sub' }, { script: 'super' }], // 上标/下标-----[{ script: 'sub' }, { script: 'super' }]
  ['blockquote', 'code-block'], // 引用  代码块-----['blockquote', 'code-block']
  ['clean'], // 清除文本格式-----['clean']
  ['link', 'image', 'video'] // 链接、图片、视频-----['link', 'image', 'video']
]
 
export default {
  isPublishing: false, // 发布按钮 启用/禁用
  name: 'HomeDetails',
  components: { quillEditor },
  data () {
    return {
      title: '',
      // 配置方式二
      editorOption: {
        modules: {
          toolbar: {
            container: toolbarOptions,
            handlers: {
              image: this.handleImgUpload
            }
          }
        }
      },
      // 配置方式一
      // editorOption: {
      //   // 编辑器配置
      //   placeholder: '请在这里输入',
      //   modules: {
      //     toolbar: [
      //       ['bold', 'italic', 'underline', 'strike'], // 加粗,斜体,下划线,删除线
      //       ['blockquote', 'code-block'], // 引用,代码块
      //       [{ header: 1 }, { header: 2 }], // 标题,键值对的形式;1、2表示字体大小
      //       [{ list: 'ordered' }, { list: 'bullet' }], // 列表
      //       [{ script: 'sub' }, { script: 'super' }], // 上下标
      //       [{ indent: '-1' }, { indent: '+1' }], // 缩进
      //       // [{ direction: "ltl" }], // 文本方向
      //       [{ direction: 'rtl' }], // 文本方向
      //       [{ size: ['small', false, 'large', 'huge'] }], // 字体大小
      //       [{ header: [1, 2, 3, 4, 5, 6, false] }], // 几级标题
      //       [{ color: [] }, { background: [] }], // 字体颜色,字体背景颜色
      //       [{ font: [] }], // 字体
      //       [{ align: [] }], // 对齐方式
      //       ['link'], // ["link", "image", "video"], //上传图片、上传视频
      //       ['clean'] // 清除字体样式
      //     ]
      //   }
      // },
      editContent: '', // 编辑器内容
      conversion: '' // 演示内容
    }
  },
  computed: {
    editor () {
      return this.$refs.myQuillEditor.quill
    }
  },
  mounted () {
    this.$nextTick(() => {
      this.conversion = this.escapeStringHTML(this.editContent)
    })
  },
  methods: {
    // ========================富文本========================
    onEditorReady (editor) {
      // 准备编辑器
    },
    onEditorBlur () {}, // 失去焦点事件
    onEditorFocus () {}, // 获得焦点事件
    // 内容改变事件
    onEditorChange () {
      this.conversion = this.escapeStringHTML(this.editContent)
    },
    // 转码
    escapeStringHTML (content) {
      content = content.replace(/&lt;/g, '<')
      content = content.replace(/&gt;/g, '>')
      return content
    }
    // ========================富文本END========================
  }
}
</script>
<style>
.ql-editor {
  min-height: 150px;
}
.ql-snow .ql-tooltip[data-mode="link"]::before {
  content: "请输入链接地址:";
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
  border-right: 0px;
  content: "保存";
  padding-right: 0px;
}
.ql-snow .ql-tooltip[data-mode="video"]::before {
  content: "请输入视频地址:";
}
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
  content: "14px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
  content: "10px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
  content: "18px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
  content: "32px";
}
 
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
  content: "文本";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
  content: "标题1";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
  content: "标题2";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
  content: "标题3";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
  content: "标题4";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
  content: "标题5";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
  content: "标题6";
}
 
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
  content: "默认";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="SimSun"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="SimSun"]::before {
  content: "宋体";
}
.ql-snow
  .ql-picker.ql-font
  .ql-picker-label[data-value="Microsoft-YaHei"]::before,
.ql-snow
  .ql-picker.ql-font
  .ql-picker-item[data-value="Microsoft-YaHei"]::before {
  content: "微软雅黑";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="KaiTi"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="KaiTi"]::before {
  content: "楷体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="FangSong"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="FangSong"]::before {
  content: "仿宋";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="SimHei"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="SimHei"]::before {
  content: "黑体";
}
.ql-toolbar.ql-snow + .ql-container.ql-snow {
  border-bottom-left-radius: 5px;
  border-bottom-right-radius: 5px;
}
.ql-toolbar.ql-snow {
  border-top-left-radius: 5px;
  border-top-right-radius: 5px;
}
.ql-snow .ql-stroke,
.ql-snow .ql-picker {
  color: #999;
  stroke: #999;
}
.ql-snow .ql-fill,
.ql-snow .ql-stroke.ql-fill {
  fill: #999;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="12px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="12px"]::before {
  content: "12px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="14px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="14px"]::before {
  content: "14px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="16px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="16px"]::before {
  content: "16px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="20px"]::before {
  content: "20px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="24px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="24px"]::before {
  content: "24px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="36px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="36px"]::before {
  content: "36px";
}
.ql-container {
  font-size: 14px;
}
</style>
 
<style lang="scss" scoped>
.HomeDetails {
  padding: 40px 0 0 80px;
  .quill-editor /deep/ .ql-container {
    min-height: 490px;
  }
  .ql-container {
    min-height: 500px;
  }
}
public String extract(String str) throws Exception {
 
        // 定义正则表达式
        String regex = "data:image/png;base64,([^<]+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(str);
        String base64ImageData;
        //用来存放图片预览地址
        Map<Integer,String > myMap = new HashMap<Integer,String>();
        Integer i = 1;
        // 提取所有base64编码
        pictureVo pictureVo = null;
        while (matcher.find()) {
            base64ImageData = matcher.group(1);
            //解码图片,得到图片预览地址
            pictureVo = decode(base64ImageData);
            //把图片预览地址存起来
            myMap.put(i,pictureVo.getPreviewUrl());
            System.out.println("打印图片预览地址:==" + myMap.get(i));
            i++;
            //System.out.println("截取:" + matcher.group(1));
        }
        //得到一个html,存入数据库
        String html = htmlReplace(str,myMap);
 
        // 图片宽度超限 压缩图片
//        if (pictureVo.getCompressed()){
//            html = html.replaceFirst("<img src", "<img style=\"width: 100%; height: auto;\" src");
//        }
        System.out.println("最终结果:" + html);
        return html;
    }
 
    /**
     * //2.解码图片并存放在本地,此图片作为临时文件,上传完毕后删除临时文件
     * @param str
     * @throws Exception
     */
    pictureVo decode( String str) throws Exception {
 
        String base64ImageData = str;
 
        //将Base64编码的图像数据解码成图片
        byte[] imageBytes = javax.xml.bind.DatatypeConverter.parseBase64Binary(base64ImageData);
        ByteArrayInputStream bis = new ByteArrayInputStream(imageBytes);
        BufferedImage image = ImageIO.read(bis);
 
        // 获取图片的宽度和高度
        //返回类
        pictureVo pictureVo = new pictureVo();
        pictureVo.setCompressed(false);
        int width = image.getWidth();
        int height = image.getHeight();
        System.out.println("图片尺寸: " + width + "x" + height);
        bis.close();
 
        //临时图片存放地址
        String filePath = null;
        //将当前环境读取出来 是开发环境还是生产环境
        if ("dev".equals(runtimeEnvironment)){
            filePath = "/Users/zhouchenghuan/Pictures/"+ UUID.randomUUID().toString()+ ".png";
        } else if ("pro".equals(runtimeEnvironment)) {
            filePath = "/usr/local/java/temp"+ UUID.randomUUID().toString()+ ".png";
        }
 
        //图片宽度超过800px
        if (width > 654){
            System.out.println("图片宽度超限》》》》》》》》》》》》》》》》》》》》》》》》》");
            // 计算缩放后的宽度和高度
            int newWidth = 654;
            int newHeight = (int) ((double) height * newWidth / width);
 
            // 创建缩放后的图片
            BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = resizedImage.createGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.drawImage(image, 0, 0, newWidth, newHeight, null);
            g2d.dispose();
            ImageIO.write(resizedImage, "png", new File(filePath));
            System.out.println("缩放后的图片已保存到: " + filePath);
        } else {
            // 图片宽度未超过800,不需缩放
            Files.write(Paths.get(filePath), imageBytes);
            System.out.println("图片宽度未超过800,无需缩放");
        }
 
        //上传图片 到 minio 并返回图片预览地址
        String uploading = uploading(filePath);
 
        pictureVo.setPreviewUrl(uploading);
        //String previewUrl = ;
        return pictureVo;
    }
 
    /**
     * 作用:上传图片至minio,调用此方法返回图片预览地址
     * @param filePath
     * @return
     * @throws Exception
     */
    String uploading(String filePath) throws Exception {
        //3.将图片上传至minio
        //3.1.创建minio链接客户端
        FileInputStream fileInputStream = null;
        fileInputStream =  new FileInputStream(filePath);
        MinioClient minioClient = MinioClient.builder().credentials("你的账号", "密码")
                .endpoint("http://你的服务器地址").build();
        //3.2上传
        String objectName = UUID.randomUUID().toString() + ".png";
        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .object(objectName)//文件名
                .contentType("text/html/png/jpg")//文件类型
                .bucket("image")//桶名词  与minio创建的名词一致
                .stream(fileInputStream, fileInputStream.available(), -1) //文件流
                .build();
        minioClient.putObject(putObjectArgs);
        // 获取文件的下载地址
        String downloadUrl = minioClient.getObjectUrl("image", objectName);
        System.out.println("下载地址: " + downloadUrl);
        //图片预览地址
        String previewUrl = minioClient.presignedGetObject("image", objectName);
        System.out.println("预览地址: " + previewUrl);
 
        //删除临时文件
        // 判断文件是否存在
        if(Files.exists(Paths.get(filePath))) {
            try {
                // 删除文件
                Files.delete(Paths.get(filePath));
                System.out.println("临时文件删除成功");
            } catch (IOException e) {
                // 异常处理
                e.printStackTrace();
            }
        } else {
            System.out.println("临时文件不存在");
        }
 
        return previewUrl;
    }
 
 
    String htmlReplace(String html,Map<Integer,String > myMap){
 
 
        // 使用正则表达式匹配所有的base64图片并替换成minio的url
        Pattern pattern = Pattern.compile("data:image/png;base64,([^<]+)");
        Matcher matcher = pattern.matcher(html);
        StringBuffer sb = new StringBuffer();
 
        int i = 1;
        while (matcher.find()) {
            matcher.appendReplacement(sb,   myMap.get(i) + "\">");
            i++;
        }
        matcher.appendTail(sb);
        //把图片编码替换成图片预览url后的html
        String html2 = sb.toString();
        System.out.println(sb.toString());
        return html2;
    }

地址:欢-分享知识和快乐


目录
相关文章
|
7月前
|
Linux Shell Go
《Linux操作系统编程》第四章 屏幕编程器vi : 了解屏幕编辑器vi的概述和基本操作命令
《Linux操作系统编程》第四章 屏幕编程器vi : 了解屏幕编辑器vi的概述和基本操作命令
65 0
|
5天前
|
Linux 开发工具
Linux的基础编程——vi/vim编辑器(六)
Linux的基础编程——vi/vim编辑器(六)
35 0
Linux的基础编程——vi/vim编辑器(六)
|
5天前
|
Linux 编译器 C语言
【linux系统编程】编辑器gcc/g++
【linux系统编程】编辑器gcc/g++
|
7月前
|
缓存 BI Linux
《Linux操作系统编程》第九章 数据查找和筛选工具 : 了解流编辑器sed和报表生成器awk的简单使用
《Linux操作系统编程》第九章 数据查找和筛选工具 : 了解流编辑器sed和报表生成器awk的简单使用
56 0
|
8月前
|
存储 Shell Perl
shell编程之sed编辑器
shell编程之sed编辑器
47 0
|
8月前
第4章 MATLAB编程基础——4.1 M文件编辑器
第4章 MATLAB编程基础——4.1 M文件编辑器
西门子S7-200 SMART如何切换编程编辑器、如何输入LAD程序、编辑程序
上篇文章中我们学习了西门子S7-200 SMART PLC基本操作、查看PLC信息以及如何设置PLC日期和时间,本篇我们来介绍如何在编程软件STEP7-Micro/WIN SMART中切换程序编辑器、输入LAD程序以及如何编辑程序。STEP7-Micro/WIN SMART支持三种编程方式:LAD(梯形图)、FBD(功能块图)、STL(语句表)。其中LAD(梯形图)是最常用的编程方式,本篇我们就以梯形图为例来讲解。
西门子S7-200 SMART如何切换编程编辑器、如何输入LAD程序、编辑程序
|
前端开发 IDE PHP
Python编程 代码编辑器
本章将会讲解Python自带的idle以及pcharm使用,让我们开启Python搬砖之旅
97 0
Python编程 代码编辑器
|
人工智能 运维 Shell
大话Linux——Vim编辑器与Shell编程
## 4、Vim编辑器与Shell命令脚本 4.1、Vim文本编辑器 Vim编辑器的三种模式及切换方法 命令模式:控制光标移动,可对文本进行复制、粘贴、删除和查找等 输入模式:正常文本录入 保存或退出我能当,以及设置编译环境
459 0
|
Python
Python编程:sublime编辑器python开发必装插件
Python编程:sublime编辑器python开发必装插件
152 0