Tinymce6+tinymce-vue5+vue3+ts

相關(guān)包

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

復(fù)制icons、skins

安裝完成后,在 public文件夾 下創(chuàng)建 tinymce文件夾,然后在node_modules下找到 tinymce,注意不是 @tinymce,復(fù)制 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) => {
      //點(diǎn)擊按鈕后執(zhí)行
      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驅(qū)動
  menubar: false, // 是否隱藏頂部菜單
  contextmenu_never_use_native: true, //防止瀏覽器上下文菜單出現(xiàn)在編輯器中
  elementpath: false, //隱藏底欄的元素路徑(隱藏右下角元素顯示)
  object_resizing: true,//是否允許調(diào)整圖像大小.
  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, //此選項(xiàng)指定是否應(yīng)從粘貼的內(nèi)容中刪除圖像
  paste_webkit_styles: 'all', //此選項(xiàng)允許您指定粘貼到 WebKit 中時(shí)要保留的樣式 'none' 或者 'all'
  // paste_merge_formats: true, //此選項(xiàng)在粘貼內(nèi)容時(shí)啟用合并格式功能。這將合并相同的文本格式元素,以減少生成的 HTML 元素的數(shù)量
  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, //此選項(xiàng)允許您禁用對話框中的鏈接輸入字段
  nonbreaking_force_tab: true, //tab鍵插入三個(gè)&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)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容