Справочная информация: существуют сценарии, в которых в проекте необходимо использовать форматированный текстовый редактор.В настоящее время существует много форматированных текстовых редакторов, и в этом случае используется форматированный текстовый редактор tinymce;
Решение. В vue3 используются два метода, каждый из которых имеет свои преимущества и недостатки:
① Использование официального метода внедрения, преимущества: простота в эксплуатации, недостатки: использование API-ключа для запроса js-файлов в облаке, медленная скорость загрузки, влияющая на работу пользователя;
②Использование локальных файлов для импорта, преимущества: быстрая загрузка, возможность переупаковки в компоненты редактора, недостатки: введение стилей и плагинов более проблематично, а некоторые методы настройки плагинов легко освоить;
Оглавление
1. Официальный метод предоставления Tinymce:
2. Используйте локальные файлы для импорта:
1. Установите tinymce и tinymce-vue
3. Перепакуйте компонент редактора и создайте новый TinymceEditor.vue:
4. Использование в компонентах:
1. Официальный метод предоставления Tinymce:
В этом случае используется метод tinymce версии 5 (tinymce-vue версии 4).
Официальная документация (версия 5): интеграция с Vue | Документы | TinyMCE
1. Установите tinymce-vue:
npm install --save "@tinymce/tinymce-vue@^4"
//或者
yarn add "@tinymce/tinymce-vue@^4"
2. Подать заявку на API-ключ:
3. Использовать в компоненте:
<template>
<div>
<Editor :init="myTinyInit" api-key="你申请到的A P I key" v-model="content" />
</div>
</template>
<script setup>
import {defineExpose, reactive, ref, defineEmits} from 'vue'
import Editor from '@tinymce/tinymce-vue';
const myTinyInit = ref({
width:'100%', //编辑器宽度,在tinymce版本6中要将toolbar_mode设置为wrap才生效
height:500, //编辑器高度
branding: false, //不显示logo
menubar: false,
resize: false,
toolbar_mode: 'wrap',
skeletonScreen: true, //编辑器懒加载,但设置后好像不生效
placeholder: 'Please enter notification content',
plugins: ['lists link image table paste help wordcount'], //需要的插件,可参考官方文档引入自己需要的插件
toolbar: 'undo redo | formatselect | bold italic forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image | help', //工具栏显示工具,可参考官方文档引入自己需要的工具
fontsize_formats: '12px 14px 16px 18px 20px 22px 24px 26px 36px 48px 56px',
content_style: 'body, p{font-size: 14px;color:#606266}', //编辑器内的文本样式,也可以自定义 content.css 文件后引入
//自定义图片上传方法(tinymce版本5)
images_upload_handler:async (blobInfo, success, failure)=> {
var formData = new FormData();
formData.append('file', blobInfo.blob(), blobInfo.filename());
const res = await tinymceImageUpload(formData); //tinymceImageUpload为封装的图片上传方法,可换成自己的方法
if (res.code === 1) {
success(`/image_manipulation/${res.data.filePath}`); //成功之后,返回图片路径,此处/image_manipulation/为图片路径前缀,具体情况根据后端返回的结果来
} else {
failure('Image upload failed due to a XHR Transport error. Code: ' + res.msg);
}
},
})
</script>
2. Используйте локальные файлы для импорта:
В этом случае используется метод tinymce версии 6 (tinymce-vue версии 5).
Официальная документация: Использование пакета TinyMCE с фреймворком Vue.js | Документация TinyMCE
1. Установите tinymce и tinymce-vue
npm install tinymce
npm install tinymce-vue
//or
yarn add tinymce
yarn add tinymce-vue
2. Обработайте путь к файлу:
① Создайте новую папку tinymce в общей папке (если это vue2, она будет в статической папке);
②Языковый пакет: интерфейс по умолчанию английский.Если вам нужно перейти на китайский интерфейс, вам необходимо загрузить китайский языковой пакет , создать новую папку langs в папке tinymce и поместить загруженный файл в папку langs;
③стиль скинов: создайте новую папку tinymce в общей папке (если это vue2, то она будет в статической папке), найдите скины в node_modules и скопируйте всю папку в /public/tinymce/;
3. Перепакуйте компонент редактора и создайте новый TinymceEditor.vue:
<template>
<div>
<Editor v-model="content" :init="myTinyInit"></Editor>
</div>
</template>
<script setup>
import {computed, defineEmits, defineProps, onMounted, reactive, ref, watch} from 'vue'
import tinymce from "tinymce/tinymce";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/icons/default/icons";
import "tinymce/themes/silver";
import "tinymce/models/dom/model";
//按需引入插件
import "tinymce/plugins/image";
import "tinymce/plugins/table";
import "tinymce/plugins/lists";
import "tinymce/plugins/link";
import "tinymce/plugins/help";
import "tinymce/plugins/wordcount";
import axios from "axios";
import {useStore} from "vuex";
import {ElNotification} from "element-plus";
const props = defineProps({
modelValue: {
type: String,
default: ""
},
plugins: {
type: [String, Array],
default:'lists link image table help wordcount',
},
toolbar: {
type: [String, Array],
default: 'undo redo | formatselect | bold italic forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image | help',
}
});
const emit = defineEmits(['input']);
const store = useStore();
const myTinyInit = reactive({
width: '100%',
height: 500,
branding: false,
menubar: false,
resize: false,
skin_url: "/tinymce/skins/ui/oxide", //手动引入
content_css: '/tinymce/skins/content/default/content.css', //手动引入
toolbar_mode: "wrap",
plugins: props.plugins,
toolbar: props.toolbar,
//图片上传方法(注意!!:要使用 promise 对象中的 resolve 返回图片路径,否则会报错)
images_upload_handler: (blobInfo) => new Promise((resolve, reject) => {
let formData = new FormData();
formData.append('file', blobInfo.blob(), blobInfo.filename());
axios.post(`/api/backend/upload`, formData, {
headers: ({
'Content-Type': 'multipart/form-data',
'Authorization': "Bearer " + store.state.user.accessToken
})
}).then(res => {
if (res.data.code === 1) {
resolve(`/image_manipulation${res.data.data.filePath}`)
} else {
ElNotification.warning(res.data.msg)
}
}).catch(error => {
reject(error);
})
}),
});
const initContent = computed(() => {
return props.modelValue
});
onMounted(() => {
tinymce.init({});
})
const content = ref();
watch(initContent, (newVal) => {
content.value = newVal;
}, {deep: true, immediate: true});
watch(content, (newVal) => {
emit("input", newVal);
}, {deep: true});
</script>
<style scoped lang="scss">
</style>
4. Использование в компонентах:
<template>
<div>
<editor v-model="notificationForm.content" @input="(val)=> {notificationForm.content=val}"></editor>
//@input方法需要自己定义,不然父组件可能获取不到editor的值
</div>
</template>
<script setup>
import {reactive} from 'vue'
import Editor from '@/components/backend/TinymceEditor.vue';
const notificationForm = reactive({
content: '',
})
</script>
5. Яма:
①Введение файлов: Помимо необходимости локального хранения языковых пакетов и скинов, могут возникать ошибки при импорте файлов css или плагинов, просто импортируйте соответствующие файлы в соответствии с отчетами об ошибках;
②Пользовательский метод: вы не можете использовать упакованный запрос axios, вы должны использовать объект обещания (подробности см. в определении метода images_upload_handler);