实现功能:
- 在线预览word文档(oss在线地址转blob对象预览)
- 根据选项或输入内容在线更改word对应的字段(包含多个匹配)
- 每次更改跳转到第一个匹配的地方(居中显示并且高亮显示)
实现效果:
实现思路:
word文档中需要根据用户控制的需要每一个配置一个独有代码如合同编号为${HTBH},初始化的时候我们可以先把word加载出来,等dom加载完毕我们在每一个含有${}符号的dom上增加一个独有类,这样我们就可以通过js的dom查询查找用户改变的dom,并在dom上进行处理替换文本显示值,跳转到可视区域中心显示,记录每次key增加样式高亮显示并移除上一次的高亮样式。
具体实现过程:
使用了docx-preview插件,也可以去看看预览demo
我这里是vue实现的,首先引入插件
npm i docx-preview --save
实现代码:
<div class="docWrap">
<div ref="wordFile"></div>
</div>
activedKey: null, //当前高亮选项key
//初始化word文档
initDocx() {
const that = this
const xhr = new XMLHttpRequest();
//oss文件地址转blob 如果是后端返回文件流可以不转
let url = this.contract.template_link
xhr.open("get", url);
xhr.responseType = "blob";
xhr.onload = function() {
const blob = new window.Blob([xhr.response], { type: 'application/docx' }); //转换后blob文件
docx.renderAsync(blob, that.$refs.wordFile).then((x) => {
const elements = that.$refs.wordFile.getElementsByTagName('span')
for (let index = 0; index < elements.length; index++) {
const item = elements[index];
//匹配带有${}的元素
var reg = /\$\{(.+?)\}/;
var reg_g = /\$\{(.+?)\}/g;
let result = item.innerHTML.match(reg_g);
if(result && result.length>0){
for (var i = 0; i < result.length; i++) {
let items = result[i]
//添加独有的类 如visualize-HTBH
item.classList.add('visualize-' + items.match(reg)[1])
}
}
}
})
};
xhr.send();
},
/**
* 选项变化回调
* @param {String} val 改变后的值
* @param {String} key 每项对应的key如HTBH
* @param {String} type 选项类型 如下拉 输入框 日期等
*/
optionChange(val, key, type) {
const that = this
let value = val
if(type == 'select') {
value = val && val.length > 0 ? val.join(',') : ''
}
//找到对应的dom
let dom = that.$refs.wordFile.getElementsByClassName("visualize-" + key);
let arrayDom = Array.from(dom)
if(arrayDom && arrayDom.length > 0) {
if(this.activedKey) { //上一个高亮显示选项key的类值
//查找上一个高亮dom
let aDom = that.$refs.wordFile.getElementsByClassName(this.activedKey);
let arrayADom = Array.from(aDom)
if(arrayADom && arrayADom.length > 0) {
arrayADom.forEach(item => {
//移除所有上一个高亮显示的样式
item.classList.remove("actived-color");
});
}
}
//存储当前高亮显示选项key的类值以便下次查找
this.activedKey = "visualize-" + key
//屏幕滚动到第一个匹配的dom
arrayDom[0].scrollIntoView();
arrayDom.forEach(item => {
//替换内容
item.innerHTML = value
});
}
},
.actived-color {
background-color: rgba(10, 224, 8, .1);
}