一 资源下载
tinymce 官方为vue项目提供了一个组件 tinymce-vue
1 | npm install tinymce -S |
我package.json文件里tinymce的版本是^4.8.5
安装之后,在 node_modules 中找到 tinymce/skins 目录,然后将 skins 目录拷贝到 static 目录下
// 如果是使用 vue-cli 3.x 构建的 typescript 项目,就放到 public 目录下,文中所有 static 目录相关都这样处理
tinymce 默认是英文界面,所以还需要下载一个中文语言包(记得搭梯子!搭梯子!搭梯子!)
下载中文语言包,附上地址中文包下载地址
然后将这个语言包放到 static 目录下,为了结构清晰,我包了一层 tinymce 目录

二 创建组件,在组件中引入以下文件
创建组件 tinymce-editor.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | <template> <textarea :id='id' :value='value'></textarea> </template> <script> // Import TinyMCE import store from '@/store/store' import tinymce from 'tinymce/tinymce' import 'tinymce/skins/lightgray/skin.min.css' import 'tinymce/themes/modern/theme' //import 'tinymce/themes/silver/theme' import 'tinymce/plugins/advlist' import 'tinymce/plugins/link' import 'tinymce/plugins/image' import 'tinymce/plugins/code' import 'tinymce/plugins/table' import 'tinymce/plugins/textcolor' import 'tinymce/plugins/paste' import 'tinymce/plugins/colorpicker' const INIT = 0 const CHANGED = 2 export default { data () { return { no: '' } }, props: { value: { type: String, editor: null, required: true }, setting: {}, url: { // 接口 default: '', type: String }, accept: { // 文件类型 default: 'image/jpeg, image/png', type: String }, maxSize: { // 大小 default: 2097152, type: Number }, withCredentials: { default: false, type: Boolean } }, watch: { value: function (val) { console.log('init ' + val) if (this.status === INIT || tinymce.activeEditor.getContent() !== val) { tinymce.activeEditor.setContent(val) } this.status = CHANGED } }, data () { return { status: INIT, id: 'editor-' + new Date().getMilliseconds() } }, methods: { }, mounted () { const _this = this const setting = { selector: '#' + _this.id, images_upload_url: 'http://localhost:8080/uploadCenter/upload/images', language_url: '/tinymce/langs/zh_CN.js', language: 'zh_CN', init_instance_callback: function (editor) { // EDITOR = editor console.log('Editor: ' + editor.id + ' is now initialized.') editor.on('input change undo redo', () => { var content = editor.getContent() _this.$emit('show', content) }) }, content_style: ` * { padding:0; margin:0; } html, body { height:100%; } img { max-width:100%; display:block;height:auto; } a { text-decoration: none; } iframe { width: 100%; } p { line-height:1.6; margin: 0px; } table { word-wrap:break-word; word-break:break-all; max-width:100%; border:none; border-color:#999; } .mce-object-iframe { width:100%; box-sizing:border-box; margin:0; padding:0; } ul,ol { list-style-position:inside; } `, insert_button_items: 'image link | inserttable', paste_retain_style_properties: 'all', paste_word_valid_elements: '*[*]', // word需要它 paste_data_images: true, // 粘贴的同时能把内容里的图片自动上传,非常强力的功能 paste_convert_word_fake_lists: false, // 插入word文档需要该属性 paste_webkit_styles: 'all', paste_merge_formats: true, nonbreaking_force_tab: false, paste_auto_cleanup_on_paste: false, menubar: 'edit insert view format table tools', branding: false, plugins: [ 'advlist autolink lists image charmap print preview hr anchor pagebreak imagetools', 'searchreplace visualblocks visualchars code fullpage', 'insertdatetime nonbreaking save table contextmenu directionality', 'emoticons paste textcolor colorpicker textpattern imagetools' ], toolbar1: ' newnote print fullscreen preview | undo redo | insert | styleselect | forecolor backcolor bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image emoticons media codesample', // 上传图片回调 images_upload_handler (blobInfo, success, failure) { let xhr = '' let formData = '' xhr = new XMLHttpRequest() xhr.withCredentials = false xhr.open('POST', 'http://localhost:8080/uploadCenter/upload/images') xhr.setRequestHeader('token','') xhr.onload = () => { let json = {} if (xhr.status !== 200) { failure('HTTP Error: ', xhr.status) return } console.log(xhr) json = JSON.parse(xhr.responseText) console.log(json) success(json.data.httpFilePath) } formData = new FormData() formData.append('file', blobInfo.blob()) xhr.send(formData) } } Object.assign(setting, _this.setting) tinymce.init(setting) }, beforeDestroy: function () { tinymce.get(this.id).destroy() } } </script> |
三 其他组件引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <template> <div class="app-container calendar-list-container"> <div style="width: 100%;"> <editor class="editor" :value="content" :setting="editorSetting" @show="editors" :with-credentials="withCredentials"></editor> </div> </div> </template> <script> import editor from './tinymce-editor' // 根据tinymce-editor.vue组件位置引入 export default { data () { return { editorSetting: { // 配置富文本编辑器高 height: 500 }, withCredentials: true, content: '', // 富文本编辑器双向绑定的内容 formLeft: { title: '' } } }, components: { // 引入组件 editor }, methods: { editors (content) { // editor组件传过来的值赋给content console.log(content) this.content = content } } } </script> |