(轉)vue 打印 前台用戶自己設計模版 打印報表實現記錄


 

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;">&nbsp; &nbsp; &nbsp; <span style="font-size: 18px;">&nbsp; <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

 
0
0
 
 
 
 
posted @  2019-09-30 17:21  拐進web的奮斗者  閱讀(538)  評論(0)  編輯  收藏

 

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM