Files
jdt-user/src/components/RichEditor.vue

286 lines
7.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<view class="page-body">
<view class="wrapper">
<view
class="toolbar"
@click="format"
style="max-height: 240px; overflow-y: auto"
>
<!-- 加粗 -->
<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.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.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" @click="insertDivider"></view>
<!-- 插入图片 -->
<view class="iconfont icon-image" @click="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-undo" @click="undo"></view>
<view class="iconfont icon-redo" @click="redo"></view>
</view>
<view class="editor-wrapper">
<editor
id="editor"
class="ql-container"
:placeholder="data.placeholder"
@statuschange="onStatusChange"
:show-img-resize="true"
@ready="onEditorReady"
@input="getCtx"
/>
</view>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import { reactive } from "vue";
import Taro from "@tarojs/taro";
import { BASE_URL } from "@/utils/request";
const { content } = defineProps<{
content: string;
}>();
let emits = defineEmits(["input"]);
const data = reactive<any>({
editorCtx: "",
readOnly: false,
placeholder: "请输入商品详情...",
richText: "",
formats: {},
});
function onEditorReady() {
// 富文本节点渲染完成
Taro.createSelectorQuery()
.select("#editor")
.context((res) => {
data.editorCtx = res.context;
// 初始化数据
if (content) {
data.editorCtx.setContents({
html: content,
});
}
})
.exec();
}
// 失去焦点时,获取富文本的内容
function getCtx(e: { detail: { html: any } }) {
data.richText = e.detail.html;
emits("input", e.detail.html);
}
// 撤销操作
function undo() {
data.editorCtx.undo();
}
// 复原操作
function redo() {
data.editorCtx.redo();
}
//修改样式
function format(e: { target: { dataset: { name: any; value: any } } }) {
// console.log("format", e.target.dataset);
let { name, value } = e.target.dataset;
if (!name) return;
data.editorCtx.format(name, value);
}
//通过 Context 方法改变编辑器内样式时触发,返回选区已设置的样式
function onStatusChange(e: { detail: any }) {
data.formats = e.detail;
}
// 插入分割线
function insertDivider() {
data.editorCtx.insertDivider();
}
// 插入图片
function insertImage() {
Taro.chooseImage({
count: 1,
sizeType: ["original", "compressed"],
sourceType: ["album", "camera"],
success: (res) => {
// 上传图片的逻辑各有不同,自行调整即可
Taro.uploadFile({
url: `${BASE_URL}/upload`,
name: "file",
header: { token: Taro.getStorageSync("token") },
filePath: res.tempFilePaths[0],
success: (res) => {
console.log(res);
const imgData = JSON.parse(res.data) as {
code: number;
msg: string;
data: any;
};
if (imgData.code === 200) {
// 将图片展示在编辑器中
data.editorCtx.insertImage({
width: "100%",
height: "auto",
src: imgData.data.data,
alt: "图像",
success: function () {
console.log("insert image success");
},
});
} else {
console.log("上传失败");
}
},
fail: (err) => {
console.log(err);
},
});
},
});
}
</script>
<style lang="scss">
@import "../static/font_4211210_2x20brbrv94.css";
.wrapper {
height: 100%;
}
.editor-wrapper {
height: calc(
100vh - var(--window-top) - var(--status-bar-height) - 280px - 650px
);
overflow: scroll;
background: rgba(153, 153, 153, 0.05);
border-radius: 20px;
margin: 20px 0;
color: #000;
}
.iconfont {
display: inline-block;
margin: 20px 20px;
width: 32px;
height: 32px;
cursor: pointer;
font-size: 32px;
}
.toolbar {
box-sizing: border-box;
border-bottom: 0;
font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
}
.ql-container {
box-sizing: border-box;
padding: 24px 30px;
width: 100%;
min-height: 30vh;
height: 100%;
font-size: 28px;
line-height: 1.5;
}
.ql-active {
color: #f38e48;
}
</style>