Skip to content

Editor 富文本编辑器

如何富文本编辑器,如何自定义表单组件。

WARNING

由于富文本编辑器是一个第三方插件,为了保持配置的灵活性,GvoUI 并没有将其直接集成。本文将逐步指导您如何自定义配置一个能够与表单进行交互的表单组件。

准备工作

当你想创建一个表单组件时候,需要从表单组件获取必要的表单状态disabledsizevalidateState;监听表单事件reset;触发事件给 FormItem, 如:changefocus...

VueQuill 插件为例,需要先安装:

sh
yarn add @vueup/vue-quill@latest

在自定义组件里加入以下逻辑:

js
// 注入 FormItem
const govFormItem = inject("govFormItem", null);

// 来自表单状态
const { disabled, size, validateState } = govFormItem;

// 告知表单组件发生了?例如 change 事件
govFormItem?.$emit("change");

// 监听表单 reset 事件来处理重置逻辑
govFormItem?.$on("reset", () => {
	// ...
});

富文本示例

以下代码为简单的封装,你可以复制代码到你的公共组件内,选择适当的 Toolbar 、或者配置更多模块。

控制台
 validState: 
invalidFields:
html:
查看 Editor 封装代码
vue
<template>
	<div
		class="costom-editor"
		:class="[
			`size-${innerSize}`,
			{
				'is-disabled': innerDisabled,
				'is-error': isError,
			},
		]"
	>
		<!-- 动态导入 QuillEditor 组件 -->
		<component
			:is="quillEditorComponent"
			theme="snow"
			v-model:content="innerValue"
			contentType="html"
			style="height: 200px"
			placeholder="请输入"
			@focus="handleFocus"
			@blur="handleBlur"
			ref="editorRef"
		/>
	</div>
</template>

<script setup>
import { shallowRef, ref, computed, inject, onMounted, watchEffect } from "vue";
import "@vueup/vue-quill/dist/vue-quill.snow.css";

defineOptions({
	name: "GovEditor",
});

const props = defineProps({
	modelValue: String,
	size: String,
	disabled: Boolean,
});

// 动态导入 QuillEditor 组件
let quillEditorComponent = shallowRef(null);
const loadQuillEditor = async () => {
  const module = await import("@vueup/vue-quill");
  quillEditorComponent.value = module.QuillEditor;
};
onMounted(loadQuillEditor);


const editorRef = ref();
const govFormItem = inject("govFormItem", null);
const emits = defineEmits(["update:modelValue", "change", "focus", "blur"]);

// 绑定值
const innerValue = computed({
	get() {
		return props.modelValue;
	},
	set(value) {
		emits("update:modelValue", value);
		emits("change", value);
		govFormItem?.$emit("change");
	},
});

// 重置功能
// 参见 VueQuill 的 setHTML
// 文档:https://vueup.github.io/vue-quill/api/methods.html#sethtml-html
const initialValue = ref();
onMounted(() => {
	initialValue.value = props.modelValue;
});
govFormItem?.$on("reset", () => {
	editorRef.value?.setHTML(initialValue.value || "");
});

// 获得焦点
const handleFocus = () => {
	emits("focus");
	govFormItem?.$emit("focus");
};

// 失去焦点
const handleBlur = () => {
	emits("blur");
	govFormItem?.$emit("blur");
};

// 计算大小
const innerSize = computed(() => {
	return props?.size || govFormItem?.size || "default";
});

// 是否禁用
const innerDisabled = computed(() => {
	return props?.disabled || govFormItem?.disabled;
});

// 表单验证是否为错误状态
const isError = computed(() => {
	return govFormItem?.validateState === "error";
});

// 设置禁用,quill 文档:https://quilljs.com/docs/api/#disable
watchEffect(() => {
	const quill = editorRef.value?.getQuill?.();
	quill?.enable(!innerDisabled.value);
});
</script>

<style lang="scss">
.costom-editor {
	&.is-disabled {
		.ql-toolbar {
			background: #f9f9f9;
		}
		.ql-container {
			background: #f9f9f9;
		}
	}
	&.is-error {
		.ql-toolbar {
			border-color: red;
		}
		.ql-container {
			border-color: red;
		}
	}
}
</style>
查看 Form 内调用代码
vue
<template>
	<demo-container>
		<gov-form ref="ruleFormRef" :model="formData" :rules="formRules">
			<gov-form-item label="禁用富文本">
				<gov-switch v-model="disabled" />
			</gov-form-item>
			<gov-form-item prop="html" label="姓名">
				<customEditor v-model="formData.html" :disabled="disabled" />
			</gov-form-item>
			<gov-form-item>
				<gov-button @click="handleSubmit" type="primary">
					提交
				</gov-button>
				<gov-button @click="handleReset"> 重置 </gov-button>
				<gov-button @click="handleClearValidate"> 清除验证 </gov-button>
			</gov-form-item>
		</gov-form>
		<hr />
		<template #console>
			validState: {{ validState }}<br />
			invalidFields: {{ invalidFields }}<br />
			html:{{ formData.html }}
		</template>
	</demo-container>
</template>

<script setup>
import { ref, reactive } from "vue";
import customEditor from "./editor.vue";

const ruleFormRef = ref();
const disabled = ref(true);
const validState = ref(null);
const invalidFields = ref(null);

// 表单数据
const formData = reactive({
	html: "",
});

// 表单验证
const formRules = reactive({
	html: [
		{
			required: true,
			validator: (rule, value = "", callback) => {
				const text = value.trim();
				if (!text || text === "<p><br></p>") {
					return callback(new Error("该项为必填项!"));
				}
				return callback();
			},
			trigger: ["focus", "blur", "change"],
		},
	],
});

// 提交并验证
const handleSubmit = () => {
	ruleFormRef.value.validate((valid, fields) => {
		validState.value = valid;
		invalidFields.value = fields;
	});
};

// 重置
const handleReset = () => {
	validState.value = null;
	invalidFields.value = null;
	ruleFormRef.value.resetFields();
};

// 清除表单验证
const handleClearValidate = () => {
	validState.value = null;
	invalidFields.value = null;
	ruleFormRef.value.clearValidate();
};
</script>

Released under the MIT License.