uni-app原生editor封装编辑组件(vue3)

1. uni-app原生editor封装编辑组件(vue3)

   官方文档:editor编辑组件

   uni-app内置的editor直接使用的时候是什么图标都没有的,各个功能也需要自己借助api进行封装,因此简单封装一个编辑器组件,包括了几个基本的功能,包括加粗、倾斜、段落格式、分割线、上下角标等。

   具体代码如下:(使用到的icon可以在阿里巴巴里面自己找一下进行替换)

c 复制代码
<template>
  <view class="container">
    <view class="page-body">
      <view class="wrapper">
        <view
          class="toolbar"
          @tap="format"
          style="max-height: 240rpx; overflow-y: auto"
        >
          <!-- 字体 -->
          <!-- <view
            :class="data.formats.fontFamily ? 'ql-active' : ''"
            class="iconfont icon-font"
            data-name="fontFamily"
            data-value="Pacifico"
          ></view> -->
          <!-- 加粗 -->
          <view
            :class="data.formats.bold ? 'ql-active' : ''"
            class="iconfont icon-zitijiacu"
            data-name="bold"
          ></view>
          <!-- 斜体 -->
          <view
            :class="data.formats.italic ? 'ql-active' : ''"
            class="iconfont icon-zitixieti"
            data-name="italic"
          ></view>
          <!-- 下划线 -->
          <view
            :class="data.formats.underline ? 'ql-active' : ''"
            class="iconfont icon-zitixiahuaxian"
            data-name="underline"
          ></view>
          <!-- 删除中划线 -->
          <!-- <view
            :class="data.formats.strike ? 'ql-active' : ''"
            class="iconfont icon-zitishanchuxian"
            data-name="strike"
          ></view> -->
          <!-- 字号 -->
          <!-- <view
            :class="data.formats.fontSize === '24px' ? 'ql-active' : ''"
            class="iconfont icon-font-size"
            data-name="fontSize"
            data-value="48rpx"
          ></view>-->
          <!-- 字体颜色 -->
          <!-- <view
            :class="data.formats.color === '#0000ff' ? 'ql-active' : ''"
            class="iconfont icon-font-colors"
            data-name="color"
            data-value="#0000ff"
          ></view>  -->
          <!-- 清除样式 -->
          <!-- <view class="iconfont icon-clearformat" @tap="removeFormat"></view> -->
          <!-- 对齐方式:左 -->
          <view
            :class="data.formats.align === 'left' ? 'ql-active' : ''"
            class="iconfont icon-zuoduiqi"
            data-name="align"
            data-value="left"
          ></view>
          <!-- 对齐方式:居中 -->
          <view
            :class="data.formats.align === 'center' ? 'ql-active' : ''"
            class="iconfont icon-juzhongduiqi"
            data-name="align"
            data-value="center"
          ></view>
          <!-- 对齐方式:右 -->
          <view
            :class="data.formats.align === 'right' ? 'ql-active' : ''"
            class="iconfont icon-youduiqi"
            data-name="align"
            data-value="right"
          ></view>
          <!-- 对齐方式:两侧 -->
          <view
            :class="data.formats.align === 'justify' ? 'ql-active' : ''"
            class="iconfont icon-zuoyouduiqi"
            data-name="align"
            data-value="justify"
          ></view>
          <!-- 行高 -->
          <!-- <view
            :class="data.formats.lineHeight ? 'ql-active' : ''"
            class="iconfont icon-line-height"
            data-name="lineHeight"
            data-value="2"
          ></view>-->
          <!-- 字间距 -->
          <!-- <view
            :class="data.formats.letterSpacing ? 'ql-active' : ''"
            class="iconfont icon-Character-Spacing"
            data-name="letterSpacing"
            data-value="2em"
          ></view>  -->
          <!-- 上边距 -->
          <!-- <view
            :class="data.formats.marginTop ? 'ql-active' : ''"
            class="iconfont icon-duanqianju"
            data-name="marginTop"
            data-value="40rpx"
          ></view> -->
          <!-- 下边距 -->
          <!-- <view
            :class="data.formats.marginBottom ? 'ql-active' : ''"
            class="iconfont icon-duanhouju"
            data-name="marginBottom"
            data-value="40rpx"
          ></view> -->
          <!-- 日期 -->
          <!-- <view class="iconfont icon-date" @tap="insertDate"></view> -->
          <!-- 勾选 -->
          <!-- <view
            class="iconfont icon--checklist"
            data-name="list"
            data-value="check"
          ></view> -->
          <!-- 有序排列 -->
          <view
            :class="data.formats.list === 'ordered' ? 'ql-active' : ''"
            class="iconfont icon-youxupailie"
            data-name="list"
            data-value="ordered"
          ></view>
          <!-- 无序排列 -->
          <view
            :class="data.formats.list === 'bullet' ? 'ql-active' : ''"
            class="iconfont icon-wuxupailie"
            data-name="list"
            data-value="bullet"
          ></view>
          <!-- 取消缩进 -->
          <view
            class="iconfont icon-outdent"
            data-name="indent"
            data-value="-1"
          ></view>
          <!-- 缩进 -->
          <view
            class="iconfont icon-indent"
            data-name="indent"
            data-value="+1"
          ></view>
          <!-- 添加分割线 -->
          <view class="iconfont icon-fengexian" @tap="insertDivider"></view>
          <!-- 插入图片 -->
          <view class="iconfont icon-image" @tap="insertImage"></view>
          <!-- 设置标题 -->
          <view
            :class="data.formats.header === 3 ? 'ql-active' : ''"
            class="iconfont icon-H"
            data-name="header"
            :data-value="3"
          ></view>
          <!-- 下标 -->
          <view
            :class="data.formats.script === 'sub' ? 'ql-active' : ''"
            class="iconfont icon-zitixiabiao"
            data-name="script"
            data-value="sub"
          ></view>
          <!-- 上标 -->
          <view
            :class="data.formats.script === 'super' ? 'ql-active' : ''"
            class="iconfont icon-zitishangbiao"
            data-name="script"
            data-value="super"
          ></view>
          <!-- 清空 -->
          <!-- <view class="iconfont icon-shanchu" @tap="clear"></view> -->
          <!-- <view
            :class="data.formats.direction === 'rtl' ? 'ql-active' : ''"
            class="iconfont icon-direction-rtl"
            data-name="direction"
            data-value="rtl"
          ></view> -->
          <view class="iconfont icon-undo" @tap="undo"></view>
          <view class="iconfont icon-redo" @tap="redo"></view>
        </view>
        <view class="editor-wrapper">
          <!-- <editor id="editor" class="ql-container" placeholder="开始输入..." showImgSize showImgToolbar showImgResize >
					</editor> -->
          <editor
            id="editor"
            class="ql-container"
            :placeholder="data.placeholder"
            @statuschange="onStatusChange"
            :show-img-resize="true"
            @ready="onEditorReady"
            @input="getCtx"
          ></editor>
        </view>
      </view>
    </view>
  </view>
</template>
 
<script lang="ts" setup>
const { token } = $(useUser());
import { javaBaseUrl } from "@/utils/request";
 
const { content } = defineProps<{
  content: string;
}>();
let emits = defineEmits(["input"]);
const data = reactive({
  editorCtx: "",
  readOnly: false,
  placeholder: "开始输入...",
  richText: "",
  formats: {},
});
 
function onEditorReady() {
  // 富文本节点渲染完成
  // #ifdef MP-BAIDU
  data.editorCtx =
    requireDynamicLib("editorLib").createEditorContext("editorId");
  // #endif
  // #ifdef APP-PLUS || H5 ||MP-WEIXIN
  uni
    .createSelectorQuery()
    .select("#editor")
    .context((res) => {
      data.editorCtx = res.context;
      // 初始化数据
      if (content) {
        data.editorCtx.setContents({
          html: content,
        });
      }
    })
    .exec();
  // #endif
}
 
// 失去焦点时,获取富文本的内容
function getCtx(e) {
  data.richText = e.detail.html;
  emits('input', e.detail.html);
}
// 撤销操作
function undo() {
  data.editorCtx.undo();
}
// 复原操作
function redo() {
  data.editorCtx.redo();
}
 
//修改样式
function format(e) {
  // console.log("format", e.target.dataset);
  let { name, value } = e.target.dataset;
  if (!name) return;
  data.editorCtx.format(name, value);
}
//通过 Context 方法改变编辑器内样式时触发,返回选区已设置的样式
function onStatusChange(e) {
  const formats = e.detail;
  data.formats = formats;
}
// 插入分割线
function insertDivider() {
  data.editorCtx.insertDivider();
}
 
// 插入图片
function insertImage() {
  uni.chooseImage({
    count: 1,
    sizeType: ["original", "compressed"],
    sourceType: ["album", "camera"],
    success: (res) => {
      // 上传图片的逻辑各有不同,自行调整即可
      uni.uploadFile({
        url: `${javaBaseUrl}/system/v1/upload`, 
        fileType: "image",
        name: "file",
        header: { Authorization: token },
        filePath: res.tempFilePaths[0],
        success: (res) => {
          const imgData = JSON.parse(res.data) as {
            code: number;
            msg: string;
            success: boolean;
          };
          if (imgData.code === 200) {
            // 将图片展示在编辑器中
            data.editorCtx.insertImage({
              width: "20%", //设置宽度为100%防止宽度溢出手机屏幕
              height: "auto",
              src: imgData.msg,
              alt: "图像",
              success: function () {
                console.log("insert image success");
              },
            });
          } else {
            console.log("上传失败");
          }
        },
        fail: (err) => {
          console.log(err);
        },
      });
    },
  });
}
// 清空编辑器内容
// function clear() {
//   data.editorCtx.clear({
//     success: function (res) {
//       console.log("clear success");
//     },
//   });
// }
// 清除当前选区的样式
// function removeFormat() {
//   data.editorCtx.removeFormat();
// }
 
// 选择日期
// function insertDate() {
// 	const date = new Date();
// 	const formatDate = `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`;
// 	data.editorCtx.insertText({
// 		text: formatDate
// 	});
// }
</script>
 
<style lang="scss" scoped>
@import "//at.alicdn.com/t/c/font_4211210_2x20brbrv94.css";
 
.page-body {
  // height: calc(100vh - var(--window-top) - var(--status-bar-height));
}
 
.wrapper {
  height: 100%;
}
 
.editor-wrapper {
  height: calc(
    100vh - var(--window-top) - var(--status-bar-height) - 280rpx - 650rpx
  );
  overflow: scroll;
  background: rgba(153, 153, 153, 0.05);
  border-radius: 20rpx;
  margin: 20rpx 0;
}
 
.iconfont {
  display: inline-block;
  margin: 20rpx 20rpx;
  width: 32rpx;
  height: 32rpx;
  cursor: pointer;
  font-size: 32rpx;
}
 
.toolbar {
  box-sizing: border-box;
  border-bottom: 0;
  font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
}
 
.ql-container {
  box-sizing: border-box;
  padding: 24rpx 30rpx;
  width: 100%;
  min-height: 30vh;
  height: 100%;
  font-size: 28rpx;
  line-height: 1.5;
}
 
.ql-active {
  color: #f38e48;
}
</style>

1.1. editor封装编辑组件封装

1.1.1. 封装editor组件

   (1)editor.vue文件是主要封装代码

c 复制代码
<template>
  <view class="container">
    <view class="page-body">
      <view class="wrapper">
        <view
          class="toolbar"
          @tap="format"
          style="max-height: 240rpx; overflow-y: auto"
        >
          <!-- 字体 -->
          <!-- <view
            :class="data.formats.fontFamily ? 'ql-active' : ''"
            class="iconfont icon-font"
            data-name="fontFamily"
            data-value="Pacifico"
          ></view> -->
          <!-- 加粗 -->
          <view
            :class="data.formats.bold ? 'ql-active' : ''"
            class="iconfont icon-zitijiacu"
            data-name="bold"
          ></view>
          <!-- 斜体 -->
          <view
            :class="data.formats.italic ? 'ql-active' : ''"
            class="iconfont icon-zitixieti"
            data-name="italic"
          ></view>
          <!-- 下划线 -->
          <view
            :class="data.formats.underline ? 'ql-active' : ''"
            class="iconfont icon-zitixiahuaxian"
            data-name="underline"
          ></view>
          <!-- 删除中划线 -->
          <!-- <view
            :class="data.formats.strike ? 'ql-active' : ''"
            class="iconfont icon-zitishanchuxian"
            data-name="strike"
          ></view> -->
          <!-- 字号 -->
          <!-- <view
            :class="data.formats.fontSize === '24px' ? 'ql-active' : ''"
            class="iconfont icon-font-size"
            data-name="fontSize"
            data-value="48rpx"
          ></view>-->
          <!-- 字体颜色 -->
          <!-- <view
            :class="data.formats.color === '#0000ff' ? 'ql-active' : ''"
            class="iconfont icon-font-colors"
            data-name="color"
            data-value="#0000ff"
          ></view>  -->
          <!-- 清除样式 -->
          <!-- <view class="iconfont icon-clearformat" @tap="removeFormat"></view> -->
          <!-- 对齐方式:左 -->
          <view
            :class="data.formats.align === 'left' ? 'ql-active' : ''"
            class="iconfont icon-zuoduiqi"
            data-name="align"
            data-value="left"
          ></view>
          <!-- 对齐方式:居中 -->
          <view
            :class="data.formats.align === 'center' ? 'ql-active' : ''"
            class="iconfont icon-juzhongduiqi"
            data-name="align"
            data-value="center"
          ></view>
          <!-- 对齐方式:右 -->
          <view
            :class="data.formats.align === 'right' ? 'ql-active' : ''"
            class="iconfont icon-youduiqi"
            data-name="align"
            data-value="right"
          ></view>
          <!-- 对齐方式:两侧 -->
          <view
            :class="data.formats.align === 'justify' ? 'ql-active' : ''"
            class="iconfont icon-zuoyouduiqi"
            data-name="align"
            data-value="justify"
          ></view>
          <!-- 行高 -->
          <!-- <view
            :class="data.formats.lineHeight ? 'ql-active' : ''"
            class="iconfont icon-line-height"
            data-name="lineHeight"
            data-value="2"
          ></view>-->
          <!-- 字间距 -->
          <!-- <view
            :class="data.formats.letterSpacing ? 'ql-active' : ''"
            class="iconfont icon-Character-Spacing"
            data-name="letterSpacing"
            data-value="2em"
          ></view>  -->
          <!-- 上边距 -->
          <!-- <view
            :class="data.formats.marginTop ? 'ql-active' : ''"
            class="iconfont icon-duanqianju"
            data-name="marginTop"
            data-value="40rpx"
          ></view> -->
          <!-- 下边距 -->
          <!-- <view
            :class="data.formats.marginBottom ? 'ql-active' : ''"
            class="iconfont icon-duanhouju"
            data-name="marginBottom"
            data-value="40rpx"
          ></view> -->
          <!-- 日期 -->
          <!-- <view class="iconfont icon-date" @tap="insertDate"></view> -->
          <!-- 勾选 -->
          <!-- <view
            class="iconfont icon--checklist"
            data-name="list"
            data-value="check"
          ></view> -->
          <!-- 有序排列 -->
          <view
            :class="data.formats.list === 'ordered' ? 'ql-active' : ''"
            class="iconfont icon-youxupailie"
            data-name="list"
            data-value="ordered"
          ></view>
          <!-- 无序排列 -->
          <view
            :class="data.formats.list === 'bullet' ? 'ql-active' : ''"
            class="iconfont icon-wuxupailie"
            data-name="list"
            data-value="bullet"
          ></view>
          <!-- 取消缩进 -->
          <view
            class="iconfont icon-outdent"
            data-name="indent"
            data-value="-1"
          ></view>
          <!-- 缩进 -->
          <view
            class="iconfont icon-indent"
            data-name="indent"
            data-value="+1"
          ></view>
          <!-- 添加分割线 -->
          <view class="iconfont icon-fengexian" @tap="insertDivider"></view>
          <!-- 插入图片 -->
          <view class="iconfont icon-image" @tap="insertImage"></view>
          <!-- 设置标题 -->
          <view
            :class="data.formats.header === 3 ? 'ql-active' : ''"
            class="iconfont icon-H"
            data-name="header"
            :data-value="3"
          ></view>
          <!-- 下标 -->
          <view
            :class="data.formats.script === 'sub' ? 'ql-active' : ''"
            class="iconfont icon-zitixiabiao"
            data-name="script"
            data-value="sub"
          ></view>
          <!-- 上标 -->
          <view
            :class="data.formats.script === 'super' ? 'ql-active' : ''"
            class="iconfont icon-zitishangbiao"
            data-name="script"
            data-value="super"
          ></view>
          <!-- 清空 -->
          <!-- <view class="iconfont icon-shanchu" @tap="clear"></view> -->
          <!-- <view
            :class="data.formats.direction === 'rtl' ? 'ql-active' : ''"
            class="iconfont icon-direction-rtl"
            data-name="direction"
            data-value="rtl"
          ></view> -->
          <view class="iconfont icon-undo" @tap="undo"></view>
          <view class="iconfont icon-redo" @tap="redo"></view>
        </view>
        <view class="editor-wrapper">
          <!-- <editor id="editor" class="ql-container" placeholder="开始输入..." showImgSize showImgToolbar showImgResize >
					</editor> -->
          <editor
            id="editor"
            class="ql-container"
            :placeholder="data.placeholder"
            @statuschange="onStatusChange"
            :show-img-resize="true"
            @ready="onEditorReady"
            @input="getCtx"
          ></editor>
        </view>
      </view>
    </view>
  </view>
</template>
 
<script lang="ts" setup>
const { token } = $(useUser());
import { javaBaseUrl } from "@/utils/request";
 
const { content } = defineProps<{
  content: string;
}>();
let emits = defineEmits(["input"]);
const data = reactive({
  editorCtx: "",
  readOnly: false,
  placeholder: "开始输入...",
  richText: "",
  formats: {},
});
 
function onEditorReady() {
  // 富文本节点渲染完成
  // #ifdef MP-BAIDU
  data.editorCtx =
    requireDynamicLib("editorLib").createEditorContext("editorId");
  // #endif
  // #ifdef APP-PLUS || H5 ||MP-WEIXIN
  uni
    .createSelectorQuery()
    .select("#editor")
    .context((res) => {
      data.editorCtx = res.context;
      // 初始化数据
      if (content) {
        data.editorCtx.setContents({
          html: content,
        });
      }
    })
    .exec();
  // #endif
}
 
// 失去焦点时,获取富文本的内容
function getCtx(e) {
  data.richText = e.detail.html;
  emits('input', e.detail.html);
}
// 撤销操作
function undo() {
  data.editorCtx.undo();
}
// 复原操作
function redo() {
  data.editorCtx.redo();
}
 
//修改样式
function format(e) {
  // console.log("format", e.target.dataset);
  let { name, value } = e.target.dataset;
  if (!name) return;
  data.editorCtx.format(name, value);
}
//通过 Context 方法改变编辑器内样式时触发,返回选区已设置的样式
function onStatusChange(e) {
  const formats = e.detail;
  data.formats = formats;
}
// 插入分割线
function insertDivider() {
  data.editorCtx.insertDivider();
}
 
// 插入图片
function insertImage() {
  uni.chooseImage({
    count: 1,
    sizeType: ["original", "compressed"],
    sourceType: ["album", "camera"],
    success: (res) => {
      // 上传图片的逻辑各有不同,自行调整即可
      uni.uploadFile({
        url: `${javaBaseUrl}/system/v1/upload`, 
        fileType: "image",
        name: "file",
        header: { Authorization: token },
        filePath: res.tempFilePaths[0],
        success: (res) => {
          const imgData = JSON.parse(res.data) as {
            code: number;
            msg: string;
            success: boolean;
          };
          if (imgData.code === 200) {
            // 将图片展示在编辑器中
            data.editorCtx.insertImage({
              width: "20%", //设置宽度为100%防止宽度溢出手机屏幕
              height: "auto",
              src: imgData.msg,
              alt: "图像",
              success: function () {
                console.log("insert image success");
              },
            });
          } else {
            console.log("上传失败");
          }
        },
        fail: (err) => {
          console.log(err);
        },
      });
    },
  });
}
// 清空编辑器内容
// function clear() {
//   data.editorCtx.clear({
//     success: function (res) {
//       console.log("clear success");
//     },
//   });
// }
// 清除当前选区的样式
// function removeFormat() {
//   data.editorCtx.removeFormat();
// }
 
// 选择日期
// function insertDate() {
// 	const date = new Date();
// 	const formatDate = `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`;
// 	data.editorCtx.insertText({
// 		text: formatDate
// 	});
// }
</script>
 
<style lang="scss" scoped>
@import "//at.alicdn.com/t/c/font_4211210_2x20brbrv94.css";
 
.page-body {
  // height: calc(100vh - var(--window-top) - var(--status-bar-height));
}
 
.wrapper {
  height: 100%;
}
 
.editor-wrapper {
  height: calc(
    100vh - var(--window-top) - var(--status-bar-height) - 280rpx - 650rpx
  );
  overflow: scroll;
  background: rgba(153, 153, 153, 0.05);
  border-radius: 20rpx;
  margin: 20rpx 0;
}
 
.iconfont {
  display: inline-block;
  margin: 20rpx 20rpx;
  width: 32rpx;
  height: 32rpx;
  cursor: pointer;
  font-size: 32rpx;
}
 
.toolbar {
  box-sizing: border-box;
  border-bottom: 0;
  font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
}
 
.ql-container {
  box-sizing: border-box;
  padding: 24rpx 30rpx;
  width: 100%;
  min-height: 30vh;
  height: 100%;
  font-size: 28rpx;
  line-height: 1.5;
}
 
.ql-active {
  color: #f38e48;
}
</style>

  (2)editor-icon.css文件样式

c 复制代码
@font-face {
	font-family: 'iconfont';
	src: url('data:font/truetype;charset=utf-8;base64,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AAsAJgFuAAoAQwByAGUAYQB0AGUAZAAgAGIAeQAgAGkAYwBvAG4AZgBvAG4AdAAKAAAKQ3JlYXRlZCBieSBpY29uZm9udAoAAGkAYwBvAG4AZgBvAG4AdAAAaWNvbmZvbnQAAFIAZQBnAHUAbABhAHIAAFJlZ3VsYXIAAGkAYwBvAG4AZgBvAG4AdAAAaWNvbmZvbnQAAGkAYwBvAG4AZgBvAG4AdAAAaWNvbmZvbnQAAFYAZQByAHMAaQBvAG4AIAAxAC4AMAAAVmVyc2lvbiAxLjAAAGkAYwBvAG4AZgBvAG4AdAAAaWNvbmZvbnQAAEcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAAcwB2AGcAMgB0AHQAZgAgAGYAcgBvAG0AIABGAG8AbgB0AGUAbABsAG8AIABwAHIAbwBqAGUAYwB0AC4AAEdlbmVyYXRlZCBieSBzdmcydHRmIGZyb20gRm9udGVsbG8gcHJvamVjdC4AAGgAdAB0AHAAOgAvAC8AZgBvAG4AdABlAGwAbABvAC4AYwBvAG0AAGh0dHA6Ly9mb250ZWxsby5jb20AAAIAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOwAAAAEAAgECAQMBBAEFAQYBBwEIAQkBCgELAQwBDQEOAQ8BEAERARIBEwEUARUBFgEXARgBGQEaARsBHAEdAR4BHwEgASEBIgEjASQBJQEmAScBKAEpASoBKwEsAS0BLgEvATABMQEyATMBNAE1ATYBNwE4ATkEcmVkbwlzZWxlY3RhbGwHcHJldmlldwR1bmRvBGRhdGUHY2xlYXJ1cBU3MjNiaWFuamlxaV9kdWFuaG91anUWNzIyYmlhbmppcWlfZHVhbnFpYW5qdQotY2hlY2tsaXN0DWRpcmVjdGlvbi1sdHINZGlyZWN0aW9uLXJ0bAtmb250Ymdjb2xvcg1jbGVhcmVkZm9ybWF0BGZvbnQHb3V0ZGVudAhmb250c2l6ZQp0ZXh0X2NvbG9yD2Zvcm1hdC1oZWFkZXItMg9mb3JtYXQtaGVhZGVyLTMLbGluZS1oZWlnaHQPZm9ybWF0LWhlYWRlci0xD2Zvcm1hdC1oZWFkZXItNA9mb3JtYXQtaGVhZGVyLTUPZm9ybWF0LWhlYWRlci02EUNoYXJhY3Rlci1TcGFjaW5nBmluZGVudAZiYW9jdW4IcXVhbnBpbmcFZnV6aGkHc2hhbmNodQxiaWFuamlzZWt1YWkJZmVuZ2V4aWFuB2RpYW56YW4MY2hhcnVsaWFuamllC2NoYXJ1dHVwaWFuCnd1eHVwYWlsaWUManV6aG9uZ2R1aXFpB3lpbnlvbmcLeW91eHVwYWlsaWUIeW91ZHVpcWkJeml0aWRhaW1hCHhpYW9saWFuCXppdGlqaWFjdQ96aXRpc2hhbmNodXhpYW4Neml0aXNoYW5nYmlhbwp6aXRpYmlhb3RpDnppdGl4aWFodWF4aWFuCXppdGl4aWV0aQl6aXRpeWFuc2UIenVvZHVpcWkJeml0aXl1bGFuC3ppdGl4aWFiaWFvC3p1b3lvdWR1aXFpB2R1aWdvdXgGZ3VhbmJpDnNoZW5neWluX3NoaXRpAAAAAAAB//8AAgABAAAADAAAABYAAAACAAEAAwA6AAEABAAAAAIAAAAAAAAAAQAAAADVpCcIAAAAANhk6GIAAAAA2GToYg==') format('truetype');
	font-weight: normal;
	font-style: normal;
	font-display: swap;
}
 
.iconfont {
	font-family: "iconfont" !important;
	font-size: 16px;
	font-style: normal;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}
 
.icon-redo:before {
	content: "\e627";
}
 
.icon-undo:before {
	content: "\e633";
}
 
.icon-indent:before {
	content: "\eb28";
}
 
.icon-outdent:before {
	content: "\e6e8";
}
 
.icon-fontsize:before {
	content: "\e6fd";
}
 
.icon-format-header-1:before {
	content: "\e860";
}
 
.icon-format-header-4:before {
	content: "\e863";
}
 
.icon-format-header-5:before {
	content: "\e864";
}
 
.icon-format-header-6:before {
	content: "\e865";
}
 
.icon-clearup:before {
	content: "\e64d";
}
 
.icon-preview:before {
	content: "\e631";
}
 
.icon-date:before {
	content: "\e63e";
}
 
.icon-fontbgcolor:before {
	content: "\e678";
}
 
.icon-clearedformat:before {
	content: "\e67e";
}
 
.icon-font:before {
	content: "\e684";
}
 
.icon-723bianjiqi_duanhouju:before {
	content: "\e65f";
}
 
.icon-722bianjiqi_duanqianju:before {
	content: "\e660";
}
 
.icon-text_color:before {
	content: "\e72c";
}
 
.icon-format-header-2:before {
	content: "\e75c";
}
 
.icon-format-header-3:before {
	content: "\e75d";
}
 
.icon--checklist:before {
	content: "\e664";
}
 
.icon-baocun:before {
	content: "\ec09";
}
 
.icon-line-height:before {
	content: "\e7f8";
}
 
.icon-quanping:before {
	content: "\ec13";
}
 
.icon-direction-rtl:before {
	content: "\e66e";
}
 
.icon-direction-ltr:before {
	content: "\e66d";
}
 
.icon-selectall:before {
	content: "\e62b";
}
 
.icon-fuzhi:before {
	content: "\ec7a";
}
 
.icon-shanchu:before {
	content: "\ec7b";
}
 
.icon-bianjisekuai:before {
	content: "\ec7c";
}
 
.icon-fengexian:before {
	content: "\ec7f";
}
 
.icon-dianzan:before {
	content: "\ec80";
}
 
.icon-charulianjie:before {
	content: "\ec81";
}
 
.icon-charutupian:before {
	content: "\ec82";
}
 
.icon-wuxupailie:before {
	content: "\ec83";
}
 
.icon-juzhongduiqi:before {
	content: "\ec84";
}
 
.icon-yinyong:before {
	content: "\ec85";
}
 
.icon-youxupailie:before {
	content: "\ec86";
}
 
.icon-youduiqi:before {
	content: "\ec87";
}
 
.icon-zitidaima:before {
	content: "\ec88";
}
 
.icon-xiaolian:before {
	content: "\ec89";
}
 
.icon-zitijiacu:before {
	content: "\ec8a";
}
 
.icon-zitishanchuxian:before {
	content: "\ec8b";
}
 
.icon-zitishangbiao:before {
	content: "\ec8c";
}
 
.icon-zitibiaoti:before {
	content: "\ec8d";
}
 
.icon-zitixiahuaxian:before {
	content: "\ec8e";
}
 
.icon-zitixieti:before {
	content: "\ec8f";
}
 
.icon-zitiyanse:before {
	content: "\ec90";
}
 
.icon-zuoduiqi:before {
	content: "\ec91";
}
 
.icon-zitiyulan:before {
	content: "\ec92";
}
 
.icon-zitixiabiao:before {
	content: "\ec93";
}
 
.icon-zuoyouduiqi:before {
	content: "\ec94";
}
 
.icon-duigoux:before {
	content: "\ec9e";
}
 
.icon-guanbi:before {
	content: "\eca0";
}
 
.icon-shengyin_shiti:before {
	content: "\eca5";
}
 
.icon-Character-Spacing:before {
	content: "\e964";
}

  (3)到此封装就完毕了,以下是单个页面引入

c 复制代码
<template>
  <view>
    <editor-view @input="input">
    </editor-view>
  </view>
</template>
<script>
import EditorView from '../../../components/editor/view/editor-view.vue';

export default {
  components: {
    EditorView
  },
  data() {
    return {
      ruleForm: {
        content: ''
      }
    };
  },
  onLoad() {

  },
  methods: {
    input(e) {
      this.ruleForm.content = e;
    }
  },
}
</script>
<style>
</style>

  (4)最后效果如下,编辑器一共四排,这边隐藏了一排,可以上下滑动。

相关推荐
felipeas1 天前
uni-app day1
uni-app·notepad++
前端后腿哥1 天前
UNIAPPX UTS插件Widget开发完整教程(Android版)
前端·uni-app
黄同学real2 天前
uni-app 真机调试:手动代理环境下访问内网 API 的解决方案
uni-app
Hoshizola2 天前
uniapp与蓝牙设备连接详细步骤
前端·uni-app
优雅格子衫2 天前
uniapp 拍照相册选取后超级好用的裁剪组件,增加水印完全自定义
开发语言·前端·javascript·uni-app·vue
路光.2 天前
uniapp中解决webview在app中调用,有过渡空白问题,增加过渡动效
uni-app·vue·app·uniapp
linlinlove22 天前
前端uniapp、后端thinkphp股票系统开发功能展示、代码披露、HQChart
前端·uni-app·echarts·thinkphp·hqchart·配资·deepseek选股票
2501_915909062 天前
深入理解HTTPS中间人抓包技术原理与实战指南
网络协议·http·ios·小程序·https·uni-app·iphone
2501_916007473 天前
iOS应用性能优化全面指南:从内存管理到工具使用
android·ios·性能优化·小程序·uni-app·iphone·webview