实现思路:

整个分页分成三层 第一层是分页布局,第二层是书写编辑器层 第三层是水印层

1.分页展示层:为分页效果展示,在书写层上方,包含页眉页脚,占位不动

2.书写层:用于用户输入,它是一个整体,无论写多少页,其实 都是一个元素

3.水印层:生成水印渲染

在看前您可先看demo 效果是否是您要找的,再决定是否继续往下看,以免浪费您的时间。http://demo.doc.goflys.cn/ ,需要源码在这里免费下载


技术点:

1.第一层是分页布局 点击事件要穿透到书写层,使用css 属性 pointer-events: none;

2.在这三层外包裹一层 用于设纸张大小,如A4,可以用于整体编辑页面背景(白色)

3.两个页面之间加入分割符,实时计算书写层的高度,并生成相对应的分页数,生成分页同时给与最新分页的分割符之间的书写层添加空白区。


实现分页步骤:

  1. 加一个外框容器(class:form-widget-container)设置容器的高,
  2. 加一个总分页容器(class:editor-container-box)设置容器的高为全部分页文档的高,并设置文本的宽、让其居中。
  3. 添加一个容器(class:editor-content)与父级容器同高,背景色为白色、position: relative;,
  4. 在(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全栈开发者社区技术社区。 需要源码在这里免费下载 。希望能帮到您,互相支持!一起成长!

下一篇:vue+ts在线文档编辑(类腾讯文档)多人在线编辑-自定义页眉和分页打印(三)_vue在线文档编辑_GoFly开发者的博客-CSDN博客随着在线办公场景越来越多,同时需要各式各样办公软件,在开发时就用得到在线文档来内容指定某人填写、审批、传阅文件,文件导出、打印成纸盖章等。所以需要功能较为强大、复杂的文档编辑器,前两篇文章我们已经教大家如何制作分页的文档编辑器,这篇文章我们把功能补全,教大家做好的文档怎么添加自定义页眉、打印。https://blog.csdn.net/qq_23731311/article/details/129833733

Logo

前往低代码交流专区

更多推荐