Tinymce - 宇宙第一富文本编辑器?[2]

图片

tinymce 提供了丰富的图片上传、管理、修改功能。只须要配置对应插件及一些参数便可。javascript

图片上传

引用image插件,添加images_upload_handler配置项,图片弹窗左侧导航会多一个上传的选项,在点击以后便可完成咱们经常使用的图片上传功能php

<template>
	<div class="default-tinymce">
		<textarea id="editor"></textarea>
	</div>
</template>
<script> import Tinymce from 'tinymce' import Upload from 'src/utils/upload' export default { name: 'DefaultTinymce', mounted () { this.upload = new Upload() let self = this Tinymce.init({ selector: '#editor', plugins: 'image', async images_upload_handler (blobInfo, success, fail) { const file = blobInfo.blob() try { const url = self.YB.businessURL(await self.upload.post(file)) success(url) } catch (e) { fail(e.message || '上传失败,请重试') } } }) } } </script>

复制代码

图片管理

tinymce提供了相似我的图库和公共图库的功能。使用起来也很方便,只要配置便可。html

这个咱们暂时没有这个需求,之后可能会用到。前端

一种是下拉选择,配置image_list便可,值得注意的是,它的值能够是数组,函数,或者接口。java

tinymce.init({
  selector: "textarea",  // change this value according to your HTML
  plugins: "image",
  image_list: [
    {title: 'Dog', value: 'mydog.jpg'},
    {title: 'Cat', value: 'mycat.gif'}
  ]
});

tinymce.init({
  selector: "textarea",  // change this value according to your HTML
  plugins: "image",
  image_list: "/mylist.php"
});

tinymce.init({
  selector: "textarea",  // change this value according to your HTML
  plugins: "image",
  image_list: function(success) {
    success([
      {title: 'Dog', value: 'mydog.jpg'},
      {title: 'Cat', value: 'mycat.gif'}
    ]);
  }
});
复制代码

另外一种是提供了一个按钮,点击这个按钮会触发相应的方法file_picker_callback,方法的参数中有回调函数,咱们能够利用这个方法作一个我的图库。canvas

tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  file_picker_callback: function(callback, value, meta) {
    // 如下是伪代码
    // 打开一个弹窗
    openDialog()  
    // 展现图片列表
    showImageList()
    // 选择图片,确认选择
    const url = submitActiveImage()
    // 关闭弹窗,返回图片
    callback(url)
  }
});
复制代码

图片编辑

图片编辑分为两部分,后端

一部分是对图片属性的编辑,好比边框、边距、宽度等,这部分其实就是对插件image的配置;数组

一部分是对图片自身的编辑,好比剪裁、调色等。这部分是基于插件image Tools的配置服务器

image

image_caption
  • 默认值 false
  • 可能值 [true/false]

图片下方增长对图片的描述文字。开启后,会在弹窗面板多一个显示标题的可选项。cors

config = {
  image_caption: true
}
复制代码

这会生成新的结构

<figure class="image" contenteditable="false" data-mce-selected="1">
    <img src="https://imgtest.120yibao.com/test/base/obu1oj9a5fhy4ftku49.jpeg" alt="sdf" width="650" height="639">
    <figcaption contenteditable="true">图片底部</figcaption>
</figure>
复制代码
image_class_list
  • 值类型 string

能够下拉选择给图片加对应class

config = {
  image_class_list: [
    { title: '无', value: '' },
    { title: '自适应屏幕宽度', value: 'adaptive-screen-width' }
  ]
}

复制代码
image_advtab
  • 默认值 false
  • 可能值 [true/false]

图标编辑弹窗多了一个属性编辑的tab,包含外边距(margin),边框(border)的编辑。修改后,图片的style的属性值会被覆盖。

image_description
  • 默认值 true
  • 可能值 [true/false]

对应img标签的alt属性

image_dimensions
  • 默认值 true
  • 可能值 [true/false]

是否能够在弹窗中经过input设置图片的宽高

image Tools

此插件会编辑图片的原始数据。

编辑后自动上传

涉及修改图片原始数据的操做(如剪裁、翻转等),须要从新上传图片。能够配合服务端接口从新上传,也能够前端间接调用images_upload_handler方法进行上传。

咱们看一下前端上传

function handleImageUrlToBlob (url, callback) {
   function imageToCanvas (src, cb) {
     const canvas = document.createElement('canvas')
     const ctx = canvas.getContext('2d')
     const img = new Image()
     img.src = src + '?t=2'
     img.crossOrigin = ''
     img.onload = function () {
       canvas.width = img.width
       canvas.height = img.height
       ctx.drawImage(img, 0, 0)
       cb(canvas)
     }
   }

   function dataURLToBlob (dataURL) {
     const arr = dataURL.split(',')
     const mime = arr[0].match(/:(.*?);/)[1]
     const bStr = atob(arr[1])
     let n = bStr.length
     const u8arr = new Uint8Array(n)
     while (n--) {
       u8arr[n] = bStr.charCodeAt(n)
     }
     return new Blob([u8arr], { type: mime })
   }

   function canvasToDataURL (canvas, format, quality) {
     return canvas.toDataURL(format || 'image/jpeg', quality || 1.0)
   }

   imageToCanvas(url, function (canvas) {
     callback(dataURLToBlob(canvasToDataURL(canvas)))
   })
 }

tinymce.init({
  // 此两项在使用imagetools插件时必填,只在使用服务端上传时有用。但前端使用了其余方法获取图片(imagetools_fetch_image),因此随便写了些值
  imagetools_cors_hosts: [],
  imagetools_proxy: 'just a string and do nothing',
  // 修改图片以后,获取图片
  imagetools_fetch_image: image => {
    return new tinymce.util.Promise(function (resolve) {
      // 须要将图片转为blob格式
      handleImageUrlToBlob(image.src, resolve)
    })
  },
})

复制代码

修改完图片以后,编辑器会在图片失去焦点以后自动上传图片,并生成新的URL替换掉以前的。

编辑功能列表配置

imagetools_toolbar可配置编辑功能列表

tinymce.init({
  selector: "textarea",  
  toolbar: "image",
  plugins: "image imagetools",
  imagetools_toolbar: "rotateleft rotateright | flipv fliph | editimage imageoptions"
});
复制代码

格式化

有时候你须要对内容进行一些格式化,例如改变字体大小、将内容转换为标题,或者直接清除选择内容的全部样式。这不须要引入插件,至于要配置便可。

tinymce.init({
  selector: "textarea",  
  /** * 「块」样式格式化 */
  block_formats: '段落=p; 标题 1=h1; 标题 2=h2; 标题 3=h3; 标题 4=h4; 标题 5=h5; 标题 6=h6;',

  /** * 工具栏「段落」下拉组件的默认值 */
  style_formats: [
      { title: 'Headings',
        items: [
          { title: 'Heading 1', format: 'h1' },
          { title: 'Heading 2', format: 'h2' },
          { title: 'Heading 3', format: 'h3' },
          { title: 'Heading 4', format: 'h4' },
          { title: 'Heading 5', format: 'h5' },
          { title: 'Heading 6', format: 'h6' }
        ] },
      { title: 'Inline',
        items: [
          { title: 'Bold', format: 'bold' },
          { title: 'Italic', format: 'italic' },
          { title: 'Underline', format: 'underline' },
          { title: 'Strikethrough', format: 'strikethrough' },
          { title: 'Superscript', format: 'superscript' },
          { title: 'Subscript', format: 'subscript' },
          { title: 'Code', format: 'code' }
        ] },
      { title: 'Blocks',
        items: [
          { title: 'Paragraph', format: 'p' },
          { title: 'Blockquote', format: 'blockquote' },
          { title: 'Div', format: 'div' },
          { title: 'Pre', format: 'pre' }
        ] },
      { title: 'Align',
        items: [
          { title: 'Left', format: 'alignleft' },
          { title: 'Center', format: 'aligncenter' },
          { title: 'Right', format: 'alignright' },
          { title: 'Justify', format: 'alignjustify' }
        ] }
    ],
  /** * 字体大小可选列表 */
  fontsize_formats: '12px 14px 16px 18px 24px 36px 48px',
  /** * 格式化 */
  formats: {
    // 清除格式
    removeformat: [
      {
        selector: 'b,strong,em,i,font,u,strike,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins',
        remove: 'all',
        split: true,
        block_expand: true,
        expand: false,
        deep: true
      },
      {
        selector: 'span',
        attributes: ['style', 'class'],
        remove: 'empty',
        split: true,
        expand: false,
        deep: true },
      {
        selector: '*',
        attributes: ['style', 'class'],
        split: false,
        expand: false,
        deep: true
      }
    ]
  }
});
复制代码

转换外链图片

若是粘贴过来的内容中有图片,而且图片是外链图片。可能须要把这些外链图片转换成本身服务器的地址,这须要后端配合:给后端这些图片的url,后端返回给你本身的url,由后端完成图片上传。

若是粘贴内容中的图片是base64,会自动触发以前配置的images_upload_handler图片上传钩子,自动上传图片。

这一块的实现比较复杂,我不贴代码,只说下大体思路:

  1. paste_postprocess方法中标注这些外链图片
  2. 而后监听编辑器的内容插入事件(mceInsertContent),在事件的回调方法中,将这些标注的外链图片进行转化。

须要注意的是,由于一些图片的提供者会对图片进行保护,服务器不必定你传过去的每张图片都能传到本身的服务器,须要和后端约定处理方法。

封装成Vue组件

首先,咱们要实现Vue的双向绑定:在编辑器内容改变的时候,更新ViewModel;ViewModel改变的时候,更新编辑器的内容。

实现起来很简单,咱们能够监听能够改变编辑器内容的事情,以及使用vm.$watch监听值的变化。

<template>
	<div class="editor-wrap">
		<textarea v-model="value" class="editor-textarea"></textarea>
	</div>
</template>
<script> export default { name: 'TinymceEditor', model: { prop: 'value', event: 'change' }, props: { value: { type: String, required: true, default: '' } }, async mounted () { try { const self = this const editor = await Tinymce.init({ selector: '.editor-textarea', // 编辑器实例初始化完成的回调 init_instance_callback: editor => { // 数据双向绑定 self.$nextTick(() => { let currentContent = '' // 双向绑定数据 self.$watch('value', (val, prevVal) => { if (editor && typeof val === 'string' && val !== currentContent && val !== prevVal) { editor.setContent(val) currentContent = val } }) editor.on('change keyup undo redo', () => { currentContent = editor.getContent() self.$emit('change', currentContent) }) }) } }) this.editor = editor[0] } catch (e) { this.$error(e) } } } </script>

复制代码

下一篇:Tinymce - 宇宙第一富文本编辑器?[3]

参考

  1. tinymce官方文档
相关文章
相关标签/搜索