vue+ts在线文档编辑(腾讯文档)多人在线编辑-实现假分页(二)
整个分页分成三层 第一层是分页布局,第二层是书写编辑器层 第三层是水印层1.分页展示层:为分页效果展示,在书写层上方,包含页眉页脚,占位不动2.书写层:用于用户输入,它是一个整体,无论写多少页,其实 都是一个元素3.水印层:生成水印渲染
实现思路:
整个分页分成三层 第一层是分页布局,第二层是书写编辑器层 第三层是水印层
1.分页展示层:为分页效果展示,在书写层上方,包含页眉页脚,占位不动
2.书写层:用于用户输入,它是一个整体,无论写多少页,其实 都是一个元素
3.水印层:生成水印渲染
在看前您可先看demo 效果是否是您要找的,再决定是否继续往下看,以免浪费您的时间。http://demo.doc.goflys.cn/ ,需要源码在这里免费下载
技术点:
1.第一层是分页布局 点击事件要穿透到书写层,使用css 属性 pointer-events: none;
2.在这三层外包裹一层 用于设纸张大小,如A4,可以用于整体编辑页面背景(白色)
3.两个页面之间加入分割符,实时计算书写层的高度,并生成相对应的分页数,生成分页同时给与最新分页的分割符之间的书写层添加空白区。
实现分页步骤:
- 加一个外框容器(class:form-widget-container)设置容器的高,
- 加一个总分页容器(class:editor-container-box)设置容器的高为全部分页文档的高,并设置文本的宽、让其居中。
- 添加一个容器(class:editor-content)与父级容器同高,背景色为白色、position: relative;,
- 在(class:editor-content)层内依次添加分页层、书写层、水印层。
实现代码:
1.html代码,其中winHeight为编辑区高度,pageRaelheight为所有分页的高度,页眉只是占个位下一篇继续讲解。
<div class="form-widget-container" :style="{height:winHeight+'px'}">
<div class="editor-container-box" :style="{height:pageRaelheight+'px'}">
<div class="editor-content" :style="{height:pageRaelheight+'px'}" >
<!--分页层-->
<div class="editor-page-list" >
<template v-for="item in pageCount">
<div class="editor-logic-page">
<!--页眉-->
<div class="header-page page_wrapper">
</div>
<!--页脚-->
<div class="footer-page page_wrapper">
<div class="pagetext">-第{{item}}页-</div>
</div>
</div>
<div class="melo-page-gap" v-if="item!=pageCount" style=" width: 100%; height: 23px; pointer-events: auto;"></div>
</template>
</div>
<!--编辑器-书写成-->
<div ref="containerRef" style="padding-top:100px;padding-bottom: 40px;" ></div>
<!--水印层-->
<div class="editor-pagebg-list" >
<template v-for="item in pageCount">
<div class="editor-bg-page" >
</div>
</template>
</div>
</div>
</div>
</div>
2.less样式
.form-widget-container{
background: transparent;
overflow: auto;
width: 100%;
height: 100%;
display: inline-flex;
}
//编辑器
.editor-container-box {
width: 794px;
margin: 0 auto;
margin: 12px auto;
// padding: 12px 8px 10px;
// margin-bottom: 10px;
.editor-content {
position: relative;
background: #fff;
// margin-bottom: 25px;
.editor-page-list{
position: absolute;
top: 0;
z-index: 33;
pointer-events: none;
// background: #fff;
.editor-logic-page{
width: 794px;
height: 1100px;
// box-shadow: rgba(0, 0, 0, 0.06) 0px 0px 10px 0px, rgba(0, 0, 0, 0.04) 0px 0px 0px 1px;
position: relative;
.header-page{
// pointer-events: auto;
width: 100%;
position: absolute;
top: 0px;
// background: #fff;
height: 100px;
}
.footer-page{
width: 100%;
// pointer-events: auto;
position: absolute;
bottom: 0px;
height: 40px;
// background: #fff;
.pagetext{
text-align: center;
padding-top: 10px;
height: 100%;
}
}
//透明显示下层
.page_wrapper{
background-image: radial-gradient(transparent 1px,#ffffff 1px);
background-size: 4px 4px;
backdrop-filter: saturate(50%) blur(4px);
}
}
.melo-page-gap {
background: #f3f5f7;
z-index:99999999;
cursor: url("data:image/svg+xml,%3c%3fxml version='1.0' encoding='UTF-8'%3f%3e %3csvg width='24px' height='24px' viewBox='0 0 24 24' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3e %3ctitle%3eICON/bottombar/paging%3c/title%3e %3cg id='ICON/bottombar/paging' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3e %3cg id='Word-%e5%ba%95%e9%83%a8%e6%a0%8f-%e5%88%86%e9%a1%b5'%3e %3cg id='Group%e5%a4%8d%e5%88%b6-3' opacity='0' fill='black' fill-rule='nonzero'%3e %3crect id='Rectangle' opacity='0.0599999987' x='0' y='0' width='24' height='24'%3e%3c/rect%3e %3crect id='Rectangle' opacity='0.100000001' x='3' y='3' width='18' height='18'%3e%3c/rect%3e %3crect id='Rectangle' opacity='0.119999997' x='4' y='4' width='16' height='16'%3e%3c/rect%3e %3c/g%3e %3cpath d='M6.25%2c14 L6.25%2c16 L6.25%2c17.75 L17.75%2c17.75 L17.75%2c16 L17.75%2c14 L19%2c14 L19%2c18.5 C19%2c18.7761424 18.7761424%2c19 18.5%2c19 L5.5%2c19 C5.22385763%2c19 5%2c18.7761424 5%2c18.5 L5%2c14 L6.25%2c14 Z' id='%e5%bd%a2%e7%8a%b6%e7%bb%93%e5%90%88%e5%a4%8d%e5%88%b6' fill='%23464D5A' transform='translate(12.000000%2c 16.500000) scale(-1%2c 1) rotate(-180.000000) translate(-12.000000%2c -16.500000) '%3e%3c/path%3e %3crect id='%e7%9f%a9%e5%bd%a2' fill='%23464D5A' x='3' y='11.25' width='18' height='1.25'%3e%3c/rect%3e %3cpath d='M6.25%2c5 L6.25%2c7 L6.25%2c8.75 L17.75%2c8.75 L17.75%2c7 L17.75%2c5 L19%2c5 L19%2c9.5 C19%2c9.77614237 18.7761424%2c10 18.5%2c10 L5.5%2c10 C5.22385763%2c10 5%2c9.77614237 5%2c9.5 L5%2c5 L6.25%2c5 Z' id='%e5%bd%a2%e7%8a%b6%e7%bb%93%e5%90%88' fill='%23464D5A'%3e%3c/path%3e %3c/g%3e %3c/g%3e %3c/svg%3e") 15 15,auto;
}
}
.am-engine{
position: absolute;
top: 0;
width: 794px;
background: transparent;
padding: 0px 40px 0px 40px;
z-index: 19;
}
//下一层 加水印
.editor-pagebg-list{
position: absolute;
top: 0;
z-index: 10;
.editor-bg-page{
width: 794px;
height: 1123px;
position: relative;
overflow: hidden;
background: transparent;
pointer-events: none;
}
}
}
:deep(.data-table){
background-color: transparent;
}
//修改变革线颜色
:deep(.table-wrapper .table-main-bg .table-main-border-top){
border-top: 1px solid #000000;
}
:deep(.table-wrapper .table-main-bg .table-main-border-right){
border-right: 1px solid #000000;
}
:deep(.table-wrapper .table-main-bg .table-main-border-bottom){
border-bottom: 1px solid #000000;
}
:deep(.table-wrapper .table-main-bg .table-main-border-left){
border-left: 1px solid #000000;
}
}
3.计算分页ts代码
//计算有多少页面
const pageRaelheight=ref(1100)
const countPage=(engine: EngineInterface)=>{
let editorheight=containerRef.value?.clientHeight||0
editorheight=editorheight-40
let pagenum=Math.ceil(editorheight/1100)
if(pagenum>1){
const midileheight=(pagenum-1)*25//中间分割线高之和
const allheight=editorheight+midileheight
//重新介绍高度
pagenum=Math.ceil(allheight/(1100))
pageRaelheight.value=pagenum*1100+midileheight
}else{
pageRaelheight.value=pagenum*1100
}
const pageNum=getPageValue()
if(pageNum!=pagenum){
if(pageNum<pagenum){
//创建节点中间加入空行
const divdom1 = $('<p><br></p>');
const divdom2 = $('<p><br></p>');
const divdom3 = $('<p><br></p>');
const divdom4 = $('<p><br></p>');
const divdom5 = $('<p><br></p>');
const divdom6 = $('<p><br></p>');
const divdom7 = $('<p><br></p>');
const divdom8 = $('<p><br></p>');
const bfnewnode=engine.container.append(divdom1).append(divdom2).append(divdom3).
append(divdom4).append(divdom5).append(divdom6).append(divdom7).append(divdom8)
const divdom9 = $('<p><br></p>');
const newnode= bfnewnode.append(divdom9)
}
setPageValue(pagenum.toString())
}
pageCount.value=pagenum
nextTick(()=>{
// 添加水印
var watermark_txt = "<div>仅供Pge专用 请注意保护隐私</div>" ;//水印内容
WaterMark({ "watermarl_element": ".editor-bg-page", "watermark_txt": watermark_txt });
})
}
结果总结:
在文档分页需要比较全面前端经验储备,单纯技术来说,百度搜索都可解决,注意还是选型技术的思路。还有要从事件项目需求出发,是否选择假分页,或者必须是真分页。做一个产品既要从人员时间成本考虑,又兼顾使用体验。本文就到处有不明白需要了解请到作者Go.Fly全栈开发者社区技术社区。 需要源码在这里免费下载 。希望能帮到您,互相支持!一起成长!
更多推荐
所有评论(0)