前言:

有的项目需要用到打印,如果只有少数的地方需要用到打印,一般只需要固定模板进行打印就行了,但是我们的项目总是与众不同,明明只要固定模板就可以完成需求的,非要添加一个灵活的打印模板,而且还涉及到拖拉填充文本,真是脑细胞不知道死掉了多少! ! ! (= ̄ω ̄=)喵了个咪

需求:

前端页面就是简单的三栏布局,如下图所示,基本就是这种,左边框中就是一个搜索框,加上需要向富文本编辑器中拖拽的内容,中间就是用来编辑模板的富文本编辑器,右边就是各类设置(弄的和真的一样ヽ(ー_ー)ノ,)

最主要的需求就是将左边的字段拖到富文本编辑器中,字段分为基础字段,以及一些算是表格字段,因为项目的打印模板多是用来编辑各类打印单据的,所以说用的到表格比较多,基础字段只能拖拽到富文本的其他区域,不能放在表格中,表格的字段只能放在表格中,不能拖放在其他区域;(注意:这种的项目需求一般需要用到的就是判断拖拽放置的目标标签,如果是这个标签就放置,不是就直接return  提示就行了)

前端布局就不多说了,相信这种布局对于大家来说就都是小菜一碟啦(┓(;´_`)┏)

核心内容:字段拖拽填充富文本编辑

准备:wangeditor v4 的版本(本来准备用v5的版本的,之前写的时候使用v4进行实验的,然后就忘了改了,因为要根据右边的模板设置操作编辑器的编辑部分,比较麻烦,所有就懒得换版本了)

官网:Introduction · wangEditor 用户文档

拖拽字段的渲染:因为富文本编辑器最终得到的是html片段,需要在其他的地方进行使用,前端再次使用的话是无法填充数据的,所以这里就让后端进行填充数据,我们根据后端返回的"字段名称"和"变量名"(后端进行定义,用于匹配填充数据),进行编辑模板,显示是“字段名称”,拖拽填充是"变量名称"(进行隐藏)(^_−)☆。

示例:

还有一点比较重要:拖拽的时候如何区分是“基础字段”还是“表格字段”

这里我用的方法是在获取后端数据的时候,进行数据处理,因为后端给的数据是分开的

例如:[{基础字段},{BOM字段},{工序字段}...]

所以这里在处理数据的时候给‘基础字段’和“其他字段”加了一个标识,用于区分拖拽的是哪一个字段;基础字段添加了一个:source-field,其他字段添加:BOM,最终这个标识渲染到拖拽元素的类名中:class=source-field(具体的上图有)

async searchList(){

let data=this.listQuery

// 模板字段以及模糊查询

await templateField(data).then(res=>{

let datas=[]

for (const key in res.data) {

datas.push({name:key,every:res.data[key]})

}

let m=[]

datas.forEach(item=>{

if(item.name.includes('基础信息字段')){

item.every.forEach((item,index)=>{

item.class='source-field' //添加标识

item.id=index+1

})

m.unshift(item)

}else{

item.every.forEach((item,index)=>{

item.class='BOM' //添加标识

item.id=index+1

})

m.push(item)

}

})

this.fieldList=m

})

},

字段渲染过后就是拖拽填充:

常见的拖拽填充有:h5原生拖拽以及sortablejs等

h5拖拽:HTML5 拖放

sortablejs网址:Sortable.js中文网

最初的时候使用的是sortablejs进行拖放,最后发现拖拽元素的文本无法放置在富文本编辑器中,因为sortablejs的封装和富文本编辑器的封装好像有冲突,所以被迫放弃(死磕好好长时间,最终放弃 (╬◣д◢) ),最终使用的是原生拖拽,原生的拖拽需要在标签上添加:draggable=true,表示是可以进行拖拽的,原生拖拽也是有事件的,这里就不多说,大家可以去看一下官网。

 因为要进行拖拽放置文本,我们这里就需要进行处理数据,拼接成后端需要的格式;

基础字段填充:示例:订单号:{$orderNumber}

表格字段填充:示例:{$orderNumber}

这个时候我们用的原生拖拽事件是:拖拽开始的时候:@dragstart="onDragStart"

onDragStart(event) {

let flag=event.target.classList.contains('source-field')

let BOM=event.target.classList.contains('BOM')

event.dataTransfer.setData("flag",flag)

event.dataTransfer.setData("BOM",BOM)

let text=event.target.innerText

let children= event.target.children[0].innerText

// 判断数据拼接的方式

if(flag){

this.itemText = text+':${'+children+'}';

this.$refs.editor.getItemText(this.itemText)

}

if(BOM) {

this.itemText = '${'+children+'}';

this.$refs.editor.getItemText(this.itemText)

}

},

我们在 触发事件时判断 触发该事件的元素是什么(e.target) 1. 判断内容 innerHTML innerText 2. 标签名 nodeName (判断的时候,标签名需要大写) 3. 属性 e.target.hasAttribute(“属性名”); 有则是true 无则是false 4. 类名 e.target.classList.contains(“类名”); 有则是true 无则是false

我们这边判断的类名:因为要根据我之前处理数据添加的标识判断拖拽的是什么字段,决定放置文本是什么样的拼接方式(如上代码)

 同时我们又根据判断向event对象中添加一个标识,用于之后判断放置的位置(因为需求表格字段   只能放置表格中,基础字段不能放置表格中)至此拖拽基本完工,后面就是放置;❥(ゝω・✿ฺ)

 这里我们需要转到写有富文本编辑的组件中,利用监听监听拖放事件:drgover和drop,drgover要进行阻止默认事件,

// 监听拖放事件

this.$refs.editor.addEventListener("dragover", this.onDragOver);

this.$refs.editor.addEventListener("drop", this.onDrop);

// 拖放事件

onDragOver(event) {

event.preventDefault();

},

// 拖放事件

onDrop(event) {

event.preventDefault();

let Td=event.target.tagName

let flag=event.dataTransfer.getData('flag')

let BOM=event.dataTransfer.getData('BOM')

// 判断基础信息字段不能拖动到表格中

if (flag==='true') {

if (flag==='true'&&Td=='TD'||flag==='true'&&Td=='TH') {

this.$message.error('基础信息字段不能拖动到表格中');

return

}

this.fillUp()

}

// 判断子列表信息只能放在表格中

if (BOM==='true') {

if (BOM==='true'&&Td=='TD') {

this.fillUp()

return

}

this.$message.error('子列表字段只能拖拽到表格中,请先创建表格');

}

},

// 富文本编辑器内容填充方法

fillUp(){

const selection = window.getSelection();

let k=selection.anchorNode

console.log(k.parentNode.tagName);

// console.log(k);

if(!k.tagName&&k.parentNode.tagName!=='P'&&k.parentNode.tagName!=='SPAN'&&k!=='#text'&&k.parentNode.tagName!=='FONT'&&k.parentNode.tagName!=='B'){

this.$message.error('拖放位置已有内容!');

};

if(k.tagName==='P'||k.parentNode.tagName==='P'||k.tagName==='TH'||k.tagName=='TD'||k=='#text'

||k.parentNode.tagName=='SPAN'||k.parentNode.tagName==='FONT'||k.parentNode.tagName=='B'){

const range = selection.getRangeAt(0);

const text = this.itemText;

const node = document.createTextNode(text);

range.deleteContents();

range.insertNode(node);

}

},

这里我们先看上面代码中的【富文本编辑器内容填充的方法】

window.getSelection(),返回的是一个Selection对象,表示用户选择的文本范围或光标的位置,

这里我们用Selection对象属性是:anchorNode(返回选区起点所在的节点)拿到光标所在位置的节点,这里我是用来进行判断拖放位置是有内容的,因为在表格中如果选中原有的文本,在进行拖放表格的样式会发生错乱,所以这里做了一个阻止,只有没有文本的时候才能放置。

放置的时候,我们要用getRangeAt方法返回选区开始的节点,因为通常情况下,用户只能选择一个范围,所以只有一个选区,所以此方法一般为:getRangeAt(0)

返回节点之后就需要拿到原先的拖放的文本this.itemText,根据拖放的文本创建一个节点,然后利用deleteContents()方法从文档树中删除选中范围的所有内容,再将创建的节点插入到之前返回的节点;至此我们就完成拖放填充的富文本编辑中;(๑>ڡ<)☆

window.getSelection()详解:关于window.getSelection_xiao xu的博客-CSDN博客

富文本填充完成,我们这里就需要判断字段拖放的位置了

event.preventDefault();

let Td=event.target.tagName

let flag=event.dataTransfer.getData('flag')

let BOM=event.dataTransfer.getData('BOM')

// 判断基础信息字段不能拖动到表格中

if (flag==='true') {

if (flag==='true'&&Td=='TD'||flag==='true'&&Td=='TH') {

this.$message.error('基础信息字段不能拖动到表格中');

return

}

this.fillUp()

}

// 判断子列表信息只能放在表格中

if (BOM==='true') {

if (BOM==='true'&&Td=='TD') {

this.fillUp()

return

}

this.$message.error('子列表字段只能拖拽到表格中,请先创建表格');

}

上面的代码是拖放事件中的一部分,完整代码在上上面,

先判断基础字段不能放置表格中:

因为表格中我们最终放置的标签是,这里我们需要拿到目标标签的tagName,然后我们在拿到之前用区分基础字段和表格字段的标识,主要就是用标识进行判断的,如果基础字段的标识为真,并且目标标签的tagName为TD,就进行弹窗提示:“基础字段不能拖动到表格中”,并且return出去,否则就是调用富文本填充的方法;

判断表格字段只能放表格中方法就是同上,具体的可以看代码,这里就省略了❥(ゝω・✿ฺ)

最后:至此整个核心描述完了,可能很多的细节没有讲到(比如模板设置控制编辑区域),因为我也是摸着石头过河,死磕了好多天才写出了,如果有不对的地方希望大家能指正,不喜勿喷,谢谢!后面还会写编辑模板的使用,这个又是一大难题(打印的时候)  (⌒.−)=★

好文推荐

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: