jobsys-newbie
Version:
Enhanced component based on ant-design-vue
203 lines (176 loc) • 4.61 kB
JSX
import { defineComponent, onBeforeUnmount, onMounted, ref, shallowRef, inject, watch } from "vue"
import Editor from "./components/WangEditor.vue"
import Toolbar from "./components/WangToolbar.vue"
import { message, Form } from "ant-design-vue"
import "./index.less"
import { NEWBIE_EDITOR } from "../provider/NewbieProvider.jsx"
import { useFetch, useProcessStatusSuccess, useT } from "../../hooks"
/**
* 富文本编辑器
* 基于 WangEditor
*
* @version 1.0.0
* @see https://www.wangeditor.com/v5/for-frame.html#vue3
*/
export default defineComponent({
name: "NewbieEditor",
props: {
/**
* 输入框的值
* @model
*/
value: { type: String, default: "" },
/**
* 占位符
*/
placeholder: { type: String, default: "" },
/**
* 是否禁用
*/
disabled: { type: Boolean, default: false },
/**
* 是否只读
*/
readonly: { type: Boolean, default: false },
/**
* @param {Object} config.toolbarConfig [工具栏配置](https://www.wangeditor.com/v5/toolbar-config.html)
* @param {Object} config.editorConfig [编辑器配置](https://www.wangeditor.com/v5/editor-config.html)
*/
config: {
type: Object,
default: () => ({
toolbarConfig: {},
editorConfig: {},
}),
},
},
emits: ["update:value"],
setup(props, { emit, expose }) {
const formItemContext = Form.useInjectFormItemContext()
// 编辑器实例,必须用 shallowRef,重要!
const editorRef = shallowRef()
// 内容 HTML
const valueHtml = ref("")
const toolbarConfig = ref({
excludeKeys: ["group-video", "emotion"],
...props.config?.toolbarConfig,
})
const { uploadUrl } = inject(NEWBIE_EDITOR, () => ({}))
const editorConfig = ref({
placeholder: props.placeholder || useT("form.please-input", { title: useT("common.content") }),
readOnly: props.disabled || props.readonly,
MENU_CONF: {
uploadImage: {
async customUpload(file, insertFn) {
const formData = new FormData()
formData.append("file", file)
try {
let res = await useFetch().post(uploadUrl, formData)
useProcessStatusSuccess(res, () => {
const { url, alt, href } = res.result
insertFn(url, alt, href)
})
} catch (e) {
console.log(e)
}
},
},
},
...props.config?.editorConfig,
})
const setContent = (content) => {
if (editorRef.value) {
editorRef.value.setHtml(content)
}
}
// 组件销毁时,也及时销毁编辑器,重要!
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor == null) return
editor.destroy()
})
watch(
() => props.value,
(val) => {
if (val !== valueHtml.value && editorRef.value) {
setContent(val)
}
},
)
// 编辑器回调函数
const handleCreated = (editor) => {
editorRef.value = editor // 记录 editor 实例,重要!
setContent(props.value)
editor.on("fullScreen", () => {
document.body.classList.add("fullscreen")
})
editor.on("unFullScreen", () => {
document.body.classList.remove("fullscreen")
})
if (!props.disabled && !props.readonly) {
toolbarElemRef.value = createToolbarElem()
}
}
const handleChange = (editor) => {
let html = editor.getHtml()
if (editor.isEmpty()) {
html = ""
}
if (html !== props.value) {
emit("update:value", html)
formItemContext.onFieldChange()
}
}
const customAlert = async (info, type) => {
switch (type) {
case "success":
message.success(info)
break
case "info":
message.info(info)
break
case "warning":
message.warning(info)
break
case "error":
message.error(info)
break
default:
message.info(info)
break
}
}
expose({
setContent,
})
/********** render **********/
const toolbarElemRef = ref()
const editorElemRef = ref()
const createToolbarElem = () => {
if (editorRef?.value?.destroy) {
return <Toolbar editor={editorRef.value} defaultConfig={toolbarConfig.value} style="border-bottom: 1px solid #f0f0f0"></Toolbar>
} else {
return <div></div>
}
}
const createEditorElem = () => (
<Editor
v-model={valueHtml.value}
defaultConfig={editorConfig.value}
style="height: 400px; overflow-y: hidden"
onOnChange={handleChange}
onOnCreated={handleCreated}
onCustomAlert={customAlert}
/>
)
onMounted(() => {
editorElemRef.value = createEditorElem()
})
return () => (
<div style="border: 1px solid #f0f0f0">
{toolbarElemRef.value}
{editorElemRef.value}
</div>
)
},
})