ckeditor5 vue3使用

Vue 2023-02-25 1457

ckeditor官方提供了开箱即用的vue组件,但是其功能很有限,如果只是希望简单使用可以用此组件。如果需要更复杂的功能,则需要自己定义。

官方地址文档:https://ckeditor.com/docs/ckeditor5/latest/installation/frameworks/vuejs-v3.html

1.在线定义

进入https://ckeditor.com/ckeditor-5/online-builder/,选择

选择功能

2.打包使用ckeditor文件

下载的文件解压后或得到一个webpack项目,你可以自己在其中新增功能,在打包使用,或者直接使用

3.添加额外功能

比如添加控制文本位置插件,先在此项目中安装插件

npm install @ckeditor/ckeditor5-autoformat --save-dev

在ckeditor.js引入

import Autoformat from '@ckeditor/ckeditor5-autoformat/src/autoformat.js';

Editor.builtinPlugins = [
	Alignment,
    .... 其他插件
]
Editor.defaultConfig = {
	toolbar: {// 控制工具栏显示
		items: [
			'heading',
			'htmlEmbed',
			'|',
			'alignment',
         ... 其他忽略
         ]
    }
}

这样操作就可显示控制文本位置的图标

4.自定义插件

自己定义插件,你需要先安装下方依赖

npm install @ckeditor/ckeditor5-ui @ckeditor/ckeditor5-core --save-dev

如自定义一个上传图片按钮

import { Plugin, icons } from '@ckeditor/ckeditor5-core';
import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';

class UploadImage extends Plugin {
	init() {
		const editor = this.editor;
		// The button must be registered among the UI components of the editor
		// to be displayed in the toolbar.
		editor.ui.componentFactory.add( 'customUploadImage', () => {
			// The button will be an instance of ButtonView.
			const button = new ButtonView();

			button.set( {
				label: '上传图片',
				withText: true,
				class: 'custom-upload-image',
				icon: icons.image,
			} );
			// // 执行
			// button.on('execute', () => {
			// 	console.log("执行了...")
			// });
			return button;
		} );
	}
}

Editor.builtinPlugins = [UploadImage, ]

Editor.defaultConfig = {
	toolbar: {
		items: ['customUploadImage']
    }
}

在npm run build打包就可以显示出来

5. 封装Vue组件

引入打包的ckeditor.js,将整个build复制到项目的public,可以删除其中的部分翻译文件,保留中英文js文件即可,在index.html引入ckeditor.js

<template>
  <div style="width: 100%">
    <div class="editor"></div>
  </div>
</template>

<script lang="ts" setup>
import { markRaw, nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue"
import { FileService } from "@/components/FileService"
import { debounce } from "@/utils/common"

const props = defineProps({
  modelValue: {
    type: String,
    default: "",
  },
})
const lastEditorData = ref("") // 上一次编辑数据
const emit = defineEmits(["update:modelValue"])
const editorRef = ref()
const showUploadImageDialog = () => {
  const customUploadImageEle = document.querySelector(".custom-upload-image") as HTMLElement
  if (customUploadImageEle) {
    customUploadImageEle.addEventListener("click", () => {
      FileService.show({
        handleOk: (files) => {
          const src = files[0].url
          const htmlDP = editorRef.value.data.processor
          const viewFragment = htmlDP.toView(`<img src="${src}" alt="" />`)
          const modelFragment = editorRef.value.data.toModel(viewFragment)
          editorRef.value.model.insertContent(modelFragment)
        },
      })
    })
  }
}
// 设置html
const setHtml = (v: string) => {
  return editorRef.value.setData(v)
}
watch(
  () => props.modelValue,
  (newVal: any) => {
    if (editorRef.value && newVal !== lastEditorData.value) {
      setHtml(newVal)
    }
  }
)
// 获取html
const getHtml = () => {
  return editorRef.value.getData()
}
const renderCkEditor = () => {
  ;(window as any).ClassicEditor.create(document.querySelector(".editor"), {
    toolbar: {
      shouldNotGroupWhenFull: true, // 当宽度超出时,换行显示工具栏
    },
    htmlSupport: {
      allow: [
        // Enables all HTML features.
        {
          name: /.*/,
          attributes: true,
          classes: true,
          styles: true,
        },
      ],
      disallow: [
        {
          attributes: [{ key: /.*/, value: /data:(?!image\/(png|jpeg|gif|webp))/i }],
        },
      ],
    },
  })
    .then((editor: any) => {
      editorRef.value = markRaw(editor)
      nextTick(() => {
        showUploadImageDialog()
        const emitDebouncedInputEvent = debounce((evt: any) => {
          const data = (lastEditorData.value = editorRef.value.getData())
          emit("update:modelValue", data)
        }, 300)
        editorRef.value.model.document.on("change:data", emitDebouncedInputEvent)
      })
    })
    .catch((error: any) => {
      console.error(error)
    })
}
onMounted(() => {
  renderCkEditor()
})

onBeforeUnmount(() => {
  if (editorRef.value) {
    // 销毁组件
    setHtml("")
    editorRef.value.destroy()
  }
})

defineExpose({ editorRef, getHtml, setHtml })
</script>

<style lang="scss" scoped>
:deep(.ck-editor__editable) {
  height: 600px;
  //overflow-y: scroll;
}
</style>

 

标签:Vue

文章评论

评论列表

已有0条评论