https://www.cnblogs.com/lovelgx/articles/11613560.html
vue 打印 前台用戶自己設計模版 打印報表實現記錄
一 需求
公司產品由cs轉向bs,我前端使用vue技術棧 ,具體的難點
1.在vue的基礎上讓用戶自己設計模版
2.設計的模版 與 后台請求的數據相結合
3.打印
二 功能實現
2.1 先說打印
問百度 web打印 出來的 基本是兩種方案 ,一是 js插件 二是 lodop 控件實現web打印功能
注: lodop 控件 需要下載一個程序。對於我們客戶來說或許有些麻煩 那就選js插件吧 lodop 官網 : http://www.mtsoftware.cn/LodopDemo.html 實現方式 百度好多 略過!!!
問百度 vue 項目實現打印 也是兩種方式
一是:通過npm 安裝插件
二是:手動下載插件到本地
擴展:詳細說下 npm安裝方式
//1.安裝 npm install vue-print-nb --save //2 main.js文件中引入 import Print from 'vue-print-nb' Vue.use(Print); //注冊 //3.使用 <div id="printTest" > <p>鋤禾日當午</p> <p>汗滴禾下土 </p> <p>誰知盤中餐</p> <p>粒粒皆辛苦</p> </div> <button v-print="'#printTest'">打印</button> //目前看 不到 手動調 的方法 //
2.2 接下來 如何設計模版
做這個模版設計,百度找了一頓的 就看見一個 注冊組件方式 ,寫的不詳細,自己沒有實現出來,(┬_┬)先回到jq的思維 !!
讓用戶或者實施人員自己設計模版,這聽起來有點之前的拖拽建站的感覺呀,拖拽元素生成對應的html代碼(不想做個這東西!!),想想有啥可以借用的東西呢?一下子想到之前用過的富文本編譯器o(∩_∩)o 哈哈!!
那就百度下-----確實找到一篇類似的文章 https://www.cnblogs.com/s0611163/p/4885833.html 文章中很多數據看不到,沒法具體的嘗試!!只能借鑒思路了 ,既然提到了 ueditor 那就也用這個吧 !!
ueditor 的官網 有不少例子 http://ueditor.baidu.com/website/onlinedemo.html
初試的時候 用的jq版本 (這個插件就是jq版的)vue的盛行 到目前已經好久不更新了,試驗完 jq版本 又 嘗試往 vue項目上 轉移 。
拓展 :Vue 中使用UEditor富文本編輯器
參考 https://blog.csdn.net/haochuan9421/article/details/81975966
//1.安裝
cnpm i vue-ueditor-wrap
//2.下載處理后的UEditor,下載地址
https://github.com/HaoChuan9421/vue-ueditor-wrap/tree/master/assets/downloads
//解壓,重命名文件夾為UEditor,放入public文件夾下(如果是舊項目對應static文件夾)。
//3.引用組件、注冊組件
import VueUeditorWrap from 'vue-ueditor-wrap' // ES6 Module
// 或者
const VueUeditorWrap = require('vue-ueditor-wrap') // CommonJS
//4. v-model綁定數據
<vue-ueditor-wrap v-model="msg"></vue-ueditor-wrap>
data () {
return {
msg: '<h2><img src="http://img.baidu.com/hi/jx2/j_0003.gif"/>Vue + UEditor + v-model雙向綁定</h2>'
}
}
//5. 修改配置 具體參考如下詳細代碼
//詳細代碼
<template>
<div>
<div id="app">
<vue-ueditor-wrap v-model="msg" :config="myConfig"></vue-ueditor-wrap>
<div class="tembtn">
<!-- <el-button type="primary" @click="showOne();">獲取編輯器內容</el-button> -->
<el-button type="primary" @click="saveTemplate();">保存編輯模版</el-button>
</div>
</div>
</div>
</template>
<script>
import VueUeditorWrap from 'vue-ueditor-wrap'
export default {
name: "setPrintTemplate",
components: {
VueUeditorWrap
},
data() {
return {
msg:'',
myConfig:{
// 編輯器不自動被內容撐高
autoHeightEnabled: false,
// 初始容器高度
initialFrameHeight: 480,
// 初始容器寬度
initialFrameWidth: '100%',
// 上傳文件接口(這個地址是我為了方便各位體驗文件上傳功能搭建的臨時接口,請勿在生產環境使用!!!)
serverUrl: '',
// UEditor 資源文件的存放路徑,如果你使用的是 vue-cli 生成的項目,通常不需要設置該選項,vue-ueditor-wrap 會自動處理常見的情況,如果需要特殊配置,參考下方的常見問題2
UEDITOR_HOME_URL: '/static/UEditor/'
}
}
},
mounted() {
this.msg = localStorage.setPrintTemplate || ''
},
methods: {
showOne(){
alert(this.msg);
},
saveTemplate(){
alert('初步計划:此處需要將保存的模版保存到數據庫中,可以設置多個,先本地模擬一個保存');
localStorage.setPrintTemplate = this.msg;
alert('模版保存成功')
}
},
}
</script>
注意:這里的msg 就是 我需要的html代碼
附件:顯示一下 測試中設計的模版 與模擬的json數據 (模版字段與json字段相同)

2.3 重點來了-----將上面的 html內容與 json想結合 需要一個函數,兩個參數 分別是模版代碼 與 json內容
這個功能算是核心功能吧 費了點盡!~~~(由於不確定哪些用循環?哪些是簡單的單獨的字段替換?表格的位置都在最后么??等等可擴展功能)
補充:在做這個功能的時候 先百度了下 js模版引擎原理 來提高點思路
文章一 : https://www.cnblogs.com/c2016c/articles/9343042.html
文章二:https://www.jianshu.com/p/9091e8a343e4
文章三:https://www.cnblogs.com/hustskyking/p/principle-of-javascript-template.html
確實提供一些思路 但我需要的功能也不近相同 ,他們都知道 循環體是哪~~我這個沒法具體的 ,寫出來循環體 只能去判斷!!
上來給自己定了個難點的 模版 (⊙﹏⊙) 如圖示:

圖中 分為5個部分,
第一部分是 單純的 p標簽 內容替換
第二四部分是 一個 table 帶有循環體(這個循環體的table我加了個 class="for"做標記)
第三部分 是一個 不帶循環的table形式(其實他的性質和 單純的p標簽一樣 算是一類)
第五部分 是結尾 沒啥!!!!
大體思路:
1.將模版分段(依據循環的表格),顯示順序不能變,放入到一個大的數組arr中
2.將arr中的每個 模版進行處理
2.1 如是 非循環部分 直接 正則替換 后形成 html內容
2.2 若是 循環部分 再次正則找出循環體, 循環替換后與該table的其他部分 組成新的html內容
設計模版的時候 要注意:
如果是循環展示列表數據 那么這個列表 應該加class="for",(編譯器切換到html模式),模版字段必須與 接口返回的數據字段一樣
對於接口:
返回的數據格式要參照上面形式
直接代碼
<script>
var html = '<p>商品快遞單</p><p>時間:{{time}}</p><p>地點:{{address}}</p><p>內容:</p><p><br/></p><table class="for"><tbody><tr class="firstRow"><td width="105" valign="top" style="word-break: break-all;"> <span style="font-size: 18px;"> <strong><span style="font-size: 16px;">名稱</span></strong></span></td><td width="105" valign="top" style="word-break: break-all;">顏色</td><td width="105" valign="top" style="word-break: break-all;">大小</td><td width="105" valign="top" style="word-break: break-all;">數量</td><td width="105" valign="top" style="word-break: break-all;">途徑</td><td width="105" valign="top" style="word-break: break-all;">價格</td><td width="105" valign="top" style="word-break: break-all;">優惠價格</td><td width="105" valign="top" style="word-break: break-all;">實施人員</td></tr><tr><td width="105" valign="top" style="word-break: break-all;">{{name}}</td><td width="105" valign="top" style="word-break: break-all;">{{color}}</td><td width="105" valign="top" style="word-break: break-all;">{{size}}</td><td width="105" valign="top" style="word-break: break-all;">{{num}}</td><td width="105" valign="top" style="word-break: break-all;">{{tj}}</td><td width="105" valign="top" style="word-break: break-all;">{{price}}</td><td width="105" valign="top" style="word-break: break-all;">{{aoutprice}}</td><td width="105" valign="top" style="word-break: break-all;">{{cname}}</td></tr></tbody></table><p><br/></p><table><tbody><tr class="firstRow"><td width="483" valign="top" style="word-break: break-all;">國家</td><td width="483" valign="top" style="word-break: break-all;">{{country}}</td></tr><tr><td width="483" valign="top" style="word-break: break-all;">省份</td><td width="483" valign="top" style="word-break: break-all;">{{province}}</td></tr></tbody></table><p><br/></p><table class="for"><tbody><tr class="firstRow"><td width="483" valign="top" style="word-break: break-all;">城市</td><td width="483" valign="top" style="word-break: break-all;">姓名</td></tr><tr><td width="483" valign="top" style="word-break: break-all;">{{city}}</td><td width="483" valign="top" style="word-break: break-all;">{{name}}</td></tr></tbody></table><p><br/></p>';
var json = {
time: '2018-15-15',
address: '山東青島',
data: [{
name: '蘋果',
color: '紅色',
size: '3存',
num: '4',
tj: '5',
price: '6',
aoutprice: '1',
cname: '劉一',
}, {
name: '桃子',
color: '綠色',
size: '6',
num: '4',
tj: '5',
price: '6',
aoutprice: '1',
cname: '劉二',
}],
country: '中國',
province: '山東',
}
var efg = /<table class="for">.*?<\/table>/g;
var regtr = /<tr>.*?<\/tr>/g;
attachTemplateToData = function(template, data) {
var i = 0,
len = data.length,
fragment = '',
tmeparr = [], //總的模版
tempforarr = [], //用 replace 處理 得到 字段中需要循環的模版------最多就一個哈哈哈哈哈
tempsplit = []; //用 split 處理 得到的 不需要循環的模版
function strReplace(temps, obj) {
var t, key, reg; //遍歷該數據項下所有的屬性,將該屬性作為key值來查找標簽,然后替換
for (key in obj) {
reg = new RegExp('{{' + key + '}}', 'ig');
if (typeof(obj[key]) === 'string') {
t = (t || temps).replace(reg, obj[key]);
}
}
return t;
}
function forReplace(temps, obj) {
var t, key, reg; //遍歷該數據項下所有的屬性,將該屬性作為key值來查找標簽,然后替換
for (key in obj) {
reg = new RegExp('{{' + key + '}}', 'ig');
t = (t || temps).replace(reg, obj[key]);
}
console.log(t)
return t;
}
tempsplit = template.split(efg);
template.replace(efg, function(str) {
tempforarr.push(str)
})
for (var i = 0; i < tempsplit.length - 1; i++) {
//for 循環 把 tempforarr 和 tempsplit 的模版 組成一個完整的 組數 (按照原先顯示順序的,其實就是在 tempsplit 中元素之間依次插入 tempforarr)
//鑒於就一個 for循環的表格 的直接中間 插入就好
tmeparr.push(tempsplit[i]);
tmeparr.push(tempforarr[i])
}
tmeparr.push(tempsplit[tempsplit.length - 1]);
console.log(tmeparr)
//處理模版
var forTempHtml = '',
forTempCont = '';
for (var m = 0; m < tmeparr.length; m++) {
if (regtr.test(tmeparr[m]) && (tmeparr[m].search('table class="for"') != -1)) {
//for for循環數據
//得到 循環體的模版
tmeparr[m].replace(regtr, function(str) {
forTempHtml = str;
})
// 將循環體的模版 與 數據結合得到 相應的 html結構
for (var n = 0; n < json.data.length; n++) {
forTempCont += forReplace(forTempHtml, json.data[n]);
}
//得到循環后的html結構 將此結構 替換 原先的模版
fragment += tmeparr[m].replace(regtr, forTempCont)
} else {
//普通的字段替換
fragment += strReplace(tmeparr[m], json);
}
}
return fragment;
};
$('#cont').html(attachTemplateToData(html, json))
</script>
拓展補充:正則與字符串處理
a.*?b就是a開始b結束的匹配
//利用正則分割,str.split(/reg/); js同時使用多個分隔符分割字符串. var mystring = "jb51.net,google.com,baidu.com_weibo.com_haotu.net"; var myarray = mystring.split(/[,_]/);
//代碼中 常用的幾個正則 var re = /<%([^%>]+)?%>/g, 正則全局匹配以<%開頭,中間不是%或>並以%>結尾的配配項 var efg = /<table class="for">.*?<\/table>/g;
//目前還不知道 有啥函數可以一次性的 將模版分成5段!! //split 函數 得到的結果 不帶有 分隔符 //replace 函數可以找到 對應的分隔符 //兩者相結合 ,你來一個元素 我來一個元素 最終巧妙的 按照順序 得到了 完整的 分段模版
6666

