一 需求
公司产品由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 哈哈!!
那就百度下-----确实找到一篇类似的文章 文章中很多数据看不到,没法具体的尝试!!只能借鉴思路了 ,既然提到了 ueditor 那就也用这个吧 !!
ueditor 的官网 有不少例子 http://ueditor.baidu.com/website/onlinedemo.html
初试的时候 用的jq版本 (这个插件就是jq版的)vue的盛行 到目前已经好久不更新了,试验完 jq版本 又 尝试往 vue项目上 转移 。
拓展 :Vue 中使用UEditor富文本编辑器
参考
//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.jianshu.com/p/9091e8a343e4
文章三:
确实提供一些思路 但我需要的功能也不近相同 ,他们都知道 循环体是哪~~我这个没法具体的 ,写出来循环体 只能去判断!!
上来给自己定了个难点的 模版 (⊙﹏⊙) 如图示:
图中 分为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