-
技术选型
tips: tinymce在vue中常用的有两种方式
第一种: 官方组件,点我
优点: 不用自己封装组件
缺点: 需要申请特定apikey,类似于百度,高德地图;
第二种: 就是下面这种
优点: 不需要申请特定的apikey
缺点: 需要自己手动的封装组件,灵活性高
-
Vue
2.x和3.x基本没有区别 -
tinymce
version 6.8.3-
文档 中文 | 英文
-
下载
yarn add tinymce
npm install tinymcecnpm install tinymce
选择其中一种适合自己的就行
-
-
smms图床
点我申请- 文档 点我
-
-
如何使用
-
- 首先将node_modules中的tinymce包完整的复制到public并在node_modules中删除
-
-
在public/index.html中引入
-
-
-
为了方便我这边直接创建了一个vue文件,可以理解为vue组件,直接把源码放进去
<template> <div class="chart-container"> <el-row ref="tiny-editor" :id="`tiny-editor-${randomKey}`"></el-row> <el-row style="margin-top: 20px;"> <el-col :span="12" style="text-align: left;"> <el-button type="primary" @click="getEditorCtx">点击</el-button> </el-col> </el-row> </div> </template> <script> import axios from "axios"; const toolbar = [ "template fullscreen undo redo restoredraft cut copy paste pastetext forecolor backcolor bold italic underline strikethrough link anchor alignleft aligncenter alignright alignjustify outdent indent bullist numlist blockquote subscript superscript removeformat ", "styleselect formatselect fontselect fontsizeselect table image axupimgs media emoticons charmap hr pagebreak insertdatetime selectall visualblocks searchreplace code print preview indent2em lineheight formatpainter", ]; const plugins = "template preview searchreplace autolink directionality visualblocks visualchars " + "fullscreen image link media template code codesample table charmap pagebreak nonbreaking " + "anchor insertdatetime advlist lists wordcount autosave emoticons"; import { Message } from "element-ui"; export default { data() { return { randomKey: Date.now(), }; }, mounted() { this.$nextTick(() => { this.init() }) }, methods: { getEditorCtx() { let str = tinymce.get(`tiny-editor-${this.randomKey}`).getContent(); console.log(str); }, async uploadImageReq(formDataObj, config) { const formData = new FormData(); Object.keys(formDataObj).forEach(key => { formData.append(key, formDataObj[key]) }) try { // 为了方便,我是在本地解决跨域问题 let res = await axios.post('/smms/upload', formData, { onUploadProgress: e => { config?.progress && config.progress(e.loaded / e.total * 100); }, headers: { // smms图床的token // smms图床申请地址,放在了上面 Authorization: "XXXXXXXXX", "Content-Type": "multipart/form-data" } }); return res; } catch (error) { Message.error(error); return {} } }, uploadFile({ accept, fileType, errorHandle, uploadHandle }) { const input = document.createElement('input'); // 是不是可支持的上传格式 const fileIsAdjective = (file) => { let suffix = `.${file.type.toLowerCase().split('/')[1]}`; return accept.includes(suffix); } input.setAttribute('type', 'file'); input.setAttribute('accept', accept); input.onchange = (e) => { let file = e.target.files[0]; if (!fileIsAdjective(file)) { errorHandle(`请上传 ${accept}后缀的文件`) } else { uploadHandle({ file }) } } input.click(); input.remove() }, getSupportedFileType(fileTypes) { if (!fileTypes || fileTypes.length === 0) return ""; return fileTypes.map(item => item.toLowerCase()).toString(); }, async init() { await tinymce.init({ selector: `#tiny-editor-${this.randomKey}`, //容器,可使用css选择器 language: 'zh_CN', //调用放在langs文件夹内的语言包 plugins, toolbar, menubar: false, height: 800, // 图片上传有两种方式,一种是只供上传的images_upload_handler // 另一种就是file_picker_callback // images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => { // this.uploadImageReq({ // smfile: blobInfo.blob(), // format: 'json' // }, { progress }) // .then( // res => { // resolve(res?.data?.data?.url || "") // }, // error => { // reject(error) // } // ) // }), // 我只写了一个图片上传,视频或者音频或者其他文件类似 file_picker_callback: (callback, value, meta) => { const supportedImageTypes = ['.jpeg', '.jpg', '.png', '.gif', '.bmp', '.svg', '.webp']; const supportedMediaTypes = ['.mp4', '.webm', '.ogg', '.flv', '.avi', '.wmv', '.mov', '.mkv']; const supportedFileTypes = ['.pdf', '.doc', '.docx', '.txt', '.rtf', '.xls', '.xlsx', '.csv', '.ppt', '.pptx', '.zip', '.rar', '.7z', '.tar', '.gz', '.bz2', '.iso', '.dmg', '.apk']; if (meta.filetype == 'image') { this.uploadFile({ accept: this.getSupportedFileType(supportedImageTypes), fileType: 'image', // 空处理函数 errorHandle: (desc) => { callback('', { alt: desc }); }, // 上传处理函数 uploadHandle: ({ file }) => { this.uploadImageReq({ smfile: file, format: 'json' }) .then( res => { callback(res?.data?.data?.url || "", { alt: file.name }) }, error => { callback("", { alt: error.toString() }) } ) } }) } } }); } }, beforeDestroy() { } }; </script> <style lang="scss" scoped> .el-carousel__item { background-color: #409eff; } .tox .tox-sidebar-wrap { &::-webkit-scrollbar { width: 0; } } </style>
-
-
-
预览,两种图片上传的方式有一些不同
-
第一种
-
第二种
-
-
-
tips:
需要注意的是tinymce不同版本的上传图片可能略微有些不同,请注意分辨
tinymce默认使用英文,如果需要中文化,需要去官网下载指定的zh_CN.js文件然后放到langs文件夹下面