• <span id="ycodp"></span>
    <span id="ycodp"><small id="ycodp"></small></span>
    1. <label id="ycodp"></label>
      <rt id="ycodp"><tr id="ycodp"><strike id="ycodp"></strike></tr></rt>
      <i id="ycodp"><strong id="ycodp"><ul id="ycodp"></ul></strong></i>
    2. 幫助中心

      這里有最新的使用文檔和教程

      < 返回

      JS讓瀏覽器支持<style scoped>

      2023-04-20 19:11 作者:31IDC 閱讀量:1053 所屬分類:Linux系統

      【JS 】讓瀏覽器支持<style scoped>

      1. HTML style scoped 屬性

      今天無意中發現居然還有這么一個神仙屬性 HTML style scoped 屬性
      他的作用主要是將 style的作用域控制在他自身的父元素之內。
      例如:

      <div>
        <style type="text/css" scoped>
          h1 {color:red;}
          p {color:blue;}
        </style>
        <h1>這個標題是紅色的</h1>
        <p>這個段落是藍色的。</p>
      </div>
      
      <h1>這個標題是黑色的</h1>
      <p>這個段落是黑色的。</p>
      

      以上代碼中style中的樣式只能作用于第一個div內的元素。
      這樣一個功能應用在目前公司老項目中非常nice(asp.net+mvc,導入部分頁就不會影響當前頁其他元素了)
      但是可惜,除了火狐,其他瀏覽器都不支持!!!

       
       

      所以我決定自己實現一個

       

      2. 思路

      1. 判斷瀏覽器是否支持scoped
      2. 找到頁面中所有帶有scoped屬性的style元素,給其父元素添加一個屬性
      3. 修改style中的所有css選擇器,加上屬性前綴
      4. 監聽dom變化,處理動態創建的<style scoped>

      3. 編碼

      1. 判斷瀏覽器是否支持scoped

      if (document.createElement("STYLE").scoped !== undefined) {
          return;
      }
      

      2. 找到頁面中所有帶有scoped屬性的style元素,給其父元素添加一個屬性

      [...document.getElementsByTagName('style')].forEach(x => updateStyle(x));
      /**
       * 處理 <style> 標簽
       * @param style dom
       */
      function updateStyle(style) {
          if (!style
              || style.parentElement == null
              || style.parentElement == document.head
              || style.parentElement == document.body
              || !style.hasAttribute("scoped")
              || style.scoped === true) {
              return;
          }
          style.scoped = true; // 防止重復處理
          const scope = ("_" + (Math.random() * 100000000).toString("36")).replace('.', '');
          style.parentElement.setAttribute(scope, '');
          // 處理css
      }
      

      3. 修改style中的所有css選擇器,加上屬性前綴

      /**
       * 為選擇器添加范圍前綴scope
       * @param {String} selector css選擇器
       * @param {String} scope css范圍前綴
       * @returns 返回修改后的css選擇器
       */
      function updateSelector(selector, scope) {
          return selector.split(",").map(x => x.replace(/((?<=^\s*)\s|^)([\S])/, "$1" + scope + " $2")).join(",");
      }
      /**
       * 將css代碼中所有選擇器都加上范圍前綴scope
       * @param {String} css css代碼
       * @param {String} scope css范圍前綴
       * @returns 返回修改后的css代碼
       */
      function updateCss(css, scope) {
          // css = css.replace(/[\n\r\s]+/g, " "); // 去掉多余的空格和回車
          css = css.replace(/("[^"]*")|('[^']*')/g, x => x.charAt(0) + encodeURIComponent(x.slice(1, -1)) + x.charAt(0)); // 去字符串干擾 
          css = css.replace(/[^{}]+{/g, x => updateSelector(x, scope));
          css = css.replace(/("[^"]*")|('[^']*')/g, x => x.charAt(0) + decodeURIComponent(x.slice(1, -1)) + x.charAt(0)); // 還原字符串 
          return css;
      }
      

      用正則處理還是會有一些問題的,不過勝在代碼簡潔,實際使用中只要注意避開就好了,比如下面這段css就會有問題

      @keyframes show {
          100% {
              opacity: 1;
          }
      }
      

      4. 監聽dom變化,處理動態創建的<style scoped>

      // 當觀察到變動時執行的回調函數
      const callback = function (mutationsList) {
          if (mutationsList.length == 0) {
              return;
          }
          for (const mutation of mutationsList) {
              for (const node of mutation.addedNodes) {
                  if (node.nodeName === "STYLE") {
                      updateStyle(node);
                  }
              }
          }
      };
      // 創建一個觀察器實例并傳入回調函數
      const observer = new MutationObserver(callback);
      const config = { childList: true, subtree: true };
      observer.observe(document, config);
      // MutationObserver 是異步的,回調時間不可控,所以需要設置一個輪詢
      setInterval(() => callback(observer.takeRecords()), 100);
      

      5. 完整代碼

      
      // style scoped
      (() => {
          // 檢測原生 style是否支持 scoped 
          if (document.createElement("STYLE").scoped !== undefined) {
              return;
          }
          document.createElement("STYLE").__proto__.scoped = false;
      
          /**
           * 為選擇器添加范圍前綴scope
           * @param {String} selector css選擇器
           * @param {String} scope css范圍前綴
           * @returns 返回修改后的css選擇器
           */
          function updateSelector(selector, scope) {
              return selector.split(",").map(x => x.replace(/((?<=^\s*)\s|^)([\S])/, "$1" + scope + " $2")).join(",");
          }
      
          /**
           * 將css代碼中所有選擇器都加上范圍前綴scope
           * @param {String} css css代碼
           * @param {String} scope css范圍前綴
           * @returns 返回修改后的css代碼
           */
          function updateCss(css, scope) {
              // css = css.replace(/[\n\r\s]+/g, " "); // 去掉多余的空格和回車
              css = css.replace(/("[^"]*")|('[^']*')/g, x => x.charAt(0) + encodeURIComponent(x.slice(1, -1)) + x.charAt(0)); // 去字符串干擾 
              css = css.replace(/[^{}]+{/g, x => updateSelector(x, scope));
              css = css.replace(/("[^"]*")|('[^']*')/g, x => x.charAt(0) + decodeURIComponent(x.slice(1, -1)) + x.charAt(0)); // 還原字符串 
              return css;
          }
      
          /**
           * 處理 <style> 標簽
           * @param style dom
           */
          function updateStyle(style) {
              if (!style
                  || style.parentElement == null
                  || style.parentElement == document.head
                  || style.parentElement == document.body
                  || !style.hasAttribute("scoped")
                  || style.scoped === true) {
                  return;
              }
              style.scoped = true; // 防止重復處理
      
              const scope = ("_" + (Math.random() * 100000000).toString("36")).replace(&        

      31IDC - 12 年深耕海外 IDC 高端資源

      主站蜘蛛池模板: 亚洲人成伊人成综合网久久| 久久久久亚洲AV综合波多野结衣| 亚洲综合av一区二区三区| 婷婷综合缴情亚洲狠狠尤物| 国产综合成人色产三级高清在线精品发布 | 老色鬼久久亚洲AV综合| 久久久久久久综合| 亚洲综合久久1区2区3区| 国产一区二区三区亚洲综合 | 久久综合狠狠色综合伊人| 色噜噜狠狠色综合久| 亚洲情综合五月天| 狠狠爱天天综合色欲网| 亚洲精品第一综合99久久| 久久93精品国产91久久综合| 一本一道久久综合狠狠老| 久久久亚洲裙底偷窥综合| 久久国产综合精品五月天| 天天综合亚洲色在线精品| 人人狠狠综合久久亚洲88| 婷婷久久综合九色综合绿巨人 | 欧美日韩综合一区二区三区| 91精品婷婷国产综合久久| 激情五月激情综合网| 亚洲综合另类小说色区色噜噜| 国产91色综合久久免费| 久久综合丁香激情久久| 亚洲综合无码精品一区二区三区| 天天做天天爱天天综合网| 六月婷婷激情综合| 成人精品综合免费视频| 色视频综合无码一区二区三区| 色偷偷91综合久久噜噜| 国产亚洲综合精品一区二区三区| 国产综合视频在线观看一区| 天天综合网网欲色| 国产成人综合久久久久久| 久久综合综合久久狠狠狠97色88 | 99久久综合狠狠综合久久aⅴ| 久久综合亚洲色HEZYO社区| 色综合久久中文字幕网|