Vue 自定義富文字編輯器 tinymce 支援匯入 word 模板
自定義富文字編輯器分為前端專案和後端專案兩個部分,首先先說一下前端專案
前端
前端專案地址: https://github.com/haoxiaoyong1014/editor-ui
編輯器名稱: tinymce
前端採用的 vue.js
至於Vue 中怎麼整合 tinymce 編輯器參考: https://segmentfault.com/a/1190000012791569
其中關鍵程式碼在專案中的 index.vue
<template>
<div>
<Row>
<Col span="18" offset="3">
<Card shadow>
<Upload action="http://localhost:2020/upload/word/template"
:on-success="handleSuccess">
<Button icon="ios-cloud-upload-outline">上傳模板</Button>
</Upload>
<Form ref="editorModel" :model="editorModel" :rules="editorRules">
<FormItem prop="content">
<textarea class='tinymce-textarea' id="tinymceEditer" style="height: 800px">
</textarea>
</FormItem>
<FormItem>
<Button type="primary" @click="handleSubmit('editorModel')">Submit</Button>
<Button type="ghost" @click="handleReset('editorModel')">Reset</Button>
</FormItem>
</Form>
<Spin fix v-if="spinShow">
<Icon type="load-c" size=18 class="demo-spin-icon-load"></Icon>
<div>載入元件中...</div>
</Spin>
</Card>
</Col>
</Row>
</div>
</template>
<script>
import tinymce from 'tinymce';
import util from '@/libs/util';
export default {
name: 'index',
data () {
return {
spinShow: true,
editorModel: {
content: 'dfsd'
},
content2: 'sdds',
editorRules: {
content: [
{
type: 'string',
min: 5,
message: 'the username size shall be no less than 5 chars ',
trigger: 'blur'
}
]
},
customEditor: null
};
},
methods: {
handleSuccess(res){
console.log(res)
this.customEditor=res.content;
console.log('haoxy'+this.customEditor)
tinymce.get('tinymceEditer').setContent(this.customEditor);
/*this.$nextTick(() => {
this.customEditor = tinymce.get("tinymceEditer");
})*/
},
init () {
this.$nextTick(() => {
let vm = this;
let height = document.body.offsetHeight - 300;
tinymce.init({
selector: '#tinymceEditer',
branding: false,
elementpath: false,
height: height,
language: 'zh_CN.GB2312',
menubar: 'edit insert view format table tools',
plugins: [
'advlist autolink lists link image charmap print preview hr anchor pagebreak imagetools',
'searchreplace visualblocks visualchars code fullpage',
'insertdatetime media nonbreaking save table contextmenu directionality',
'emoticons paste textcolor colorpicker textpattern imagetools codesample'
],
toolbar1: ' newnote print preview | undo redo | insert | styleselect | forecolor backcolor bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image emoticons media codesample',
autosave_interval: '20s',
image_advtab: true,
table_default_styles: {
width: '100%',
height: '100%',
borderCollapse: 'collapse'
},
setup: function (editor) {
editor.on('init', function (e) {
vm.spinShow = false;
if (localStorage.editorContent) {
tinymce.get('tinymceEditer').setContent(localStorage.editorContent);
}
});
editor.on('keydown', function (e) {
localStorage.editorContent = tinymce.get('tinymceEditer').getContent();
vm.editorModel.content = tinymce.get('tinymceEditer').getContent();
});
}
});
/*this.customEditor = tinymce.get("tinymceEditer");*/
});
},
handleSubmit (name) {
this.$refs[name].validate((valid) => {
if (valid) {
util.post('/html/pdf', this.editorModel).then(res => {
this.$Message.success('Success!');
});
} else {
this.$Message.error('Fail!');
}
});
},
handleReset (name) {
this.$refs[name].resetFields();
},
},
mounted () {
this.init();
},
destroyed () {
tinymce.get('tinymceEditer').destroy();
}
}
</script>
在原有的編輯器的基礎上新增了上傳模板功能, 在上傳成功之後拿到服務端 返回的 html 資料,將其設定到
<textarea class='tinymce-textarea' id="tinymceEditer" style="height: 800px"></textarea>
這個標籤中,所有的編輯器都是這個道理.
上傳成功之後:
handleSuccess(res){
console.log(res)
this.customEditor=res.content;
console.log('haoxy'+this.customEditor)
tinymce.get('tinymceEditer').setContent(this.customEditor);
看下效果圖:
點選 submit 我是在後端將其轉換成了 pdf 檔案(按需求定義)
如果在整合中出現: Uncaught SyntaxError: Unexpected token <
這個錯誤
解決方法:
在 tinymce.init 中把language : zh_CN.GB2312
去掉
在你需要的地方引入: import '../../../zh_CN'
(我是把 zh_CN.js放到了根目錄下了,效果是一樣的),
如果編輯器的樣式還是沒有出來,只出來一個編輯框的話 ,就在你的根目錄下的 index.html 中引入:
<script src="https://cdn.bootcss.com/tinymce/4.7.4/tinymce.min.js"></script>
後端
後端(服務端)專案地址: https://github.com/haoxiaoyong1014/editor-service
後端採用: springBoot , POI
這裡就不對POI做過多的說明了,貼個官網 https://poi.apache.org/,隨意看看。
整體思路:
1,在編輯器原來的基礎上增加上傳模板按鈕
2, 前端上傳 word 模板
3, 服務端接收將 word 轉換為html 返回前端
4, 前端拿到服務端返回的值,將其放到富文字編輯器中
後端主要是第3步
首先搞清楚下要將doc/docx文件轉成html/htm的話要怎麼處理,根據POI的文件,我們可以知道,處理doc 格式檔案對應的 POI API 為 HWPF、docx 格式為 XWPF。此處參考下這篇好文:http://www.open-open.com/lib/view/open1389594797523.html 在格式轉換上說得很清楚。
所以整體就是:根據文件型別,doc我們用HWPF物件處理轉換、docx用XWPF物件處理轉換。
順便貼一下這個線上文件 http://poi.apache.org/apidocs/index.html,不得不說看得相當麻煩,特別是XWPF的。
所需依賴
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.12</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.12</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.document</artifactId>
<version>1.0.5</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>org.apache.poi.xwpf.converter.xhtml</artifactId>
<version>1.0.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons.io/commonsIO -->
<dependency>
<groupId>org.apache.commons.io</groupId>
<artifactId>commonsIO</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>com.aspose.words</groupId>
<artifactId>aspose-words</artifactId>
<version>15.8.0</version>
</dependency>
其中 commonsIO 這個依賴不知道為什麼下載不下來,我將 jar 放到了我的私服上,在pom.xml 中有體現,這裡不做詳細說明
一、處理doc。
這個相對簡單,網上一查一堆,我的程式碼也是根據網上的做下自己的優化和邏輯。
因為POI很早前就可以支援doc的處理,所以資料比較多。
思路就是:HWPFDocument物件例項化檔案流 -> WordToHtmlConverter物件處理HWPFDocument物件及預處理頁面的圖片等(主要是圖片)
文件說明是:
Converts Word files (95-2007) into HTML files.
This implementation doesn’t create images or links to them. This can be changed by overriding AbstractWordConverter.processImage(Element, boolean, Picture) method.
-> org.w3c.dom.Document物件處理WordToHtmlConverter,生成DOM物件 -> 輸出檔案。
這裡有個好處就是使用到了Document物件,從而解決了編碼、檔案格式等問題。
這裡因為過程簡單,直接貼簡單demo,看註釋即可:
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.io.FileUtils;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.converter.PicturesManager;
import org.apache.poi.hwpf.converter.WordToHtmlConverter;
import org.apache.poi.hwpf.usermodel.Picture;
import org.apache.poi.hwpf.usermodel.PictureType;
import org.apache.poi.xwpf.converter.core.FileImageExtractor;
import org.apache.poi.xwpf.converter.core.FileURIResolver;
import org.apache.poi.xwpf.converter.xhtml.XHTMLConverter;
import org.apache.poi.xwpf.converter.xhtml.XHTMLOptions;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
import org.w3c.dom.Document;
public class POIForeViewUtil {
public void parseDocx2Html() throws Throwable {
final String path = "/tmp/";
final String file = "xxxxxxx.doc";
InputStream input = new FileInputStream(path + file);
String suffix = file.substring(file.indexOf(".")+1);// //擷取檔案格式名
//例項化WordToHtmlConverter,為圖片等資原始檔做準備
WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(
DocumentBuilderFactory.newInstance().newDocumentBuilder()
.newDocument());
wordToHtmlConverter.setPicturesManager(new PicturesManager() {
public String savePicture(byte[] content, PictureType pictureType,
String suggestedName, float widthInches, float heightInches) {
return suggestedName;
}
});
if ("doc".equals(suffix.toLowerCase())) {
// doc
HWPFDocument wordDocument = new HWPFDocument(input);
wordToHtmlConverter.processDocument(wordDocument);
//處理圖片,會在同目錄下生成並儲存圖片
List pics = wordDocument.getPicturesTable().getAllPictures();
if (pics != null) {
for (int i = 0; i < pics.size(); i++) {
Picture pic = (Picture) pics.get(i);
try {
pic.writeImageContent(new FileOutputStream(path
+ pic.suggestFullFileName()));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
// 轉換
Document htmlDocument = wordToHtmlConverter.getDocument();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
DOMSource domSource = new DOMSource(htmlDocument);
StreamResult streamResult = new StreamResult(outStream);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer serializer = tf.newTransformer();
serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");//編碼格式
serializer.setOutputProperty(OutputKeys.INDENT, "yes");//是否用空白分割
serializer.setOutputProperty(OutputKeys.METHOD, "html");//輸出型別
serializer.transform(domSource, streamResult);
outStream.close();
String content = new String(outStream.toByteArray());
//我此時不想讓它生成檔案,所以我註釋掉了,按需求定
/*FileUtils.writeStringToFile(new File(path, "interface.html"), content,
"utf-8");*/
}
public static void main(String[] args) throws Throwable {
new POIForeViewUtil().parseDocx2Html();
}
}
其中 content 就是我們想要的 HTML 資料
接下來我看第二中 docx
二、處理docx。
docx是07的版本,處理起來困難的多,貌似POI對docx的處理方法沒有doc那麼便捷,處理樣式等等都有問題,我遇到的兩個最明顯問題就是字型編碼問題和表格的邊框線顯示。
思路:XWPFDocument載入檔案流 -> XHTMLOptions處理頁面資源(主要圖片) -> OutputStream輸出流直接輸出檔案。
過程程式碼相當簡單,可是越簡單結果約沒有預期的好。輸出的檔案字型編碼預設為GBK,例如我的“微軟雅黑”字型就變成“寰蔣闆呴粦”,而且節點的顯示也沒有doc處理的好。
同樣貼一下demo程式碼:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import org.apache.poi.xwpf.converter.core.FileImageExtractor;
import org.apache.poi.xwpf.converter.core.FileURIResolver;
import org.apache.poi.xwpf.converter.xhtml.XHTMLConverter;
import org.apache.poi.xwpf.converter.xhtml.XHTMLOptions;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
public class Word07ToHtml {
public static void parseToHtml() throws IOException {
File f = new File("tmp/xxxxx.docx");
if (!f.exists()) {
System.out.println("Sorry File does not Exists!");
} else {
if (f.getName().endsWith(".docx") || f.getName().endsWith(".DOCX")) {
// 1) 載入XWPFDocument及檔案
InputStream in = new FileInputStream(f);
XWPFDocument document = new XWPFDocument(in);
// 2) 例項化XHTML內容(這裡將會把圖片等檔案放到生成的"word/media"目錄)
File imageFolderFile = new File("f:/opt");
XHTMLOptions options = XHTMLOptions.create().URIResolver(
new FileURIResolver(imageFolderFile));
options.setExtractor(new FileImageExtractor(imageFolderFile));
//options.setIgnoreStylesIfUnused(false);
//options.setFragment(true);
// 3) 將XWPFDocument轉成XHTML並生成檔案 --> 我此時不想讓它生成檔案,所以我註釋掉了,按需求定
/*OutputStream out = new FileOutputStream(new File(
path, "result.html"));
XHTMLConverter.getInstance().convert(document, out, null);*/
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XHTMLConverter.getInstance().convert(document, baos, options);
String content = baos.toString();
baos.close();
} else {
System.out.println("Enter only MS Office 2007+ files");
}
}
}
}
其中 content 就是我們想要的 HTML 資料
點選 submit 我是在後端將其轉換成了 pdf 檔案(按需求定義)
POI的jar包下載路徑:https://archive.apache.org/dist/poi/release/bin/poi-bin-3.9-20121203.zip
至此 富文字編輯器增加匯入 word 模板就結束了, 無論是匯入檔案還匯入圖片都是一個道理.
注: 前端專案使用方式
git clone https://github.com/haoxiaoyong1014/editor-ui.git
進入專案執行:
npm install
npm run dev
前提: 需要安裝 npm
前端專案地址: https://github.com/haoxiaoyong1014/editor-ui
後端專案地址: https://github.com/haoxiaoyong1014/editor-service
如果對您有幫助還請給個星星哦!
2018/10/19更新,更新內容修復 bug
放到專案中遇到的問題修復
- 問題描述1:
當上傳模板之後點選瀏覽器重新整理編輯框中的內容會變為之前上傳的內容
- 解決方法:
if (localStorage.editorContent) {
tinymce.get('tinymceEditer').setContent(localStorage.editorContent);
}
將這段程式碼註釋掉即可,因為編輯器會自動的將內容儲存到本地,當你去點選瀏覽器重新整理的時候他會去本地取出並賦值到編輯框中
- 問題描述2:
當你在編輯框中進行編輯的時候tinymce編輯器監聽了鍵盤按下的事件,但是鍵盤按下的前一個字元沒有儲存,例如:
你在編輯框中輸入4個字元 aaaa
你再點選submit生成pdf檔案,但是 pdf檔案中就只有3個字元aaa
- 解決方法:
因為編輯器只監聽了keydown
事件,並沒有去監聽keyup
事件
所以加上如下程式碼即可
editor.on('keyup', function (e) {
localStorage.editorContent = tinymce.get('tinymceEditer').getContent();
vm.editorModel.content = tinymce.get('tinymceEditer').getContent();
});
- 問題描述3:
當點選submit 生成pdf檔案時,生成的 pdf 檔案樣式改變了
- 解決方法:
這是因為將 word 文件轉換成 html 的時候自動的加上了這段樣式
<div style="width: 595.0pt; margin: 72.0pt 90.0pt 72.0pt 90.0pt;"></div>
解決方法可以在前端解決也可以在後端去解決,這裡我選擇了在後端解決
後端在返回給前端html 的時候,在返回的內容上加上
respInfo.setContent("<div style=\"width: 595.0pt; margin: -72.0pt -90.0pt -72.0pt -90.0pt !important;\">"+content+"</div>")
總結何嘗不是一種學習
相關文章
- Vue-Cli 3+tinymce 5 富文字編輯器整合Vue
- Tinymce - 宇宙第一富文字編輯器?[1]
- Tinymce - 宇宙第一富文字編輯器?[2]
- Tinymce - 宇宙第一富文字編輯器?[3]
- quill 富文字編輯器自定義格式化UI
- 【前端】vue引入tinymce富文字編輯器上傳影片自動轉img問題前端Vue
- vue 富文字編輯器 vue-quill-editorVueUI
- vue專案獲取富文字編輯器wangEditor內容匯出為word(html轉word格式並下載)VueHTML
- 九、Vue+Element使用富文字編輯器Vue
- vue如何使用富文字編輯器wangEditor自定義圖片上傳(解決跨域問題)Vue跨域
- 自定義 Word 模板
- SpringMVC整合富文字編輯器SpringMVC
- 富文字編輯器 VUE-QUILL-EDITOR 使用教程 (最全)VueUI
- Element UI 整合富文字編輯器 vue-quill-editorUIVue
- 分享 - 富文字編輯器 Froala Editor
- SSM使用UEditor富文字編輯器SSM
- 線上富文字編輯器初探
- 半成品md富文字編輯器
- [Djangorestframework]-富文字編輯器的使用DjangoRESTFramework
- [phpword][laravel-admin]匯入文件轉html,並使用富文字編輯後匯出PHPLaravelHTML
- 一個富文字編輯器quill 以Vue專案為例UIVue
- 深入淺出contenteditable富文字編輯器
- Eleditor移動端富文字編輯器
- Django後臺管理配置富文字編輯器Django
- 在VueJS中使用 froala 富文字編輯器VueJS
- HTML 頁面使用 wangeditor 富文字編輯器HTML
- vue中正確使用富文字編輯器wangeditor和使用wangeditor遇到的坑Vue
- Vue富文字帶圖片修改圖片大小自定義選擇項自定義字型Vue自定義字型
- 幾種開源富文字編輯器對比
- iOS使用UITableView實現的富文字編輯器iOSUIView
- 富文字及編輯器的跨平臺方案
- 淺析富文字編輯器框架Slate.js框架JS
- 關於專案中使用的富文字編輯器markdown和傳統的富文字編輯器的對比和選擇
- 富文字編輯器:UEditor與wangEditor 初使用總結
- 各種富文字/ HTML編輯器和框架比較HTML框架
- 一個百度富文字編輯器的坑
- 富文字編輯器之遊戲角色升級ing遊戲
- 可以自定義編輯和渲染的Vue-MarkdownVue