目录
一、自定义组件
Editor.vue
<!-- 自定义的富文本框的组件 -->
<template>
<div style="border: 1px solid #ccc">
<Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" />
<Editor
style="height: 300px; overflow-y: hidden"
v-model="valueHtml"
@onCreated="handleCreated"
@onChange="handleChange"
/>
</div>
</template>
<script lang="ts" setup>
import "@wangeditor/editor/dist/css/style.css"; // 引入 css
import { ref, shallowRef, onMounted, watch } from "vue";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { uploadApi } from "@/api";
//定义modelValue属性
const props = defineProps({ modelValue: { type: String, default: "" } });
const emit = defineEmits(["update:modelValue"]);
// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef();
// 内容 HTML
const valueHtml = ref("");
watch(
() => props.modelValue,
() => {
editorRef.value.setHtml(props.modelValue);
}
);
const handleCreated = (editor: any) => {
editorRef.value = editor; // 记录 editor 实例,重要!
editor.setHtml(props.modelValue);
editor.getConfig().MENU_CONF["uploadImage"] = {
// 自定义上传
async customUpload(file: File, insertFn: any) {
// TS 语法
// file 即选中的文件
// 自己实现上传,并得到图片 url alt href
// 最后插入图片
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (f) => {
uploadApi.upload
.call({ name: file.name, base64: f.target?.result })
.then((url: any) => {
insertFn(url, file.name, url);
});
};
},
};
editor.getConfig().MENU_CONF["uploadVideo"] = {
// 自定义上传
async customUpload(file: File, insertFn: any) {
// TS 语法
// file 即选中的文件
// 自己实现上传,并得到图片 url alt href
// 最后插入图片
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (f) => {
uploadApi.upload
.call({ name: file.name, base64: f.target?.result })
.then((url: any) => {
// 从 res 中找到 url poster ,然后插入视频
insertFn(url, "");
});
};
},
};
};
const handleChange = (editor: any) => {
emit("update:modelValue", editor.getHtml());
};
</script>
二、使用改自定义组件
将自定义得组件到修改页面中 其中详情页是富文本得位置
<template>
<el-form
ref="formRef"
:model="formData"
label-width="120px"
status-icon
>
<el-form-item label="商品名称" prop="name">
<el-input v-model="formData.name" />
</el-form-item>
<el-form-item label="副标题" prop="subName">
<el-input v-model="formData.subName" type="textarea" />
</el-form-item>
<el-form-item label="商品图片" prop="img">
<el-space>
<Tuku v-model="formData.img1" />
<Tuku v-model="formData.img2" />
<Tuku v-model="formData.img3" />
</el-space>
</el-form-item>
<el-form-item label="商品价格" prop="price">
<el-input-number
v-model="formData.price"
:precision="2"
:step="0.1"
:min="0"
/>
</el-form-item>
<el-form-item label="排序" prop="seq">
<el-input-number v-model="formData.seq" />
</el-form-item>
<el-form-item label="商品分类" prop="categoryId">
<el-input v-model="formData.categoryId" />
</el-form-item>
<el-form-item label="详情" >
<Editor v-model="formData.brief"></Editor>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm(formRef)"> 保存 </el-button>
<el-button @click="resetForm(formRef)">重置</el-button>
</el-form-item>
</el-form>
</template>
<script setup lang="ts">
import { ref, onMounted, reactive } from "vue";
import { productApi } from "@/api/index";
import { ElMessage } from "element-plus";
import Tuku from "@/components/Tuku.vue";
import { useRoute } from "vue-router";
import Editor from "@/components/Editor.vue";
const route = useRoute();
const formRef = ref();
const formData = reactive({
id: 0,
name: "",
subName: "",
categoryId: "5",
img1: "",
img2: "",
img3: "",
seq: 0,
price: 0,
brief:""
});
onMounted(() => {
formData.id = Number(route.query.id);
callProductApi();
});
const callProductApi = () => {
productApi.select.call({ id: formData.id }).then((res: any) => {
formData.name = res[0].name;
formData.subName = res[0].subName;
formData.categoryId = res[0].categoryId;
formData.seq = res[0].seq;
formData.price = res[0].price;
formData.brief = res[0].brief;
let imgArray = res[0].img.split(",");
formData.img1 = imgArray[0];
if(imgArray.length > 1){
formData.img2 = imgArray[1];
}
if(imgArray.length > 2){
formData.img3 = imgArray[2];
}
});
};
const submit = () => {
callSaveProductApi();
};
const callSaveProductApi = () => {
let img = [];
if (formData.img1 != "") {
img.push(formData.img1);
}
if (formData.img2 != "") {
img.push(formData.img2);
}
if (formData.img3 != "") {
img.push(formData.img3);
}
let params = {
id: formData.id,
name: formData.name,
subName: formData.subName,
categoryId: formData.categoryId,
img: img.join(","),
price: formData.price,
seq: formData.seq,
lastUpdateBy: "admin",
brief: formData.brief
};
productApi.update.call(params).then((_res: any) => {
ElMessage.success("保存成功");
});
};
const submitForm = async (formEl: any) => {
if (!formEl) return;
await formEl.validate((valid: any, _fields: any) => {
if (valid) {
submit();
}
});
};
const resetForm = (formEl: any) => {
if (!formEl) return;
formEl.resetFields();
};
</script>