jiuyiUniapp/jiuyi2/components/public/editor/editor.vue

312 lines
6.9 KiB
Vue

<script setup>
import {
ref,
reactive,
onMounted,
onUnmounted,
getCurrentInstance,
defineProps,
defineEmits,
defineExpose,
} from 'vue'
// 工具库
import util from '@/common/js/util'
// 调色板
import pickerColor from '@/components/public/pickerColor/pickerColor.vue'
const {
proxy
} = getCurrentInstance()
const props = defineProps({
modelValue: String
})
//
const emit = defineEmits(['update:modelValue']);
// 编辑器内容
const formats = reactive({})
// 编辑器上下文对象
const editorCtx = ref(null)
// 设置颜色板
const color = reactive({
// 前景色
forecolor: '#ff0000',
// 背景色
backgroundColor: '#ff0000',
})
// 颜色板键值
const colorKey = ref('forecolor')
// 富文本编辑器宽度
const editorWidth = ref(0)
onMounted(() => {
// 创建编辑器上下文对象
onEditorReady()
// 获取编辑器节点信息
getEditorInfo()
})
// 创建编辑器上下文对象
function onEditorReady() {
uni.createSelectorQuery().select('#editor').context((res) => {
editorCtx.value = res.context
}).exec()
}
// 获取编辑器节点信息 用来处理图片
function getEditorInfo() {
const query = uni.createSelectorQuery().in(proxy);
query.select("#editor").boundingClientRect((data) => {
editorWidth.value = data.width
}).exec();
}
// 初始化编辑器上下文对象
function init(html) {
editorCtx.value.setContents({
html,
})
}
// 撤销
function undo() {
editorCtx.value.undo()
}
// 重做
function redo() {
editorCtx.value.redo()
}
/**
* 执行editor方法
* @param {Object} event
*/
function handleEditor(event) {
let {
name,
value
} = event.target.dataset
if (!name) return
editorCtx.value.format(name, value)
}
/**
* 编辑器状态被变化
* @param {Object} e
*/
function onStatusChange(e) {
Object.assign(formats, e.detail)
}
// 插入下划线
function handleInsertDivider() {
editorCtx.value.insertDivider()
}
// 清空编辑器内容
function handleClear() {
editorCtx.value.clear()
}
// 清除所有格式
function handleRemoveFormat() {
editorCtx.value.removeFormat()
}
// 插入图片
function handleImage() {
util.upload_image({
type: 1,
success: rs => {
editorCtx.value.insertImage({
src: rs.value,
alt: '图像',
width: Math.min(rs.width, editorWidth.value),
extClass: 'editorImg',
})
}
})
}
/**
* 选择颜色
* @param {Object} key 需要修改颜色的键
*/
function handleColor(key) {
colorKey.value = key
proxy.$refs.pickerColorRef.open()
}
/**
* 选择颜色
* @param {Object} event
*/
function handlePickerColorConfirm(event) {
// console.log('event', event)
color[colorKey.value] = event
}
// 设置标题
function handleHeader() {
const config = [{
name: '一级标题',
value: '1'
},
{
name: '二级标题',
value: '2'
},
{
name: '三级标题',
value: '3'
},
{
name: '四级标题',
value: '4'
},
{
name: '五级标题',
value: '5'
},
{
name: '六级标题',
value: '6'
}
]
// 多选菜单
uni.showActionSheet({
itemList: config.map(item => item.name),
success: (res) => {
editorCtx.value.format('header', config[res.tapIndex].value)
}
})
}
// 富文本编辑
function handleEditorInput(event) {
emit('update:modelValue', event.detail.html)
}
defineExpose({
init,
})
</script>
<template>
<view class="container ptb30">
<view class='toolbar' @click="handleEditor">
<!-- 加粗 -->
<view class="item" data-name="bold">加粗</view>
<!-- 倾斜 -->
<!-- <view class="item" data-name="italic">倾斜</view> -->
<!-- 下划线 -->
<view class="item" data-name="underline">下划线</view>
<!-- 删除线 -->
<view class="item" data-name="strike">删除线</view>
<!-- 左对齐 -->
<view class="item" data-name="align" data-value="left">左对齐</view>
<!-- 居中 -->
<view class="item" data-name="align" data-value="center">居中</view>
<!-- 右对齐 -->
<view class="item" data-name="align" data-value="right">右对齐</view>
<!-- 两端对齐 -->
<!-- <view class="item" data-name="align" data-value="justify">两端对齐</view> -->
<!-- 清除格式 -->
<view class="item" @tap="handleRemoveFormat">清除所有格式</view>
<!-- 字体颜色 -->
<view class="item df aic" data-name="color" :data-value="color.forecolor">
文本颜色
<view class="colorBox ml10" :style="{backgroundColor:color.forecolor}"
@click.stop="handleColor('forecolor')"></view>
</view>
<!-- 字体背景 -->
<view class="item df aic" data-name="backgroundColor" :data-value="color.backgroundColor">
文本背景
<view class="colorBox ml10" :style="{backgroundColor: color.backgroundColor}"
@click.stop="handleColor('backgroundColor')"></view>
</view>
<!-- 有序列表 -->
<view class="item" data-name="list" data-value="ordered">数字列表</view>
<!-- 点列表 -->
<view class="item" data-name="list" data-value="bullet">点列表</view>
<!-- 撤销 -->
<view class="item" @tap="undo">撤销</view>
<!-- 重做 -->
<view class="item" @tap="redo">重做</view>
<!-- 增加缩进 -->
<!-- <view class="item" data-name="indent" data-value="+1">增加缩进</view> -->
<!-- 减少缩进 -->
<!-- <view class="item" data-name="indent" data-value="-1">减少缩进</view> -->
<!-- 分割线 -->
<view class="item" @tap="handleInsertDivider">分割线</view>
<!-- 插入图片 -->
<view class="item" @tap="handleImage">插入图片</view>
<!-- 大标题 -->
<view class="item" @click.stop="handleHeader">插入标题</view>
<!-- 下标 -->
<!-- <view class="item" data-name="script" data-value="sub">下标</view> -->
<!-- 上标 -->
<!-- <view class="item" data-name="script" data-value="super">上标</view> -->
<!-- 清空 -->
<view class="item" @tap="handleClear">清空内容</view>
</view>
<!-- 内容 -->
<view class="main">
<editor id="editor" class="ql-container" placeholder="在此输入产品详情" showImgSize showImgToolbar showImgResize
@statuschange="onStatusChange" @ready="onEditorReady" @input="handleEditorInput">
</editor>
</view>
</view>
<!-- 调色板 -->
<pickerColor ref="pickerColorRef" @change="handlePickerColorConfirm" />
</template>
<style lang="scss" scoped>
// 富文本编辑区
.container {
.toolbar {
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
}
// 列表项
.item {
margin: 0 20rpx 20rpx 0;
font-size: 26rpx;
}
// 内容
.active {
color: #FF9B27;
}
// 内容
.main {
background: #fff;
}
// 色块
.colorBox {
width: 26rpx;
height: 26rpx;
}
}
// 富文本区
.ql-container {
box-sizing: border-box;
width: 100%;
height: 50vh;
padding: 10rpx;
font-size: 16px;
// background-color: #f4f4f4;
border-radius: 10rpx;
border: 2rpx solid #ccc;
}
</style>