vue项目中引入tinymce4

本文介绍如何在Vue项目中集成TinyMCE富文本编辑器,包括安装步骤、配置选项、图片上传处理及代码示例。通过详细指南,帮助开发者快速掌握TinyMCE的使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上个项目用没记录,这次捣鼓了半天,赶紧拿小本本记下来~

ps:只实现了基本功能,图片上传有点问题,还得捣鼓捣鼓,捣鼓出来了再更新~

  1. 安装:

    npm install @tinymce/tinymce-vue -S
    npm install tinymce -S
  2. 安装之后,在 node_modules 中找到 tinymce/skins目录,然后将 skins 目录拷贝到 static 目录下,下载zh_CN.js文件也放在static/tinymce/

  3. 修改index.html文件:

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1.0">
        <title>graduation-project</title>
        <script src="https://cdn.bootcss.com/tinymce/4.8.4/tinymce.min.js"></script>
      </head>
      <body>
        <div id="app"></div>
        <!-- built files will be auto injected -->
      </body>
    </html>
    
  4. Editor.vue文件

    <template>
      <div style="margin: 20px auto; padding-top:20px;width: 80%;">
        <textarea :id="Id" :value="value"></textarea>
        <el-button @click="getContent">获取内容</el-button>
      </div>
    </template>
    <script>
      require('../../../static/tinymce/zh_CN.js') // 根据自己的组件路径修改
      export default {
        data () {
          const Id = Date.now()
          return {
            Id: Id,
            Editor: null,
            DefaultConfig: {
              // GLOBAL
              height: 900,
              theme: 'modern',
              menubar: false,
              toolbar: `styleselect | fontselect | formatselect | fontsizeselect | forecolor backcolor | bold italic underline strikethrough | image  media | table | alignleft aligncenter alignright alignjustify | outdent indent | numlist bullist | preview removeformat  hr | paste code  link | undo redo | fullscreen `,
              plugins: `
                paste
                importcss
                image
                code
                table
                advlist
                fullscreen
                link
                media
                lists
                textcolor
                colorpicker
                hr
                preview
              `,
              // CONFIG
    
              forced_root_block: 'p',
              force_p_newlines: true,
              importcss_append: true,
    
            // CONFIG: ContentStyle 这块很重要, 在最后呈现的页面也要写入这个基本样式保证前后一致, `table`和`img`的问题基本就靠这个来填坑了
              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; }
              `,
              images_upload_url: 'https://sm.ms/api/upload',
              images_upload_base_path: '',
              insert_button_items: 'image link | inserttable',
    
              // CONFIG: Paste
              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,
    
              // CONFIG: Font
              fontsize_formats: '10px 11px 12px 14px 16px 18px 20px 24px',
    
              // CONFIG: StyleSelect
              style_formats: [
                {
                  title: '首行缩进',
                  block: 'p',
                  styles: { 'text-indent': '2em' }
                },
                {
                  title: '行高',
                  items: [
                    {title: '1', styles: { 'line-height': '1' }, inline: 'span'},
                    {title: '1.5', styles: { 'line-height': '1.5' }, inline: 'span'},
                    {title: '2', styles: { 'line-height': '2' }, inline: 'span'},
                    {title: '2.5', styles: { 'line-height': '2.5' }, inline: 'span'},
                    {title: '3', styles: { 'line-height': '3' }, inline: 'span'}
                  ]
                }
              ],
    
              // FontSelect
              font_formats: `
                微软雅黑=微软雅黑;
                宋体=宋体;
                黑体=黑体;
                仿宋=仿宋;
                楷体=楷体;
                隶书=隶书;
                幼圆=幼圆;
                Andale Mono=andale mono,times;
                Arial=arial, helvetica,
                sans-serif;
                Arial Black=arial black, avant garde;
                Book Antiqua=book antiqua,palatino;
                Comic Sans MS=comic sans ms,sans-serif;
                Courier New=courier new,courier;
                Georgia=georgia,palatino;
                Helvetica=helvetica;
                Impact=impact,chicago;
                Symbol=symbol;
                Tahoma=tahoma,arial,helvetica,sans-serif;
                Terminal=terminal,monaco;
                Times New Roman=times new roman,times;
                Trebuchet MS=trebuchet ms,geneva;
                Verdana=verdana,geneva;
                Webdings=webdings;
                Wingdings=wingdings,zapf dingbats`,
    
              // Tab
              tabfocus_elements: ':prev,:next',
              object_resizing: true,
    
              // Image
              imagetools_toolbar: 'rotateleft rotateright | flipv fliph | editimage imageoptions'
            }
          }
        },
        props: {
          value: {
            default: '',
            type: String
          },
          config: {
            type: Object,
            default: () => {
              return {
                theme: 'modern',
                height: 600
              }
            }
          },
          url: {
            default: '',
            type: String
          },
          accept: {
            default: 'image/jpeg, image/png',
            type: String
          },
          maxSize: {
            default: 2097152,
            type: Number
          },
          withCredentials: {
            default: false,
            type: Boolean
          }
        },
         headers: {
         'Content-type': 'application/json;charset=UTF-8'
          },
        mounted () {
          this.init()
        },
        beforeDestroy () {
          // 销毁tinymce
          this.$emit('on-destroy')
          window.tinymce.remove(document.getElementById(`{this.Id}`))
        },
    
        methods: {
          // 上传主图
          myFunction (){
            var x=document.getElementById("mainfile")
            var f= document.getElementById("mainfile").files[0]
            var formData=new FormData()
            var xmlhttp
            var self = this
            if (window.XMLHttpRequest)
            {
              //  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
              xmlhttp=new XMLHttpRequest()
            }
            else
            {
              // IE6, IE5 浏览器执行代码
              xmlhttp=new ActiveXObject("Microsoft.XMLHTTP")
            }
            xmlhttp.onreadystatechange=function()
            {
              if (xmlhttp.readyState==4 && xmlhttp.status==200)
              {
                self.sproduct.pictures=JSON.parse(xmlhttp.responseText).data.url
              }
            }
            formData.append('smfile',f)
            xmlhttp.open('POST', 'https://sm.ms/api/upload',false)
            xmlhttp.send(formData)
          },
           init () {
             const self = this
    
            this.Editor = window.tinymce.init({
              // 默认配置
              ...this.DefaultConfig,
              // 图片上传
              images_upload_handler: function (blobInfo, success, failure) {
                if (blobInfo.blob().size > self.maxSize) {
                  failure('文件体积过大')
                }
    
                if (self.accept.indexOf(blobInfo.blob().type) >= 0) {
                  uploadPic()
                } else {
                  failure('图片格式错误')
                }
                function uploadPic () {
                  const xhr = new XMLHttpRequest()
                  const formData = new FormData()
                  formData.append('smfile', blobInfo.blob())
                  xhr.open('POST', 'https://sm.ms/api/upload')
                  xhr.onload = function () {
    
                    if (xhr.status !== 200) {
                      // 抛出 'on-upload-fail' 钩子
                      self.$emit('on-upload-fail')
                      failure('上传失败: ' + xhr.status)
                      return
                    }
    
                    const json = JSON.parse(xhr.responseText)
                    // 抛出 'on-upload-complete' 钩子
                    console.log(json.data.url)
                    self.$emit('on-upload-complete' , [
                      json.data, success, failure
                    ])
                     success(json.data.url)
                  }
                  formData.append('smfile', blobInfo.blob())
                  xhr.send(formData)
                }
              },
    
              // prop内传入的的config
              ...this.config,
    
              // 挂载的DOM对象
              selector: `#${this.Id}`,
              setup: (editor) => {
                // 抛出 'on-ready' 事件钩子
                editor.on(
                  'init', () => {
                    self.loading = false
                    self.$emit('on-ready')
                    editor.setContent(self.value)
                  }
                )
                // 抛出 'input' 事件钩子,同步value数据
                editor.on(
                  'input change undo redo', () => {
                    self.$emit('input', editor.getContent())
                  }
                )
              }
            })
          },
          getContent () {
            console.log(tinymce.editors[0].getContent())
          }
        }
      }
    </script>
    

    参考链接:

https://www.cnblogs.com/wisewrong/p/8985471.html

http://tinymce.ax-z.cn/advanced/some-example.php

对于 Vue 项目引入 tinymce 富文本编辑器,我们需要先在项目中安装 tinymce 的依赖包,可以通过 npm 指令进行安装。安装成功后,我们需要在组件中引入并初始化 tinymce 编辑器。 首先,我们需要在组件中引入 tinymce,可以通过 `import 'tinymce/tinymce'` 和 `import 'tinymce/themes/silver'` 来引入 tinymce 核心文件和主题文件。然后,我们在组件的 `mounted()` 生命周期函数中进行 tinymce 编辑器的初始化。如下所示: ``` <template> <div> <textarea id="editor"></textarea> </div> </template> <script> import 'tinymce/tinymce' import 'tinymce/themes/silver' export default { mounted() { tinymce.init({ selector: '#editor', height: 500, plugins: [ 'paste', 'table', 'advlist' ], toolbar: 'undo redo | styleselect | bold italic | alignleft aligncenter alignright | bullist numlist outdent indent | table | code | preview' }) } } </script> ``` 在初始化过程中,我们需要指定要初始化的 HTML 元素的选择器 `selector`,这里是 `'#editor'`,然后可以进行一系列的配置,包括高度、插件、工具栏等,具体可以参考官方文档。 需要注意的是,在组件销毁时我们需要进行 tinymce 编辑器的销毁,可以在 `beforeDestroy()` 生命周期函数中进行编写。如下所示: ``` <script> import 'tinymce/tinymce' import 'tinymce/themes/silver' export default { data() { return { tinymceInstance: null } }, mounted() { this.tinymceInstance = tinymce.init({ selector: '#editor', ... }) }, beforeDestroy() { tinymce.remove(this.tinymceInstance) } } </script> ``` 以上就是 Vue 项目引入 tinymce 富文本编辑器的一个基本流程,可以根据自己的需求进行相应的配置调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值