整合營銷服務商

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

          免費咨詢熱線:

          關于html元素的css-定位

          理解定位,首先要了解文檔流是什么。

          文件流:指盒子按照html標簽編寫的順序,從上到下,從左到右排列,塊元素占一行,從左到右排列,每一行元素在一行中從左到右排列,先寫的先,后寫的排在后面,每個盒子都占據自己的位置。

          位置可以使方框脫離文檔流,就好比將元素分割成幾層,沒有位置的在一層,定位在沒有定位的上面一層。

          你可以用Z-index設置等級,Z-index越大,顯示的就越向前。在創建網頁彈框時,通常將其設置為最大。

          我們可以使用css的position屬性來設置元素的定位類型,postion的設置項如下:

          relative生成相對定位元素,元素所占據的文檔流的位置保留,元素本身相對自身原位置進行偏移。

          absolute生成絕對定位元素,元素脫離文檔流,不占據文檔流的位置,可以理解為漂浮在文檔流的上方,相對于上一個設置了定位的父級元素來進行定位,如果找不到,則相對于body元素進行定位。

          fixed生成固定定位元素,元素脫離文檔流,不占據文檔流的位置,可以理解為漂浮在文檔流的上方,相對于瀏覽器窗口進行定位。

          static默認值,沒有定位,元素出現在正常的文檔流中,相當于取消定位屬性或者不設置定位屬性。

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <meta name="viewport" content="width=device-width, initial-scale=1.0">
              <meta http-equiv="X-UA-Compatible" content="ie=edge">
              <title>元素的定位</title>
              <style>
                  .con1,.con2,.con3,.con4,.con5{
                      border: 1px solid #000;
                      margin: 10px;
                      height: 400px;
                  }
                  /* 這個div屬于它下屬div的父元素,如果沒有設置浮動,當下屬div設置absolute時,相對于body偏移*/
                  .con3{
                      position: relative;  
                  }
                  .no_pos_1,.no_pos_2{
                      height: 100px;
                      width: 400px;
                      margin :10px;
                      font-size: 16px;
                  }
                  .no_pos_1{
                      background-color: red;
                  }
                  .no_pos_2{
                      background-color: gold;
                  }
          
                  .relative_1,.relative_2{
                      height: 100px;
                      width: 400px;
                      margin-top :10px;
                      font-size: 16px;
                  }
                  .relative_1{
                      background-color: red;
                      position: relative;
                      left: 50px;
                      top: 50px;
                  }
                  .relative_2{
                      background-color: gold;
                  }
          
                  .absolute_1,.absolute_2{
                      height: 100px;
                      width: 400px;
                      margin-top :10px;
                      font-size: 16px;
                  }
                  .absolute_1{
                      background-color: red;
                      position: absolute;
                      left: 50px;
                      top: 50px;
                  }
                  .absolute_2{
                      background-color: gold;
                  }
                  .fixed_1,.fixed_2{
                      height: 100px;
                      width: 400px;
                      margin-top :10px;
                      font-size: 16px;
                  }
                  .fixed_1{
                      background-color: red;
                      position: fixed;
                      left: 50%;
                      margin-left: -200px;  /* 設置水平垂直居中*/
                      top: 50%;
                      margin-top: -50px;
                      z-index: 9999;   /*  彈框一般設置足夠大的值 */
                  }
                  
                   /* 彈框效果 */ 
                  .mask{
                      position: fixed;
                      width: 100%;
                      height: 100%;
                      background-color: black;
                      opacity: 0.6;      /* 設置透明度 */
                      z-index: 9998;   /* 一般比彈框設置的值小1*/
                  }
                  .fixed_2{
                      background-color: gold;
                  }
                  .static_1{
                      height: 100px;
                      width: 400px;
                      margin-top :10px;
                      background-color: gold;
                      position: static;
                  }
          </style>
          </head>
          <body>
              <div class="mask">
          
              </div>
              <div class="con1">
                  <div class="no_pos_1">
                      沒有使用定位
                  </div>
          
                  <div class="no_pos_2">
                      沒有使用定位
                  </div>
              </div>
              <div class="con2">
                  <div class="relative_1">
                      relative 生成相對定位元素,元素所占據的文檔流的位置保留,元素本身相對自身原位置進行偏移
                  </div>
                  <div class="relative_2">
                      
                  </div>
              </div>
              <div class="con3">
                  <div class="absolute_1">
                      absolute 生成絕對定位元素,元素脫離文檔流,不占據文檔流的位置,可以理解為漂浮在文檔流的上方,相對于上一個設置了定位的父級元素來進行定位,如果找不到,則相對于body元素進行定位
                  </div>
                  <div class="absolute_2">
                      
                  </div>
              </div>
              <div class="con4">
                  <div class="fixed_1">
                      fixed 生成固定定位元素,元素脫離文檔流,不占據文檔流的位置,可以理解為漂浮在文檔流的上方,相對于瀏覽器窗口進行定位。
                  </div>
                  
                  <div class="fixed_2">
          
                  </div>
              </div>
              <div class="con5">
                  <div class="static_1">
                      static 默認值,沒有定位,元素出現在正常的文檔流中,相當于取消定位屬性或者不設置定位屬性。
                  </div>
              </div>
          </body>
          </html>123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143復制代碼類型:[html]

          制作一個彈框效果:

          「鏈接」

          HP是世界上最好的語言,這是一個老梗。

          有不少學習PHP的程序員后來去做了前端開發,畢竟近些年前端開發還是蠻吃香的。

          學習PHP不僅僅要學習html,而且還要學習CSS。

          CSS是萬維網聯盟在 HTML 4.0 之外提出,目的是為了讓CSS完成樣式與內容的分離。

          那么,CSS如何入門呢?w3cschool在這里分享幾個方法:

          0、研究w3cschool CSS教程

          w3cschool官方本身就有CSS教程,我們看教程的目的主要還是要了解CSS到底是干什么用的。

          其實,用一句簡單的話來說,改變我們看的網頁的樣子.。

          1、CSS微課游戲化編程體驗

          w3cschool新開發了CSS微課,這可能是很多程序員小伙伴所需要的。

          CSS直接抓住了CSS教程中比較核心的一些概念和語法,并且有實戰的訓練習題。

          其內容包括了CSS基礎、CSS文本樣式、CSS屬性、CSS定位和布局,讓你系統、立體地全面認識CSS。

          CSS微課實現了游戲化的編程體驗,關卡是循序漸進的,這迫使你不能跳躍而忽略一些重要的編程知識。

          其中,習題類型包含了判斷題、選擇題、實戰訓練題。

          理論離不開實戰,CSS微課做到了例子多,概括技術全面。

          當你可以通關的時候,你已經對CSS算是有一個比較深刻的認識,也掌握了一定的CSS編程技能。

          2、CSS看什么書呢?

          學編程一定要讓編程本身變得有趣,所以大可以先玩編程。

          用CSS微課學習是一種有趣化的方法。

          另外,閱讀《css禪意花園》,就當成一本故事書看,隨便翻翻你會發現css確實很好玩的。

          文來源于:程序員成長指北;作者:海闊_天空

          原文:https://juejin.cn/post/7173596154297810957

          如有侵權,聯系刪除


          前言


          如何快速定位線上bug,是多數開發者都會遇到的難題


          web-see[1] 前端監控方案,提供了 前端錄屏+定位源碼 方式,讓bug無處藏身


          這是前端監控的第二篇,該篇講解如何實現錯誤還原功能,第一篇 從0到1搭建前端監控平臺,面試必備的亮點項目總結(已開源)沒有看過的小伙伴,建議先了解下


          最終效果


          在監控后臺,通過報錯信息列表,可以查看具體報錯的源碼,以及報錯時的錄屏回放


          效果演示:


          錄屏記錄了用戶的所有操作,紅色的線代表了鼠標的移動軌跡


          定位源碼


          前端項目發布上線,代碼一般都會進行壓縮、混淆、甚至加密,當線上代碼報錯時,很難定位到具體的源碼


          SourceMap 完美解決了代碼反解的問題,項目在打包時,除了生成最終 XXX.js 文件外,還會額外生成一個 XXX.js.map 的文件


          .map 文件里包含了原始代碼及其映射信息,可以利用它反解出報錯信息的源碼


          SourceMap 文件


          先了解下 SourceMap 的基本內容


          例如 app.a2a3ceec.js 代碼如下:


          var add=function(x, y){return x+y;};
          //# sourceMappingURL=app.a2a3ceec.js.map
          復制代碼


          其中 sourceMappingURL 用來說明該文件對應的map文件


          對應的 app.a2a3ceec.js.map 代碼如下:


          {
            version : 3, // SourceMap標準版本,最新的為3
            file: "js/app.a2a3ceec.js", // 轉換后的文件名
            sourceRoot : "", // 轉換前的文件所在目錄,如果與轉換前的文件在同一目錄,該項為空
            sources: [ // 轉換前的文件,該項是一個數組,表示可能存在多個文件合并
              "webpack://web-see-demo/./src/App.vue",
              "webpack://web-see-demo/./src/main.js"
            ], 
            names: [], // 轉換前的所有變量名和屬性名
            sourcesContent: [ // 原始文件內容
              "const add = (x,y) => {\n  return x+y;\n}"
            ],
            // 所有映射點
            mappings: "AAAA,IAAM,GAAG,GAAG,UAAC,CAAQ,EAAC,CAAQ;IAC5B,OAAO,CAAC,GAAC,CAAC,CAAC;AACb,CAAC,CAAA"
          }
          復制代碼


          其中 sources 和 sourcesContent 是關鍵字段,下文的還原示例中將用到


          source-map-js 庫


          代碼還原,這里主要使用 source-map-js[3] 庫,下面介紹下如何使用


          示例代碼:


          import sourceMap from 'source-map-js';
          
          /**
          * findCodeBySourceMap用于獲取map文件對應的源代碼
          * @param { string } fileName .map文件名稱
          * @param { number } line 發生錯誤的行號
          * @param { number } column 發生錯誤的列號
          * @param { function } 回調函數,返回對應的源碼
          */
          const findCodeBySourceMap = async ({ fileName, line, column }, callback) => {
            // loadSourceMap 用于獲取服務器上 .map 的文件內容
            let sourceData = await loadSourceMap(fileName);
            let { sourcesContent, sources } = sourceData;
            // SourceMapConsumer實例表示一個已解析的源映射
            // 可以通過在生成的源中給它一個文件位置來查詢有關原始文件位置的信息
            let consumer = await new sourceMap.SourceMapConsumer(sourceData);
            // 輸入錯誤的發生行和列,可以得到源碼對應原始文件、行和列信息
            let result = consumer.originalPositionFor({
              line: Number(line),
              column: Number(column)
            });
            // 從sourcesContent得到具體的源碼信息
            let code = sourcesContent[sources.indexOf(result.source)];
            ……
            callback(code)
          復制代碼


          本小節的代碼倉庫[4]


          source-map 的還原流程:


          1、從服務器獲取指定.map 的文件內容


          2、new 一個 SourceMapConsumer 的實例,表示一個已解析的源映射,給它一個文件位置來查詢有關原始文件位置的信息


          3、輸入報錯發生的行和列,可以得到源碼對應原始文件名、行和列信息


          4、從源文件的 sourcesContent 字段中,獲取對應的源碼信息


          接下來的重點就變為:如何獲取報錯發生的原始文件名、行和列信息


          error-stack-parser 庫


          通過第一篇文章的介紹,我們知道可以通過多種方式來捕獲報錯


          比如 error事件、unhandledrejection事件、vue 中通過Vue.config.errorHander、react中通過componentDidCatch


          為了消除各瀏覽器的差異,使用 error-stack-parser[5] 庫來提取給定錯誤的原始文件名、行和列信息


          示例代碼:


          import ErrorStackParser from 'error-stack-parser';
          
          ErrorStackParser.parse(new Error('BOOM'));
          
          // 返回值 StackFrame 堆棧列表
          [
              StackFrame({functionName: 'foo', args: [], fileName: 'path/to/file.js', lineNumber: 35, columnNumber: 79, isNative: false, isEval: false}),
              StackFrame({functionName: 'Bar', fileName: 'https://cdn.somewherefast.com/utils.min.js', lineNumber: 1, columnNumber: 832, isNative: false, isEval: false, isConstructor: true}),
              StackFrame(... and so on ...)
          ]
          復制代碼


          這里簡單說明下 JS 堆棧列表


          堆棧示例:


          function c() {
            try {
              var bar = baz;
              throw new Error()
            } catch (e) {
              console.log(e.stack);
            }
          }
          function b() {
            c();
          }
          function a() {
            b();
          }
          a();
          復制代碼


          上述代碼中會在執行到 c 函數的時候報錯,調用棧為 a -> b -> c,如下圖所示:



          一般我們只需要定位到 c 函數的堆棧信息,所以使用 error-stack-parser 庫的時候,只取 StackFrame 數組中的第一個元素


          最終代碼:


          import ErrorStackParser from 'error-stack-parser';
          
          // 取StackFrame數組中的第一個元素
          let stackFrame = ErrorStackParser.parse(error)[0];
          // 獲取對應的原始文件名、行和列信息,并上報
          let { fileName, columnNumber, lineNumber } = stackFrame;
          復制代碼


          示例演示


          下載 web-see-demo[6] 安裝并運行


          1)點擊 js錯誤 按鈕,會執行 HomeView.vue 文件中的 codeErr 方法


          codeErr的源碼為:



          codeErr.png


          2)Vue.config.errorHander中捕獲到報錯信息為:



          length.png


          3)使用 ErrorStackParser.parse 解析后的stackFrame為:



          stackFrame.png


          4)經過 consumer.originalPositionFor 還原后的 result 結果為:



          result.png


          5)最終拿到的源碼:



          code.png


          流程總結



          sourcemap.png


          如上圖所示,定位源碼流程總結:


          1、項目中引入監控 SDK,打包后將js文件發布到服務器上


          2、將 .map 文件放到指定的地址,統一存儲


          3、當線上代碼報錯時,利用 error-stack-parser 獲取具體原始文件名、行和列信息,并上報


          4、利用 source-map 從 .map 文件中得到對應的源碼并展示


          前端錄屏


          web-see 監控通過 rrweb[7] 提供了前端錄屏的功能


          rrweb 使用


          先介紹下在vue中如何使用


          錄制示例:


          import { record } from 'rrweb';
          // events存儲錄屏信息
          let events = [];
          // record 用于記錄 `DOM` 中的所有變更
          rrweb.record({
            emit(event, isCheckout) {
              // isCheckout 是一個標識,告訴你重新制作了快照
              if (isCheckout) {
                events.push([]);
              }
              events.push(event);
            },
            recordCanvas: true, // 記錄 canvas 內容
            checkoutEveryNms: 10 * 1000, // 每10s重新制作快照
            checkoutEveryNth: 200, // 每 200 個 event 重新制作快照
          });
          復制代碼


          播放示例:


          <template>
            <div ref='player'>
            </div>
          </template>
          <script>
          import rrwebPlayer from 'rrweb-player';
          import 'rrweb-player/dist/style.css';
          export default {
             mounted() {
               // 將記錄的變更按照對應的時間一一重放
               new rrwebPlayer(
                  {
                    target: this.$refs.player, // 回放所需要的HTML元素
                    data: { events }
                  },
                  {
                    UNSAFE_replayCanvas: true // 回放 canvas 內容
                  }
               )
             }
          }
          </script>
          復制代碼


          rrweb 原理淺析


          rrweb 主要由 rrweb 、 rrweb-player 和 rrweb-snapshot 三個庫組成:


          1)rrweb:提供了 record 和 replay 兩個方法;record 方法用來記錄頁面上 DOM 的變化,replay 方法支持根據時間戳去還原 DOM 的變化


          2)rrweb-player:基于 svelte 模板實現,為 rrweb 提供了回放的 GUI 工具,支持暫停、倍速播放、拖拽時間軸等功能。內部調用了 rrweb 的提供的 replay 等方法


          3)rrweb-snapshot:包括 snapshot 和 rebuilding 兩大特性,snapshot 用來序列化 DOM 為增量快照,rebuilding 負責將增量快照還原為 DOM


          rrweb 整體流程:


          1)rrweb 在錄制時會首先進行首屏 DOM 快照,遍歷整個頁面的 DOM 樹,轉換為 JSON 結構數據,使用增量快照的處理方式,通過 mutationObserver 獲取 DOM 增量變化,同步轉換為 JSON 數據進行存儲


          2)整個錄制的過程會生成 unique id,來確定增量數據所對應的 DOM 節點,通過 timestamp 保證回放順序。


          3) 回放時,會創建一個 iframe 作為承載事件回放的容器,針對首屏 DOM 快照進行重建,在遍歷 JSON 的同時,根據序列化后的節點數據構建出實際的 DOM 節點


          4)rrweb 可以監聽的用戶行為包括:鼠標移動,鼠標交互,頁面滾動,視窗變化、用戶輸入等,通過添加相應的監聽事件來實現


          壓縮數據


          如果一直錄屏,數據量是巨大的


          實測下來,錄制10s的時長,數據大小約為 8M 左右(頁面的不同復雜度、用戶不同操作的頻率都會造成大小不一樣)


          數據如果不經過壓縮,直接傳給后端,面對大量的用戶,需要非常高的帶寬做支持。還好,rrweb官方提供了數據壓縮函數[8]


          基于 packFn 的單數據壓縮,在錄制時可以作為 packFn 傳入


          rrweb.record({
            emit(event) {},
            packFn: rrweb.pack,
          });
          復制代碼


          回放時,需要傳入 rrweb.unpack 作為 unpackFn 傳入


          const replayer = new rrweb.Replayer(events, {
            unpackFn: rrweb.unpack,
          });
          復制代碼


          但是官方提供的壓縮方式,是對每個 event 數據單獨進行壓縮,壓縮比不高。實測下來,壓縮比在70%左右,比如原來 8M 的數據,壓縮后為 2.4M 左右


          官方更加推薦將多個 event 批量一次性壓縮,這樣壓縮效果更好


          web-see 內部使用 pako.js[9]、js-base64[10] 相結合的壓縮方式,實測下來,壓縮比為 85% 以上,原來 8M 的數據,壓縮后為 1.2M 左右


          壓縮代碼示例:


          import pako from 'pako';
          import { Base64 } from 'js-base64';
          
          // 壓縮
          export function zip(data) {
            if (!data) return data;
            // 判斷數據是否需要轉為JSON
            const dataJson = typeof data !== 'string' && typeof data !== 'number' ? JSON.stringify(data) : data;
            // 使用Base64.encode處理字符編碼,兼容中文
            const str = Base64.encode(dataJson);
            let binaryString = pako.gzip(str);
            let arr = Array.from(binaryString);
            let s = '';
            arr.forEach((item) => {
              s += String.fromCharCode(item);
            });
            return Base64.btoa(s);
          }
          復制代碼


          解壓代碼示例:


          import { Base64 } from 'js-base64';
          import pako from 'pako';
          
          // 解壓
          export function unzip(b64Data) {
            let strData = Base64.atob(b64Data);
            let charData = strData.split('').map(function (x) {
              return x.charCodeAt(0);
            });
            let binData = new Uint8Array(charData);
            let data = pako.ungzip(binData);
            // ↓切片處理數據,防止內存溢出報錯↓
            let str = '';
            const chunk = 8 * 1024;
            let i;
            for (i = 0; i < data.length / chunk; i++) {
              str += String.fromCharCode.apply(null, data.slice(i * chunk, (i + 1) * chunk));
            }
            str += String.fromCharCode.apply(null, data.slice(i * chunk));
            // ↑切片處理數據,防止內存溢出報錯↑
            const unzipStr = Base64.decode(str);
            let result = '';
            // 對象或數組進行JSON轉換
            try {
              result = JSON.parse(unzipStr);
            } catch (error) {
              if (/Unexpected token o in JSON at position 0/.test(error)) {
                // 如果沒有轉換成功,代表值為基本數據,直接賦值
                result = unzipStr;
              }
            }
            return result;
          }
          復制代碼


          何時上報錄屏數據


          一般關注的是,頁面報錯的時候用戶做了哪些操作,所以目前只把報錯前10s的錄屏上報到服務端


          如何只上報報錯時的錄屏信息呢 ?


          1)window上設置 hasError、recordScreenId 變量,hasError用來判斷某段時間代碼是否報錯;recordScreenId 用來記錄此次錄屏的id


          2)當頁面發出報錯需要上報時,判斷是否開啟了錄屏,如果開啟了,將 hasError 設為 true,同時將 window 上的 recordScreenId,存儲到此次上報信息的 data 中


          3)rrweb 設置10s重新制作快照的頻率,每次重置錄屏時,判斷 hasError 是否為 true(即這段時間內是否發生報錯),有的話將這次的錄屏信息上報,并重置錄屏信息和 recordScreenId,作為下次錄屏使用


          4)后臺報錯列表,從本次報錯報的data中取出 recordScreenId 來播放錄屏


          錄屏的代碼示例:


          handleScreen() {
           try {
            // 存儲錄屏信息
            let events = [];
            record({
              emit(event, isCheckout) {
                if (isCheckout) {
                  // 此段時間內發生錯誤,上報錄屏信息
                  if (_support.hasError) {
                    let recordScreenId = _support.recordScreenId;
                    // 重置recordScreenId,作為下次使用
                    _support.recordScreenId = generateUUID();
                    transportData.send({
                      type: EVENTTYPES.RECORDSCREEN,
                      recordScreenId,
                      time: getTimestamp(),
                      status: STATUS_CODE.OK,
                      events: zip(events)
                    });
                    events = [];
                    _support.hasError = false;
                  } else {
                    // 不上報,清空錄屏
                    events = [];
                    _support.recordScreenId = generateUUID();
                  }
                }
                events.push(event);
              },
              recordCanvas: true,
              // 默認每10s重新制作快照
              checkoutEveryNms: 1000 * options.recordScreentime
            });
          復制代碼


          遺留問題,在線求解


          按照官方的 canvas 配置,驗證下來,rrweb 還是不支持 canvas 的錄制,比如使用 echarts 畫圖,圖形區域的錄屏顯示是空白的


          官方配置[11] 如下:



          Canvas.png


          測試demo[12] 如下:



          echart.png


          錄屏回放,圖形這塊區域是空白的:



          canvas.gif


          主站蜘蛛池模板: 无码国产精品一区二区免费式直播| 国产高清精品一区| 国产a∨精品一区二区三区不卡| 国产一区二区内射最近更新| 麻豆国产一区二区在线观看| 国产av一区最新精品| 国产一区二区免费视频| 无码国产精品一区二区免费I6| 久久久不卡国产精品一区二区| 精品视频一区二区三三区四区| AA区一区二区三无码精片| 精品一区二区三区免费视频| 亚洲AV无码一区二区一二区| 日韩精品无码视频一区二区蜜桃| 中字幕一区二区三区乱码| 亚洲国产激情一区二区三区 | 国产免费一区二区三区VR| 免费视频精品一区二区三区| 免费视频精品一区二区| 中文字幕一区二区三区人妻少妇| 日本免费电影一区二区| 亚洲国产综合无码一区二区二三区 | 国产成人精品一区二三区在线观看| 日本一区二区不卡在线| 国产成人无码一区二区三区在线 | 国产伦精品一区二区三区女| 美女一区二区三区| 一区二区三区免费高清视频| 国产成人一区二区精品非洲| 韩国资源视频一区二区三区| 亚洲AV无码一区二区三区鸳鸯影院 | 中文日韩字幕一区在线观看| 日本在线观看一区二区三区| 国产日韩精品一区二区在线观看 | 国产另类ts人妖一区二区三区 | 免费看无码自慰一区二区| 欧美日韩国产免费一区二区三区 | 国产欧美色一区二区三区| 秋霞日韩一区二区三区在线观看| 国产乱人伦精品一区二区在线观看| 伊人久久一区二区三区无码|