| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- <!-- 富文本编辑器 -->
- <template>
- <component v-if="inlineEditor" :is="tagName" :id="elementId" />
- <textarea v-else :id="elementId"></textarea>
- </template>
- <script>
- import tinymce from 'tinymce/tinymce';
- import 'tinymce/themes/silver';
- import 'tinymce/icons/default';
- import 'tinymce/plugins/code';
- import 'tinymce/plugins/preview';
- import 'tinymce/plugins/fullscreen';
- import 'tinymce/plugins/paste';
- import 'tinymce/plugins/searchreplace';
- import 'tinymce/plugins/save';
- import 'tinymce/plugins/autosave';
- import 'tinymce/plugins/link';
- import 'tinymce/plugins/autolink';
- import 'tinymce/plugins/image';
- import 'tinymce/plugins/media';
- import 'tinymce/plugins/table';
- import 'tinymce/plugins/codesample';
- import 'tinymce/plugins/lists';
- import 'tinymce/plugins/advlist';
- import 'tinymce/plugins/hr';
- import 'tinymce/plugins/charmap';
- import 'tinymce/plugins/emoticons';
- import 'tinymce/plugins/anchor';
- import 'tinymce/plugins/directionality';
- import 'tinymce/plugins/pagebreak';
- import 'tinymce/plugins/quickbars';
- import 'tinymce/plugins/nonbreaking';
- import 'tinymce/plugins/visualblocks';
- import 'tinymce/plugins/visualchars';
- import 'tinymce/plugins/wordcount';
- import 'tinymce/plugins/emoticons/js/emojis';
- import {
- DEFAULT_CONFIG,
- DARK_CONFIG,
- uuid,
- bindHandlers,
- openAlert
- } from './util';
- export default {
- name: 'TinymceEditor',
- props: {
- // 编辑器唯一 id
- id: String,
- // v-model
- value: String,
- // 编辑器配置
- init: Object,
- // 是否内联模式
- inline: {
- type: Boolean,
- default: false
- },
- // model events
- modelEvents: {
- type: String,
- default: 'change input undo redo'
- },
- // 内联模式标签名
- tagName: {
- type: String,
- default: 'div'
- },
- // 是否禁用
- disabled: Boolean,
- // 自动跟随框架主题
- autoTheme: {
- type: Boolean,
- default: true
- },
- // 是否使用暗黑主题
- darkTheme: Boolean
- },
- data() {
- return {
- // 编辑器唯一 id
- elementId: this.id || uuid('tiny-vue'),
- // 编辑器实例
- editorIns: null,
- // 是否内联模式
- inlineEditor: this.init?.inline || this.inline
- };
- },
- computed: {
- // 是否是暗黑模式
- darkMode() {
- return this.$store?.state?.theme?.darkMode;
- }
- },
- methods: {
- /* 更新 value */
- updateValue(value) {
- this.$emit('input', value);
- },
- /* 修改内容 */
- setContent(value) {
- if (
- this.editorIns &&
- typeof value === 'string' &&
- value !== this.editorIns.getContent()
- ) {
- this.editorIns.setContent(value);
- }
- },
- /* 渲染编辑器 */
- render() {
- const isDark = this.autoTheme ? this.darkMode : this.darkTheme;
- tinymce.init({
- ...DEFAULT_CONFIG,
- ...(isDark ? DARK_CONFIG : {}),
- ...this.init,
- selector: `#${this.elementId}`,
- readonly: this.disabled,
- inline: this.inlineEditor,
- setup: (editor) => {
- this.editorIns = editor;
- editor.on('init', (e) => {
- // 回显初始值
- if (this.value) {
- this.setContent(this.value);
- }
- // v-model
- editor.on(this.modelEvents, () => {
- this.updateValue(editor.getContent());
- });
- // valid events
- bindHandlers(e, this.$attrs, editor);
- });
- if (typeof this.init?.setup === 'function') {
- this.init.setup(editor);
- }
- }
- });
- },
- /* 销毁编辑器 */
- destory() {
- if (tinymce != null && this.editorIns != null) {
- tinymce.remove(this.editorIns);
- this.editorIns = null;
- }
- },
- /* 弹出提示框 */
- alert(option) {
- openAlert(this.editorIns, option);
- }
- },
- watch: {
- value(val, prevVal) {
- if (val !== prevVal) {
- this.setContent(val);
- }
- },
- disabled(disable) {
- if (this.editorIns !== null) {
- if (typeof this.editorIns.mode?.set === 'function') {
- this.editorIns.mode.set(disable ? 'readonly' : 'design');
- } else {
- this.editorIns.setMode(disable ? 'readonly' : 'design');
- }
- }
- },
- tagName() {
- this.destory();
- this.$nextTick(() => {
- this.render();
- });
- },
- darkMode() {
- if (this.autoTheme) {
- this.destory();
- this.$nextTick(() => {
- this.render();
- });
- }
- }
- },
- mounted() {
- this.render();
- },
- beforeDestroy() {
- this.destory();
- },
- activated() {
- this.render();
- },
- deactivated() {
- this.destory();
- }
- };
- </script>
- <style>
- body .tox-tinymce-aux {
- z-index: 19990000;
- }
- textarea[id^='tiny-vue'] {
- width: 0;
- height: 0;
- margin: 0;
- padding: 0;
- opacity: 0;
- box-sizing: border-box;
- }
- </style>
|