Tinymce6+tinymce-vue5+vue3+ts

2023-08-30  本文已影响0人  三没产品

相关包

 "tinymce": "^6.3.1"
 "@tinymce/tinymce-vue": "^5.0.0"
 "element-plus": "^2.2.28"

复制icons、skins

安装完成后,在 public文件夹 下创建 tinymce文件夹,然后在node_modules下找到 tinymce,注意不是 @tinymce,复制 icons、skins 文件夹到 public/tinymce6

下载中文语言包

下载地址:https://www.tiny.cloud/get-tiny/language-packages/,下载 zh_CN,下载后,把解压后的 langs文件夹 放到 public/tinymce6

组件代码

<template>
  <div>
    <Editor v-model="myValue" :init="init" :disabled="disabled"/>
    <input type="file" hidden :id="id" :accept="imgAccept"/>
    <div class="oe-editor-del-btn" v-if="showDel">
      <img src="../assets/img/editor_del.png" alt="">
    </div>
  </div>
</template>

<script lang="ts" setup>
import {computed, onMounted, reactive, ref} from "vue"
import tinymce from 'tinymce/tinymce'
import Editor from '@tinymce/tinymce-vue'
import 'tinymce/themes/silver/theme'
import 'tinymce/icons/default'
import 'tinymce/models/dom'
import 'tinymce/plugins/advlist'
import 'tinymce/plugins/autolink'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/link'
import 'tinymce/plugins/image'
import 'tinymce/plugins/charmap'
import 'tinymce/plugins/preview'
import 'tinymce/plugins/anchor'
import 'tinymce/plugins/searchreplace'
import 'tinymce/plugins/visualblocks'
import 'tinymce/plugins/code'
import 'tinymce/plugins/fullscreen'
import 'tinymce/plugins/insertdatetime'
import 'tinymce/plugins/media'
import 'tinymce/plugins/table'
import 'tinymce/plugins/help'
import 'tinymce/plugins/wordcount'
import {editUploadFile} from "../api/common";
import {ElMessage} from "element-plus";

interface Props {
  id?: string,
  modelValue?: string,
  height?: string | number,
  width?: string | number,
  disabled?: boolean,
  showDel?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  modelValue: '',
  id: 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + ''),
  height: 200,
  width: 'auto',
  disabled: false,
  showDel: false
})

const emits = defineEmits<{
  (e: 'update:modelValue', value: string): void
}>()

const myValue = computed({
  get() {
    return props.modelValue
  },
  set(value) {
    emits('update:modelValue', value);
  },
});

const oldValue = ref<string>()
const imgAccept = ref<string>('.bmp,.jpg,.png,.tif,.gif,.pcx,.tga,.exif,.fpx,.svg,.psd,.cdr,.pcd,.dxf,.ufo,.eps,.ai,.raw,.WMF,.webp,.avif,.apng')

const example_image_upload_handler = (blobInfo: any, progress: any) => new Promise((resolve, reject) => {
  let fd = new FormData();
  fd.append('file', blobInfo.blob(), blobInfo.filename());
  editUploadFile(fd).then((res: any) => {
    if (res.code === 1) {
      resolve(res.data)
    } else {
      resolve('')
    }
  })
})

const setup = (editor: any) => {
  editor.ui.registry.addButton('imageUpload', {
    tooltip: '图片',
    icon: 'image',
    onAction: (api: any) => {
      //点击按钮后执行
      oldValue.value = props.modelValue;
      const input: any = document.getElementById(props.id);
      input.click();
      input.onchange = function () {
        let file = input.files[0];
        let fd = new FormData();
        fd.append('file', file);
        if (!imgAccept.value.includes(file.name.substring(file.name.indexOf('.')))) {
          ElMessage.warning('请选择图片上传')
          input.value = '';
          return
        }
        editUploadFile(fd).then((res: any) => {
          if (res.code === 1) {
            editor.insertContent("<img src='" + res.data + "' alt=''/>");
            input.value = '';
          } else {
            editor.setContent(oldValue.value as string);
          }
        })
      }
    }
  });
}

const init = reactive({
  selector: `#${props.id}`,
  content_style: "p {margin: 0; border:0; padding: 0;}",
  content_css: '/tinymce6/skins/content/default/content.css',
  language_url: '/tinymce6/langs/zh-Hans.js', // https://www.tiny.cloud/get-tiny/language-packages/
  language: 'zh-Hans',
  skin_url: '/tinymce6/skins/ui/oxide',
  height: props.height,
  promotion: false, //隐藏右上角upgrade按钮
  branding: false, //隐藏右下角由TINY驱动
  menubar: false, // 是否隐藏顶部菜单
  contextmenu_never_use_native: true, //防止浏览器上下文菜单出现在编辑器中
  elementpath: false, //隐藏底栏的元素路径(隐藏右下角元素显示)
  object_resizing: true,//是否允许调整图像大小.
  toolbar: 'undo redo | blocks | fontfamily forecolor |' +
    'bold italic backcolor | alignleft aligncenter ' +
    'alignright alignjustify | bullist numlist outdent indent | ' +
    'removeformat | table | imageUpload | help',
  plugins: ['advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview',
    'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen',
    'insertdatetime', 'media', 'table', 'help', 'wordcount'],
  // paste_data_images: false, //此选项指定是否应从粘贴的内容中删除图像
  paste_webkit_styles: 'all', //此选项允许您指定粘贴到 WebKit 中时要保留的样式 'none' 或者 'all'
  // paste_merge_formats: true, //此选项在粘贴内容时启用合并格式功能。这将合并相同的文本格式元素,以减少生成的 HTML 元素的数量
  advlist_bullet_styles: 'default,circle,disc,square',
  // advlist_number_styles: 'default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman',
  link_default_target: '_blank',
  link_title: false, //此选项允许您禁用对话框中的链接输入字段
  nonbreaking_force_tab: true, //tab键插入三个&nbsp;
  images_upload_handler: example_image_upload_handler,
  setup: setup
})

onMounted(() => {
  tinymce.init({})
})

</script>

<style scoped>

</style>
<style>
.tox-tinymce-aux {
  z-index: 3035 !important;
}

.tox .tox-toolbar__group {
  padding: 0 3px 0 5px !important;
}
</style>

vue2+tinymce5+tinymce-vue3 - 简书 (jianshu.com)

上一篇 下一篇

猜你喜欢

热点阅读