| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- <template>
- <div class="sa-editor">
- <Toolbar :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
- <Editor style="height: 400px; overflow-y: hidden" :defaultConfig="editorConfig" :mode="mode" v-model="valueHtml"
- @onCreated="handleCreated" @onChange="handleChange" />
- </div>
- </template>
- <script setup>
- import '@wangeditor/editor/dist/css/style.css';
- import { onBeforeUnmount, ref, shallowRef, onMounted, watch, nextTick } from 'vue';
- import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
- import { i18nChangeLanguage } from '@wangeditor/editor';
- import { useFile } from '@/sheep/hooks';
- import { checkUrl } from '@/sheep/utils/checkUrlSuffix';
- import adminApi from '@/app/admin/api';
- import { ElMessage } from 'element-plus';
- import { useI18n } from 'vue-i18n';
- const { t, locale } = useI18n();
- // 根据当前语言设置编辑器语言
- const editorLang = locale.value === 'zh-CN' ? 'zh-CN' : 'en';
- i18nChangeLanguage(editorLang);
- const emits = defineEmits(['update:content']);
- const props = defineProps({
- content: {
- type: String,
- default: '',
- },
- directUpload: {
- type: Boolean,
- default: false,
- },
- });
- const mode = 'default';
- // 编辑器实例,必须用 shallowRef
- const editorRef = shallowRef();
- // 内容 HTML
- const valueHtml = ref(props.content);
- watch(
- () => props.content,
- () => {
- valueHtml.value = props.content;
- nextTick(() => {
- editorRef.value.focus();
- });
- },
- );
- const toolbarConfig = {};
- const editorConfig = { MENU_CONF: {} };
- // 根据 directUpload 参数选择上传方式
- if (props.directUpload) {
- // 直接上传模式
- editorConfig.MENU_CONF['uploadImage'] = {
- // 自定义上传
- async customUpload(file, insertFn) {
- try {
- const formData = new FormData();
- formData.append('file', file);
- const response = await adminApi.file.upload({}, formData);
- if (response.code == '200') {
- insertFn(checkUrl(response.data), '', '');
- } else {
- ElMessage.error(response.msg || t('message.imageUploadFailed'));
- }
- } catch (error) {
- console.error('Upload image failed:', error);
- ElMessage.error(t('message.imageUploadFailed'));
- }
- },
- };
- } else {
- // 文件管理器模式
- editorConfig.MENU_CONF['uploadImage'] = {
- // 自定义选择图片
- customBrowseAndUpload(insertFn) {
- useFile(
- {
- fileType: 'image',
- multiple: true,
- },
- {
- confirm: (data) => {
- data.forEach((item) => {
- insertFn(checkUrl(item.url), '', ''); // url alt href
- });
- },
- },
- );
- },
- };
- }
- editorConfig.MENU_CONF['uploadVideo'] = {
- // 自定义选择视频
- customBrowseAndUpload(insertFn) {
- useFile(
- {
- fileType: 'video',
- multiple: true,
- },
- {
- confirm: (data) => {
- data.forEach((item) => {
- insertFn(checkUrl(item.url), ''); // url poster
- });
- },
- },
- );
- },
- };
- editorConfig.MENU_CONF['lineHeight'] = {
- lineHeightList: ['0', '1', '1.5', '2', '2.5'],
- };
- // 编辑器回调函数
- const handleCreated = (editor) => {
- editorRef.value = editor; // 记录 editor 实例
- };
- const handleChange = (editor) => {
- emits('update:content', editor.getHtml());
- };
- onMounted(() => {
- nextTick(() => {
- editorRef.value.focus();
- });
- });
- onBeforeUnmount(() => {
- const editor = editorRef.value;
- if (editor == null) return;
- editor.destroy();
- });
- </script>
- <style lang="scss" scoped>
- .sa-editor {
- border: 1px solid var(--sa-border);
- :deep() {
- .w-e-bar {
- border-bottom: 1px solid var(--sa-border);
- }
- }
- }
- </style>
- <style lang="scss">
- // 全局样式覆盖,确保富文本编辑器的加粗等样式正常显示
- .w-e-text-container [data-slate-editor] {
- strong,
- strong.token.bold,
- b {
- font-weight: bold !important;
- }
- em,
- i {
- font-style: italic !important;
- }
- u {
- text-decoration: underline !important;
- }
- s,
- strike {
- text-decoration: line-through !important;
- }
- }
- </style>
|