Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 91久久精品国产免费一区,人妖系列精品视频在线观看,精品一区二区免费视频

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          動手練一練,用純 CSS 制作一款側滑顯示留言面板的網頁組件


          家好,不知道你們是否和我一樣存在這樣的困惑呢,雖然css入門容易,但是其內容太多,好多屬性看了似是而非,覺得自己看懂了,到自己用的時候又很犯難了,看到漂亮的效果還是無從下手,這主要還是自己對新屬性實踐太少了,不能進行靈活應用,CSS總讓一些人找不到感覺。其實學好CSS真的沒有太多捷徑,和JS編程一樣,要重視對待,要多看和多練,因為現在的CSS不再是以前的CSS啦。

          比如這兩本書《 CSS 權威指南第四版》,1000多頁,買了好幾個月我到現在還沒看完,文字實在太枯燥了,看完了忘,忘了繼續看,實在看不下去,不知道大家有沒有同樣的感受呢?

          好了,廢話不多說,今天我們要做的一個案例就是做一個常見的例子:在不少網站右側都有一個固定浮動的留言圖標,我們點擊這個圖標,就會側滑顯示留言內容面板。你也許會說這個不簡單嗎,使用JQ就能輕松實現,但是我想說的,為了網站的性能,能用CSS實現的盡量不要用JS,因為現在CSS已足夠強大。

          今天這個例子,我們將使用純CSS實現這個效果,這里我們將用到” CSS checkbox hack“的技術,效果如下圖所示:


          一、創建 HTML 結構

          基于上面的效果圖,我們要創建三個元素,一個 checkbox 元素以及對應的 label 標記,和一個表單面板元素。

          這里用到了一個 CSS 特性值得大家關注下:<label> 標簽的 for 屬性用于指定與哪個表單元素進行關聯,擴大表單元素的點擊區域,我們點擊 label 元素標記,其對應的表單元素將會被聚焦選中。

          這個特性是我們實現這個案例的技巧之一,再結合 CSS checkbox 的偽類選擇器進行留言面板的顯示與隱藏,這樣我們就可以擺脫 JS 來實現這個案例。

          基于以上思路 ,我們開始動手吧,首先我們先放置 checkbox,和其對應的 label,最后添加表單面板和相關的表單元素。

          我們將通過表單的 id 屬性與表單中label元素的 for 值與其關聯,最終我們完成了 HTML 結構如下段代碼所示:

          <input type="checkbox" id="mycheckbox">
          <label for="mycheckbox" class="feedback-label">FEEDBACK</label>
          <form class="form">
            <div>
              <label for="fullname">Full Name</label>
              <input type="text" id="fullname">
            </div>
            <div>
              <label for="email">Email</label>
              <input type="email" id="email">
            </div>
            <div>
              <label for="comment">Comment</label>
              <textarea id="comment"></textarea>
            </div>
            <div>
              <button type="submit">Send</button>
            </div>
          </form>
          

          完成后的效果圖如下:

          二、定義基礎的樣式

          現在我們開始添加一些基礎的CSS的式,這里我們用到了CSS自定義變量,方便我們全局修改,還有一些 reset 規則,和表單的基礎規則樣式,示例代碼如下:

          :root {
            --white: white;
            --gradient: linear-gradient(-45deg, #FFA600 0%, #FF5E03 50%);
            --form: #eeefef;
            --border-radius: 4px;
            --form-width: 500px;
            --form-mob-width: 320px;
          }
           
          * {
            padding: 0;
            margin: 0;
            box-sizing: border-box;
          }
          
          body {
            font: 20px/1.5 sans-serif;
            background: var(--white);
          }
          
          h1 {
            font-size: 2rem;
            text-align: center;
            margin-top: 20vh;
          }
           
          button,
          label {
            cursor: pointer;
          }
           
          label {
            display: block;
          }
           
          button,
          input,
          textarea {
            font-family: inherit;
            font-size: 100%;
            border: none;
          }
           
          textarea {
            resize: none;
          }
          

          三、 定義表單元素相關樣式

          1、由于 checkbox 這個元素在案例中無需顯示,我們只是用其的偽類特性結合 label 控制留言面板的顯示與隱藏,因此我們需要將其移出可視區域,記住這里不能用隱藏屬性(display:none)。示例代碼如下:

          [type="checkbox"] {
            position: absolute;
            left: -9999px;
          }
          

          2、接下來,我們需要添加這些CSS操作:

          • 使用 fix 屬性將 checkbox 對應的 label 標簽元素固定在右側的中央。
          • 垂直先顯示”FEEDBACK“文本。
          • 隱藏表單面板,我們這里將其往右移動其寬度的 100% 的距離,并垂直居中。

          對應的CSS代碼如下:

          /*CUSTOM VARIABLES HERE*/
          .feedback-label,
          .form {
            position: fixed;
            top: 50%;
            right: 0;
          }
           
          .feedback-label {
            transform-origin: top right;
            transform: rotate(-90deg) translate(50%, -100%);
            z-index: 2;
          }
           
          .form {
            width: var(--form-width);
            max-height: 90vh;
            transform: translate(100%, -50%);
            padding: 30px;
            overflow: auto;
            background: var(--form);
            z-index: 1;
          }
          

          小提示:

          1、這里需要強調的是 feedback-label 樣式,在其垂直變換時,我們先逆時針進行了旋轉,其 x ,y 軸的方向也是隨著旋轉的,所以是translate(50%, -100%),將其垂直居中。

          2、在 form 樣式里,我們使用 transform 方法,translate(100%, -50%) 將其移出頁面顯示區域

          3、我們繼續,大家不要著急,馬上就快完成了,我們需要將頁面弄的漂亮些,添加一些樣式,示例代碼如下:

          /*CUSTOM VARIABLES HERE*/
           
          .feedback-label,
          .form input,
          .form textarea,
          .form button {
            border-radius: var(--border-radius);
          }
           
          .feedback-label,
          .form button {
            background: var(--gradient);
            color: var(--white);
          }
           
          .feedback-label:hover,
          .form button:hover {
            filter: hue-rotate(-45deg);
          }
           
          .feedback-label {
            padding: 5px 10px;
            border-radius: var(--border-radius) var(--border-radius) 0 0;
          }
           
          form div:not(:last-child) {
            margin-bottom: 20px;
          }
           
          form div:last-child {
            text-align: right;
          }
           
          .form input,
          .form textarea {
            padding: 0 5px;
            width: 100%;
          }
           
          .form button {
            padding: 10px 20px;
            width: 50%;
            max-width: 120px;
          }
           
          .form input {
            height: 40px;
          }
           
          .form textarea {
            height: 220px;
          }
          

          小提示:這里我們的背景色用到了 linear-gradient() 線性漸變,實現了一個漂亮的顏色漸變背景。還有一個 CSS3 語法需要關注下:hue-rotate,色調旋轉濾鏡,方便我們改變當前的顏色。

          四、使用CSS選擇器,實現表單面板的切換和隱藏

          我們通過點擊 checkbox 對應的 label 標簽進行切換和顯示留言面板,這里我們用到了 :checked 偽類,以及 ~(后續同胞選擇器)和 +(緊鄰同胞選擇器),輔助元素的選擇進行樣式變換,示例代碼如下:

          [type="checkbox"]:checked + .feedback-label {
            transform: rotate(-90deg) translate(50%, calc((var(--form-width) + 100%) * -1));
          }
           
          [type="checkbox"]:focus + .feedback-label {
            outline: 2px solid rgb(77, 144, 254);
          }
           
          [type="checkbox"]:checked ~ .form {
            transform: translate(0, -50%);
          }
           
          .feedback-label,
          .form {
            transition: all 0.35s ease-in-out;
          }
          

          這里有幾個樣式規則我們需要聊一下:

          1. translate(50%, calc((var(--form-width) + 100%) * -1)); 這個樣式是不是有些復雜,其實也不難,就是多加了一個表單面板的寬度,由于旋轉后,y軸變成了水平軸,向左移動相當Y軸往上移動,因此是負值,需要乘-1。
          2. 第二個選擇器,我們之所以加個選中后的 outline 輪廓屬性,主要是為了方便那些習慣鍵盤操作的用戶,當其使用 Tab 鍵選擇 feedback label元素時,然后再使用 Space 空格鍵就能很方便的打開留言面板進行切換。
          3. 第三個選擇器,我們使用 transform: translate(0, -50%); 將 X 軸更改成0,恢復成最開始的位置,這樣我們的留言面板內容就能顯示出來。

          處理響應式問題

          最后,特別重點提示下我們做頁面要考慮頁面響應式適配的問題,這里我們需要針對手機設備做一些樣式的調整,比如更改表單面板的寬度由原來的 500px 調整到 320px,以及初始字體的大小,調整成16px。

          最終添加的響應式代碼如下:

          /*CUSTOM VARIABLES HERE*/
           
          @media screen and (max-width: 600px) {
            body {
              font-size: 16px;
            }
           
            .form {
              padding: 15px;
              width: var(--form-mob-width);
            }
           
            form div:not(:last-child) {
              margin-bottom: 10px;
            }
           
            [type="checkbox"]:checked + .feedback-label {
              transform: rotate(-90deg) translate(50%, calc((var(--form-mob-width) + 100%) * -1));
            }
          }
          

          小節

          好了,到這里,我們的案例就全部完成了,你可以欣賞下自己完成的杰作啦,實現起來是不是很簡單呢,最后我還是建議大家還是親自動手實踐一遍,這樣才能加深對本案例用到的CSS屬性的理解。

          最終完成的效果,大家可以點擊以下網址進行在線體驗:

          https://www.qianduandaren.com/demo/feedback/

          今天的內容就和大家分享到這里,感謝你的閱讀,如果你喜歡我的分享,麻煩給個關注、點贊加轉發哦,你的支持,就是我分享的動力,后續會持續分享 CSS 常用案例和技巧,歡迎持續關注。

          延伸閱讀

          基礎章節:這30個CSS選擇器,你必須熟記(上)

          基礎章節:這30個CSS選擇器,你必須熟記(中)

          基礎章節:這30個CSS選擇器,你必須熟記(下)

          使用 CSS Checkbox Hack 技術制作一個手風琴組件

          擊右上方紅色按鈕關注“web秀”,讓你真正秀起來

          前言

          隨著前端開發越來越關注效率:通過選擇器的使用和簡化代碼來快速加載渲染。像Less、SCSS這樣的預處理器在工作的時候,需要繞的路較長,而直接使用css速度會更快。這里涵蓋了20個css技巧來幫助你減少重復規則和復寫,在布局中標準化樣式流程,不僅可以幫助你高效地創建自己的框架,而且可以解決許多常見的問題。

          如何提升你的CSS技能?掌握這20個css技巧即可[完整版]

          如果您對CSS比較陌生,看看這篇文章CSS選擇器如此之多,你了解多少?

          1、使用CSS重置(reset)

          css重置庫如normalize.css已經被使用很多年了,它們可以為你的網站樣式提供一個比較清晰的標準,來確保跨瀏覽器之間的一致性。大多數項目并不需要這些庫包含的所有規則,可以通過一條簡單的規則來應用于布局中的所有元素,刪除所有的margin、padding改變瀏覽器默認的盒模型。

          *{ 
           box-sizing:border-box; 
           margin:0; 
           padding:0 
          }
          

          使用box-sizing聲明是可選擇,如果你使用下面繼承的盒模型形式可以跳過它

          2、繼承盒模型

          讓盒模型從html 繼承:

          html { 
           box-sizing: border-box; 
          } 
          *, *:before, *:after { 
           box-sizing: inherit; 
          }
          

          3、使用flexbox布局來避免margin的問題 (Get Rid of Margin hacks width Flexbox)

          當你多少次試著去設計柵格布局如:組合或者圖片畫廊,如果使用浮動的方式,那么就需要去清除浮動和重置外邊距來使其分解成所需要行數。為了避免nth-、first-、last-child 問題 ,可以使用flexbox 的space-between 屬性值

          .flex-container{ 
           display:flex; 
           justify-content:space-between; 
          } 
          .flex-container .item{ 
           flex-basis:23%; 
          }
          

          4、使用:not() 解決lists邊框的問題

          在web設計中,我們通常使用:last-child nth-child 選擇器來覆蓋原先聲明應在父選擇器上的樣式。比如說一個導航菜單,通過使用borders 來給每個鏈接Link創建分割符,然后再在加上一條規則 解除最后一個link的border

          .nav li { 
           border-right: 1px solid #666; 
          } 
          .nav li:last-child { 
           border-right: none; 
          }
          

          這是一種很混亂的方式,它不僅強制瀏覽器以一種方式渲染,然后又通過特定的選擇器來撤銷它。這樣覆蓋樣式是不可避免的。然而,最重要的是,我們可以通過使用:not偽類(pseudo-class) 在你想聲明的元素上僅僅只使用一種樣式:

          .nav li:not(:last-child) { 
           border-right: 1px solid #666; 
          }
          

          上面就是,除了最后一個li以外,所有的 .nav li 都加上了border樣式,是不是很簡單! 當然,你也可以使用 .nav li+li或者 .nav li:first-child ~li ,但是 :not是更有語義化(semantic)和容易理解的。

          如何提升你的CSS技能?掌握這20個css技巧即可[完整版]

          5、body上加入line-height樣式

          導致低樣式效率(inefficient stylesheets)的一件事就是不斷的重復聲明。最好是做下項目規劃和組合規則,這樣CSS會更流暢。實現這一點,就需要我們理解級聯(cascade),以及如何在通用選擇器寫的樣式可以繼承在其他地方。行間距(line-height)可以作為 給你的整個項目設置的一個屬性,不僅可以減小代碼量,而且可以讓你的網站的樣式給一個標準的外觀

          body { 
           line-height: 1.5; 
          }
          

          請注意,這里的聲明沒有單位,我們只是告訴瀏覽器 讓它渲染行高是 渲染字體大小的1.5倍

          6、垂直居中任何元素 (vertical-center anything)

          在沒有準備使用CSSGrid 布局的時候,設置垂直居中布局的全局規則是一個很好的方式,可以為優雅(elegantly)的設置內容布局奠定一個基礎

          html, body { 
           height: 100%; 
           margin: 0; 
          } 
          body { 
           -webkit-align-items: center; 
           -ms-flex-align: center; 
           align-items: center; 
           display: -webkit-flex; 
           display: flex; 
          }
          

          這15種CSS居中的方式,你都用過哪幾種?

          7、使用SVG icons

          SVG使用于所有分辨類,并且所有瀏覽器也都支持。所以可以將.png .jpg .gif 等文件 丟棄。FontAwsome5中 也提供了SVG的圖標字體。設置SVG的格式就跟其他圖片類型一樣:

          .logo { 
           background: url("logo.svg"); 
          }
          

          溫馨提示:如果將SVG用在可交互的元素上比如說button,SVG 會產生無法加載的問題。可以通過下面這個規則來確保SVG可以訪問到(確保在HTML中已設置適當的aria屬性)

          .no-svg .icon-only:after { 
           content: attr(aria-label); 
          }
          

          如何提升你的CSS技能?掌握這20個css技巧即可[完整版]

          8、使用 “OWL選擇器”

          使用通用選擇器(universal selector)* 和相鄰的兄弟選擇器(adjacent sibling selector)+ 可以提供一個強大的的CSS功能,給緊跟其他元素中的文檔流中的所有元素設置統一的規則

          * + * { 
           margin-top: 1.5rem; 
          }
          

          這是一個很棒的技巧,可以幫你創建更加均勻的類型跟間距。在上面的列子中,跟在其他元素后面的元素,比如說H3后面的H4,或者一個段落之后的一個段落,他們之間至少1.5rems的間距(大約為30px)

          9、一致的垂直結構(Consistent Vertical Rhythm)

          一致的垂直節奏提供了一種視覺美學,使內容更具可讀性。如果owl選擇器過于通用,請在元素內使用通用選擇器(*)為布局的特定部分創建一致的垂直節奏:

          .intro > * { 
           margin-bottom: 1.25rem; 
          }
          

          10、對更漂亮的換行文本使用 box-decoration-break

          假設您希望對換行到多行的長文本行應用統一的間距、邊距、突出顯示或背景色,但不希望整個段落或標題看起來像一個大塊。Box Decoration Break屬性允許您僅對文本應用樣式,同時保持填充和頁邊距的完整性。如果要在懸停時應用突出顯示,或在滑塊中設置子文本樣式以具有突出顯示的外觀,則此功能尤其有用:

          .p { 
           display: inline-block; 
           box-decoration-break: clone; 
           -o-box-decoration-break: clone; 
           -webkit-box-decoration-break: clone; 
          }
          

          內聯塊聲明允許將顏色、背景、頁邊距和填充應用于每行文本,而不是整個元素,克隆聲明確保將這些樣式均勻地應用于每行。

          11、等寬表格單元格

          表格可能很難處理,所以嘗試使用table-layout:fixed來保持單元格相等寬度:

          .calendar { 
           table-layout: fixed; 
          }
          

          如何提升你的CSS技能?掌握這20個css技巧即可[完整版]

          12、強制使用屬性選擇器顯示空鏈接

          這對于通過CMS插入的鏈接特別有用,CMS通常不具有類屬性,并幫助您在不影響級聯的情況下對其進行特定樣式設置。例如,<a>元素沒有文本值,但href屬性有一個鏈接:

          a[href^="http"]:empty::before { 
           content: attr(href); 
          }
          

          13、樣式“默認”鏈接

          說到鏈接樣式,您可以在幾乎每個樣式表中找到一個通用的A樣式。這迫使您為子元素中的任何鏈接編寫額外的覆蓋和樣式規則,并且在使用像WordPress這樣的CMS時,可能會導致您的主鏈接樣式比按鈕文本顏色更容易出現問題。嘗試這種較少干擾的方式為“默認”鏈接添加樣式:

          a[href]:not([class]) { 
           color: #999; 
           text-decoration: none; 
           transition: all ease-in-out .3s;
          }
          

          14、比率框

          要創建具有固有比率的框,您需要做的就是將頂部或底部填充應用于div:

          .container { 
           height: 0; 
           padding-bottom: 20%; 
           position: relative; 
          } 
          .container div { 
           border: 2px dashed #ddd; 
           height: 100%; 
           left: 0; 
           position: absolute; 
           top: 0; 
           width: 100%; 
          }
          

          使用20%進行填充使得框的高度等于其寬度的20%。無論視口的寬度如何,子div都將保持其縱橫比(100%/ 20%= 5:1)。

          如何提升你的CSS技能?掌握這20個css技巧即可[完整版]

          15、風格破碎的圖像

          這個技巧不是關于代碼縮減,而是關于細化設計細節的。破碎的圖像發生的原因有很多,要么不雅觀,要么導致混亂(只是一個空元素)。用這個小小的CSS創建更美觀的效果:

          img { 
           display: block; 
           font-family: Helvetica, Arial, sans-serif; 
           font-weight: 300; 
           height: auto; 
           line-height: 2; 
           position: relative; 
           text-align: center; 
           width: 100%; 
          } 
          img:before { 
           content: "We're sorry, the image below is missing :("; 
           display: block; 
           margin-bottom: 10px; 
          } 
          img:after { 
           content: "(url: " attr(src) ")"; 
           display: block; 
           font-size: 12px; 
          }
          

          16、使用rem進行全局大小調整;使用em進行局部大小調整

          在設置根目錄的基本字體大小后,例如html字體大小:15px;,可以將包含元素的字體大小設置為rem:

          article { 
           font-size: 1.25rem; 
          } 
          aside { 
           font-size: .9rem; 
          }
          

          然后將文本元素的字體大小設置為em

          h2 { 
           font-size: 2em; 
          } 
          p { 
           font-size: 1em; 
          }
          

          現在,每個包含的元素都變得分區化,更易于樣式化、更易于維護和靈活。

          web開發中該用 em 還是 rem 呢?

          如何提升你的CSS技能?掌握這20個css技巧即可[完整版]

          17、隱藏未靜音的自動播放視頻

          當您處理無法從源代碼輕松控制的內容時,這對于自定義用戶樣式表來說是一個很好的技巧。這個技巧將幫助您避免在加載頁面時自動播放視頻中的聲音干擾訪問者,并再次提供了精彩的:not()偽選擇器:

          video[autoplay]:not([muted]) { 
           display: none; 
          }
          

          18、靈活運用root類型

          響應布局中的字體大小應該能夠自動調整到視區,從而保存編寫媒體查詢的工作,以處理字體大小。可以使用:not和視區單位,根據視區高度和寬度計算字體大小:

          :root { 
           font-size: calc(1vw + 1vh + .5vmin); 
          }
          

          現在,您可以使用根em單位,該單位基于:not:

          body { 
           font: 1rem/1.6 sans-serif; 
          }
          

          結合上面的rem/em技巧以獲得更好的控制。有關管理Safari舊版本的提示,請參閱CSS Fix for iOS VH Unit Bug。

          19、在表單元素上設置字體大小,以獲得更好的移動體驗

          為了避免移動瀏覽器(iOS Safari等)在點擊<select>下拉列表時放大HTML表單元素,請在添加font-size樣式:

          input[type="text"], 
          input[type="number"], 
          select, 
          textarea { 
           font-size: 16px; 
          }
          

          20、CSS變量

          最后,最強大的CSS級別來自于CSS變量,它允許您聲明一組公共屬性值,這些值可以通過樣式表中任何位置的關鍵字重用。你可能有一套顏色在整個項目中使用,以保持一致性。在CSS中反復重復這些顏色值不僅是件煩人的事情,而且還容易出錯。如果某個顏色在某個時刻需要改變,你就不得不去尋找和替換,這是不可靠或不快速的,當為最終用戶構建產品時,變量使得定制變得容易得多。例如:

          如何提升你的CSS技能?掌握這20個css技巧即可[完整版]

          :root { 
           --main-color: #06c; 
           --accent-color: #999; 
          } 
           
          h1, h2, h3 { 
           color: var(--main-color); 
          } 
          a[href]:not([class]), 
          p, 
          footer span{ 
           color: var(--accent-color); 
          }
          

          公告

          喜歡小編的點擊關注,了解更多知識!

          何保持頁面樣式基本不變的前提下將HTML頁面導出為PDF,下面提供一些示例代碼,純屬個人原創,如對你有幫助請記得加關注、加收藏、點贊、轉發、分享~謝謝~~

          • 基本思路:保持頁面樣式基本不變,使用 `html2canvas` 將頁面轉換為圖片,然后再通過 `jspdf` 將圖片分頁導出為PDF文件(中間會遇到圖片或文字等內容在分頁處被切割開的問題,如何解決了?詳見末尾干貨)
          • 上基礎代碼:下面為項目中實際代碼截取
          <div>
              <!-- 要打印的內容區 -->
              <div ref="contentRef">
                  <div class="print-item print-out-flow">這是脫離文檔流的內容區域</div>
                  <div class="print-item">這是一行內容,也是最小葉子元素內容</div>
              </div>
              <!-- 打印內容容器 -->
              <div ref="printContainerRef" class="print-container"></div>
          </div>
          /**
            * 1.使用一個隱藏div裝載有滾動條的div.innerHTML
            * 2.隱藏div使用position: absolute, z-index: -999, left: -9999px, width: 900px 控制讓用戶無感知
            * 3.根據需要覆寫隱藏div內html樣式(例如textarea多行顯示有問題, 可以新增一個隱藏的div
            *    包裹textarea的綁定值, 然后在打印樣式中覆寫樣式, 隱藏textarea并顯示對應div)
            */
          handleExport() {
             // 下面是VUE組件內獲取DOM元素代碼,將內容放置到打印區(定義的隱藏DIV)中
              const contentRef = this.$refs.contentRef as HTMLElement;
              const printContainerRef = this.$refs.printContainerRef as HTMLElement;
              // 打印區的需額外處理絕對定位值, 調整使得第一個元素的.top值為0, 以便于頁面計算
              printContainerRef.innerHTML = contentRef.innerHTML;	
              
              // 所有葉子div元素加上 print-item 樣式名, 脫離文檔流的額外添加 print-out-flow
              handlePrintItem(printContainerRef);  // 解決多頁內容可能被切割問題
              
              html2canvas(printContainerRef, {allowTaint: false, useCORS: true}).then((canvas: any) => {
                const contentHeight = canvas.height;
                const contentWidth = canvas.width;
                // pdf每頁顯示的內容高度
                const pageHeight = contentWidth / 595.28 * 841.89;
                // 未生成pdf的頁面高度
                let offsetHeight = contentHeight;
                // 頁面偏移值
                let position = 0;
                // a4紙的尺寸[595.28, 841.89], canvas圖片按a4紙大小縮放后的寬高
                const imgWidth = 595.28;
                const imgHeight = 595.28 / contentWidth * contentHeight;
          
                const dataURL = canvas.toDataURL('image/jpeg', 1.0);
                const doc = new jsPDF('p', 'pt', 'a4');
          
                if (offsetHeight < pageHeight) {
                  doc.addImage(dataURL, 'JPEG', 0, 0, imgWidth, imgHeight);
                } else {
                  while (offsetHeight > 0) {
                    doc.addImage(dataURL, 'JPEG', 0, position, imgWidth, imgHeight);
                    offsetHeight -= pageHeight;
                    position -= 841.89;
          
                    if (offsetHeight > 0) {
                      doc.addPage();
                    }
                  }
                }
          
                doc.save(this.generateReportFileName());
                printContainerRef.innerHTML = '';
              });
          }

          上干貨代碼:上面分頁導出PDF可能網上能看到類型代碼,但絕對找不到下面的代碼,純手搓解決分頁元素被切開問題(思路:獲取自身定位,如自己剛好在被分頁處,則加上一定的margin-top值將內容向下移)

          /** 
           * 處理打印元素項, 修復分頁后被切割的元素
           * @param printContainerRef 打印內容div容器
           * @param itemClassName 打印最小元素標識類名
           * @param outFlowClassName 脫離文檔流的元素標識類名
           */
          export function handlePrintItem(
            printContainerRef: HTMLElement,
            itemClassName: string = 'print-item',
            outFlowClassName: string = 'print-out-flow'
          ): void {
            const rootClientRect = printContainerRef.getBoundingClientRect();
            // 初始化頁面相關數據
            const totalHeight = rootClientRect.height;  // 內容總高度
            const a4PageHeight = (printContainerRef.clientWidth / 595.28) * 841.89; // a4紙高度
            let pageNum = Math.ceil(totalHeight / a4PageHeight);  // 總頁數
            let addPageHeight = 0;  // 修正被分割元素而增加的頁面高度總和
            let currentPage = 1;  // 當前正在處理切割的頁面
            const splitItemObj: { [key: number]: HTMLElement[] } = {};  // 內容中各頁被切割元素存儲對象
          
            const printItemNodes: NodeListOf<HTMLElement> = printContainerRef.querySelectorAll(`.${itemClassName}`);
            for (let item of printItemNodes) {
              // 如果當前頁已經是最后一頁, 則中斷判斷
              if (currentPage >= pageNum) {
                break;
              }
          
              // 獲取元素絕對定位數據
              const clientRect = item.getBoundingClientRect();
              let top = clientRect.top;
              const selfHeight = clientRect.height;
              // 如果當前元素距離頂部高度大于當前頁面頁腳高度, 則開始判斷下一頁頁腳被切割元素
              if (top > currentPage * a4PageHeight) {
                // 換頁前修正上一頁被切割元素
                addPageHeight += fixSplitItems(currentPage, a4PageHeight, splitItemObj[currentPage], outFlowClassName);
                pageNum = Math.ceil((totalHeight + addPageHeight) / a4PageHeight);
                top = item.getBoundingClientRect().top;
                currentPage++;
              }
              // 如果元素剛好處于兩頁之間, 則記錄該元素
              if (top > (currentPage - 1) * a4PageHeight && top < currentPage * a4PageHeight && top + selfHeight > currentPage * a4PageHeight) {
                if (!splitItemObj[currentPage]) {
                  splitItemObj[currentPage] = [];
                }
                splitItemObj[currentPage].unshift(item);
                // 如果當前元素是最后一個元素, 則直接處理切割元素, 否則交由處理下一頁元素時再處理切割
                if (item === printItemNodes[printItemNodes.length - 1]) {
                  fixSplitItems(currentPage, a4PageHeight, splitItemObj[currentPage], outFlowClassName);
                }
              }
            }
          }
          
          /**
            * 修復當前頁所有被切割元素
            * @param currentPage 當前頁
            * @param pageHeight 每頁高度
            * @param splitElementItems 當前被切割元素數組
            * @param outFlowClassName 脫離文檔流的樣式類名
            */
          function fixSplitItems(
            currentPage: number,
            pageHeight: number,
            splitElementItems: HTMLElement[],
            outFlowClassName: string
          ): number {
            if (!splitElementItems || !splitElementItems.length) {
              return 0;
            }
          
            const yMargin = 5;  // y方向距離頁眉的距離
            const splitItemsMinTop = getSplitItemsMinTop(splitElementItems);
            if (!splitItemsMinTop) {
              return 0;
            }
          
            let fixHeight = currentPage * pageHeight - splitItemsMinTop + yMargin;
            const outFlowElement = splitElementItems.find((item) => item.classList.contains(outFlowClassName));
            if (outFlowElement && outFlowElement.parentElement) {
              const parentPreviousElement = outFlowElement.parentElement.previousElementSibling as HTMLElement;
              fixHeight += getMarinTopNum(parentPreviousElement, outFlowElement.parentElement);
              outFlowElement.parentElement.style.marginTop = `${fixHeight}px`;
              return fixHeight;
            }
          
            splitElementItems.forEach((splitElement) => {
              splitElement.style.marginTop = `${fixHeight}px`;
            });
            return fixHeight;
          }
          
          /**
            * 獲取被切割元素數組中最小高度值(如一行有多個元素被切割,則選出距離頂部最小的高度值)
            * @param splitElementItems 當前被切割元素數組
            */
          function getSplitItemsMinTop(
            splitElementItems: HTMLElement[]
          ): number | undefined {
            // 獲取元素中最小top值作為基準進行修正
            let minTop: number | undefined;
            let minElement: HTMLElement | undefined;
            splitElementItems.forEach((splitElement) => {
              let top = splitElement.getBoundingClientRect().top;
              if (minTop) {
                minTop = top < minTop ? top : minTop;
                minElement = top < minTop ? splitElement : minElement;
              } else {
                minTop = top;
                minElement = splitElement;
              }
            });
          
            // 修正當前節點及其前面同層級節點的margin值
            if (minTop && minElement) {
              const previousElement = splitElementItems[splitElementItems.length - 1].previousElementSibling as HTMLElement;
              minTop -= getMarinTopNum(previousElement, minElement);
            }
            return minTop;
          }
          
          /**
            * 通過前一個兄弟元素和元素自身的位置確認一個距離頂部高度修正值
            * @param previousElement 前一個兄弟元素
            * @param curElement 當前元素
            */
          function getMarinTopNum(previousElement: HTMLElement, curElement: HTMLElement): number {
            let preMarginNum = 0;
            let curMarginNum = 0;
            if (previousElement) {
              // 獲取外聯樣式需要getComputedStyle(), 直接.style時對象的值都為空
              const previousMarginBottom = window.getComputedStyle(previousElement).marginBottom;
              preMarginNum = previousMarginBottom ? Number(previousMarginBottom.replace('px', '')) : 0;
            }
            const marginTop = window.getComputedStyle(curElement).marginTop;
            curMarginNum = marginTop ? Number(marginTop.replace('px', '')) : 0;
            return preMarginNum > curMarginNum ? preMarginNum : curMarginNum;
          }

          以上純原創!歡迎加關注、加收藏、點贊、轉發、分享(代碼閑聊站)~


          主站蜘蛛池模板: 国产a∨精品一区二区三区不卡| 国产麻豆精品一区二区三区v视界| 无码精品不卡一区二区三区| 精品国产一区二区三区无码| 国产乱码精品一区二区三区中| 无码福利一区二区三区| 精品少妇ay一区二区三区| 国产精品无码亚洲一区二区三区| 国产精品无码一区二区在线 | 精品国产一区二区三区AV性色| 午夜肉伦伦影院久久精品免费看国产一区二区三区 | 无码中文字幕一区二区三区| 国产成人高清亚洲一区91| 嫩B人妻精品一区二区三区| 久久无码AV一区二区三区| 久久精品日韩一区国产二区| 亚洲AV无码一区二区三区在线观看| 最美女人体内射精一区二区| 99久久精品午夜一区二区| 深夜福利一区二区| 色国产精品一区在线观看| 福利一区二区在线| 无码日韩精品一区二区三区免费 | 亚洲福利视频一区二区三区| 精品视频一区二区| 一区二区三区在线|欧| 日本在线电影一区二区三区| 亚洲AV无码一区二区二三区入口 | 能在线观看的一区二区三区| 国产suv精品一区二区33| 成人精品一区二区三区电影| 国产在线精品一区二区中文 | 国产一区在线视频| 无码人妻av一区二区三区蜜臀| 久久无码人妻精品一区二区三区| 午夜影院一区二区| 日韩精品成人一区二区三区| 无码国产精品一区二区高潮| 人体内射精一区二区三区| 合区精品久久久中文字幕一区| 国产精品香蕉在线一区|