TinyMCE - 在 tinyMCE 中使用七牛上传

tinyMCE 是一个我比较喜欢的 javascript 富文本编辑器,它开源免费并有着清新的 UI。
七牛云 是一个云存储服务,它有开放的 api,可以用来存放很多东西,非常方便。
本文主要讲 tinyMCE 怎么跟 React 和七牛上传结合使用。

背景

React、tinyMCE、Qiniu.js 的结合

遇到一个场景是:需要使用富文本编辑器来编辑文章,为了避免服务器压力,我希望把图片资源放到七牛上面,而项目又恰好使用了 React,
所以就尝试把三者结合起来使用。闲话不多说,直接上代码。

代码

首先要引入 tinyMCE 和 qiniu 的依赖文件:

1
2
3
4
5
6
<script src="moxie.min.js"></script>
<script src="plupload.full.min.js"></script>
<script src="qiniu.min.js"></script>
<script src="tinymce.min.js"></script>
<script src="theme.min.js"></script>
<script src="tinymce_zh_cn.js"></script>

可以使用 script 引入,也可以使用 webpack 导入。
需要注意的是,由于上述文件很多没有使用 commonjs 规范。所以使用 webpack 导入是需要用到export-loader,来使 this 指向 window

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[
... 其他 webpack loader
{
test: require.resolve('tinymce/tinymce'),
loaders: [
'imports?this=>window',
'exports?window.tinymce'
]
},
{
test: /tinymce\/(themes|plugins)\//,
loaders: [
'imports?this=>window'
]
},
{
test: /moxie/,
loaders: [
'imports?this=>window',
'exports?window.mOxie'
]
},
{
test: /plupload/,
loaders: [
'imports?this=>window',
'exports?window.plupload'
]
}
]

其次是组件入口文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// RichEditor.js

import React, { PropTypes } from 'react';
import defer from 'lodash/defer';
import tinymceQiniuPlugin from 'utils/tinymce_qiniu_plugin';


export default class RichEditor extends React.PureComponent {
componentDidMount() {
const { content } = this.props;
tinymceQiniuPlugin(window.tinymce);
window.tinymce.init({
height: 300,
selector: '#tinymce',
skin: false,
plugins: ['imageuploadtoqiniu'],
});
defer(() => window.tinymce.get('tinymce').setContent(content || ''));
}

componentWillUnmount() {
window.tinymce.get('tinymce').remove();
}

render() {
return (
<textarea id="tinymce" />
);
}
}

RichEditor.propTypes = {
content: PropTypes.string,
};

其次是 tinymceQiniuPlugin 文件,用来对接七牛上传:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import { get } from 'utils/request';

export default (tinymce) => {
tinymce.PluginManager.add('imageuploadtoqiniu', (editor) => {
const initUploader = () => {
get('common/qiniu_token/')
.then((res) => res.json())
.then((data) => {
const imgStateEl = document.getElementById('image-state');
const imgUrlEl = document.getElementById('image-url');
window.Qiniu.uploader({
runtimes: 'html5,flash,html4',
browse_button: 'image-pick',
uptoken: data.token,
domain: 'http://xxx.clouddn.com/',
max_retries: 3,
auto_start: true,
init: {
FileUploaded(up, file, info) {
const domain = up.getOption('domain');
const res = JSON.parse(info);
const sourceLink = domain + res.key;
imgStateEl.innerHTML = '上传完成';
imgStateEl.style.display = 'block';
imgUrlEl.value = sourceLink;
},
UploadProgress(up, file) {
if (file.status === window.plupload.UPLOADING) {
imgStateEl.innerHTML = `正在上传${file.percent}%`;
} else {
imgStateEl.innerHTML = '正在上传...';
}
imgStateEl.style.display = 'block';
},
Error() {
imgStateEl.innterHTML = '上传出错,请重试!';
imgStateEl.style.display = 'block';
},
},
});
});
};

const onSubmit = (edit) => {
const src = document.getElementById('image-url').value;
edit.insertContent(`<img src="${src}" />`);
};

const showDialog = (edit) => {
editor.windowManager.open({
title: '上传图片',
body: [{
id: 'image-url',
type: 'textbox',
name: 'url',
label: '图片地址',
}, {
type: 'button',
text: '请选择',
name: 'image-pick',
id: 'image-pick',
}, {
type: 'label',
text: '请输入图片地址或从本地选择上传!',
id: 'image-state',
}],
onsubmit() {
onSubmit(edit);
},
});
initUploader();
};


editor.addButton('image', {
icon: 'image',
tooltip: '插入/删除图片',
onclick() {
showDialog(editor);
},
});

editor.addMenuItem('image', {
icon: 'image',
text: '插入/删除图片',
context: 'insert',
onclick() {
showDialog(editor);
},
prependToContext: true,
});
});
};

使用:

1
<RichEditor content={'some content'} />

截图
tinymce

尾声

总的来说 React、tinyMCE 结合七牛云上传还是折腾蛮久,主要原因是由于七牛上传和 tinyMCE 都不方便用 webpack 打包,需要手工 exportwindow 对象上。
希望有类似使用场景的同学,这篇文章能够帮到你。