123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- <!-- 富文本编辑器 -->
- <template>
- <div>
- <div v-if="props.item?.label" class="ml-2 mb-2 color959595">{{ props.item.label }}</div>
- <div class="z-10 box mb-5">
- <!-- 工具栏 -->
- <Toolbar
- :editor="editorRef"
- :editorId="editorId"
- class="border-0 b-b-1 border-solid border-[var(--tags-view-border-color)]"
- />
- <!-- 编辑器 -->
- <Editor
- v-model="valueHtml"
- :defaultConfig="editorConfig"
- :editorId="editorId"
- :style="editorStyle"
- @on-maxLength="onMaxLengthFun"
- @on-blur="onBlurFun"
- @on-change="handleChange"
- @on-created="handleCreated"
- />
- </div>
- </div>
- </template>
- <script setup>
- defineOptions({ name: 'wangEditor-index' })
- import '@wangeditor/editor/dist/css/style.css' // 引入 css
- import { onBeforeUnmount, ref, shallowRef, unref, computed, nextTick, watch } from 'vue'
- import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
- import { i18nChangeLanguage } from '@wangeditor/editor'
- import { isNumber } from '@/utils/is'
- import Snackbar from '@/plugins/snackbar'
- // import { getAccessToken, getTenantId } from '@/utils/auth'
- i18nChangeLanguage('zh-CN')
- const props = defineProps({
- modelValue: {
- type: String,
- default: '',
- },
- item: { // 表单配置数据
- type: Object,
- default: () => {}
- },
- editorId: {
- type: String,
- default: 'wangEditor-1',
- },
- height: {
- type: [Number, String],
- default: '300px'
- },
- editorConfig: {
- type: Object,
- default: () => {}
- },
- readonly: {
- type: Boolean,
- default: false
- },
- })
- const emit = defineEmits(['change', 'update:modelValue'])
- // 编辑器实例,必须用 shallowRef
- const editorRef = shallowRef()
- const valueHtml = ref('')
- watch(
- () => props.modelValue,
- (val) => {
- if (val === null) val = ''
- if (val === unref(valueHtml)) return
- valueHtml.value = val
- },
- {
- immediate: true
- }
- )
- // 监听
- watch(
- () => valueHtml.value,
- (val) => {
- emit('update:modelValue', val === '<p><br></p>' ? '' : val)
- }
- )
- const handleCreated = (editor) => {
- editorRef.value = editor
- }
- const onMaxLengthFun = (editor) => {
- const maxLength = editor?.getConfig()?.maxLength || null
- if (maxLength) Snackbar.info(`最多可输入${maxLength}个字符`)
- }
- const onBlurFun = (editor) => {
- const text = editor.getText()?.replace(/\s+/g, '')
- if (!text) valueHtml.value = ''
- }
- // 编辑器配置
- const editorConfig = computed(() => {
- return Object.assign(
- {
- placeholder: '请输入内容...',
- readOnly: props.item.readonly || props.readonly,
- maxLength: Number(props.item.maxLength) || Number(props.maxLength) || null,
- customAlert: (s, t) => {
- switch (t) {
- case 'success':
- Snackbar.success(s)
- break
- case 'info':
- Snackbar.info(s)
- break
- case 'warning':
- Snackbar.warning(s)
- break
- case 'error':
- Snackbar.error(s)
- break
- default:
- Snackbar.info(s)
- break
- }
- },
- autoFocus: false,
- scroll: true,
- MENU_CONF: {
- ['uploadImage']: {
- server:`${import.meta.env.VITE_BASE_URL}/commons/upload`,
- // 单个文件的最大体积限制,默认为 2M
- // maxFileSize: 5 * 1024 * 1024,
- // 最多可上传几个文件,默认为 100
- // maxNumberOfFiles: 10,
- // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
- // allowedFileTypes: ['image/*'],
- // 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。
- // meta: { updateSupport: 0 },
- // 将 meta 拼接到 url 参数中,默认 false
- // metaWithUrl: true,
- // 自定义增加 http header
- // headers: {
- // Accept: '*',
- // Authorization: 'Bearer ' + getAccessToken(),
- // 'tenant-id': getTenantId()
- // },
- // 跨域是否传递 cookie ,默认为 false
- // withCredentials: true,
- // 超时时间,默认为 10 秒
- timeout: 5 * 1000, // 5 秒
- // form-data fieldName,后端接口参数名称,默认值wangeditor-uploaded-image
- fieldName: 'file',
- // 上传之前触发
- onBeforeUpload(file) {
- console.log(file)
- return file
- },
- // 上传进度的回调函数
- onProgress(progress) {
- // progress 是 0-100 的数字
- console.log('progress', progress)
- },
- onSuccess(file, res) {
- console.log('onSuccess', file, res)
- },
- onFailed(file, res) {
- alert(res.message)
- console.log('onFailed', file, res)
- },
- onError(file, err, res) {
- alert(err.message)
- console.error('onError', file, err, res)
- },
- // 自定义插入图片
- // customInsert(res, insertFn: InsertFnType) {
- // insertFn(res.data, 'image', res.data)
- // }
- }
- },
- uploadImgShowBase64: true,
- },
- props.editorConfig || props.item.editorConfig || {}
- )
- })
- const editorStyle = computed(() => {
- const h = props.item.height || props.height
- return {
- height: isNumber(h) ? `${h}px` : h
- }
- })
- // 回调函数
- const handleChange = (editor) => {
- emit('change', editor)
- }
- // 组件销毁时,及时销毁编辑器
- onBeforeUnmount(() => {
- const editor = unref(editorRef.value)
- // 销毁,并移除 editor
- editor?.destroy()
- })
- const getEditorRef = async () => {
- await nextTick()
- return unref(editorRef.value)
- }
- defineExpose({
- getEditorRef
- })
- </script>
- <style lang="scss" scoped>
- .box {
- border: 1px solid #a2a2a2;
- border-radius: 5px;
- padding: 1px;
- &:hover {
- border: 1px solid #2b2b2b;
- }
- }
- .color959595 {
- color: #959595;
- }
- </style>
|