欢迎!从2017年开始,将慢慢的不在xmind上写总结了,全部转到博客中!这里将不再随便写写,将继承在xmind的精神,继续前行!!!

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

posted @ 2019-09-30 17:21  拐进web的奋斗者  阅读(7986)  评论(1编辑  收藏  举报