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
的配置服務器
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>
複製代碼
string
能夠下拉選擇給圖片加對應class
config = {
image_class_list: [
{ title: '無', value: '' },
{ title: '自適應屏幕寬度', value: 'adaptive-screen-width' }
]
}
複製代碼
false
[true/false]
圖標編輯彈窗多了一個屬性編輯的tab,包含外邊距(margin
),邊框(border
)的編輯。修改後,圖片的style
的屬性值會被覆蓋。
true
[true/false]
對應img
標籤的alt
屬性
true
[true/false]
是否能夠在彈窗中經過input
設置圖片的寬高
此插件會編輯圖片的原始數據。
涉及修改圖片原始數據的操做(如剪裁、翻轉等),須要從新上傳圖片。能夠配合服務端接口從新上傳,也能夠前端間接調用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
圖片上傳鉤子,自動上傳圖片。
這一塊的實現比較複雜,我不貼代碼,只說下大體思路:
paste_postprocess
方法中標註這些外鏈圖片mceInsertContent
),在事件的回調方法中,將這些標註的外鏈圖片進行轉化。須要注意的是,由於一些圖片的提供者會對圖片進行保護,服務器不必定你傳過去的每張圖片都能傳到本身的服務器,須要和後端約定處理方法。
首先,咱們要實現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>
複製代碼