整合營銷服務商

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

          免費咨詢熱線:

          前端-干貨分享:更牛逼的CSS管理方法-層(CSS Layers)

          用 CSS 最困難的部分之一是處理CSS的權重值,它可以決定到底哪條規則會最終被應用,尤其是如果你想在 Bootstrap 這樣的框架中覆蓋其已有樣式,更加顯得麻煩。不過隨著 CSS 層的引入,這一切都發生了變化。 這個新功能允許您創建自己的自定義 CSS 層,這是有史以來第一次確定所有 CSS 代碼權重的層次結構。 在本文中,我將剖析這對您意味著什么,它是如何工作的,以及您今天如何開始使用它。

          什么是層(Layers)

          創建您自己的自定義圖層是 CSS 的新功能,但圖層從一開始就存在于 CSS 中。 CSS 中有 3 個不同的層來管理所有樣式的工作方式。

          瀏覽器(也稱為用戶代理)樣式 - user agent style
          用戶樣式 - User Styles
          作者樣式 - Author Styles

          瀏覽器樣式是應用于瀏覽器的默認樣式。這就是為什么 Chrome 和 Safari 中的按鈕看起來不同的原因。在瀏覽器層中找到的樣式在瀏覽器之間是不同的,并且給每個瀏覽器一個獨特的外觀。

          下一層是用戶樣式,這并不是您真正需要擔心的事情。這些通常是用戶可以編寫并注入瀏覽器的自定義樣式,但瀏覽器不再真正支持這些樣式。用戶可能會更改一些瀏覽器設置,這些設置會向該圖層添加樣式,但在大多數情況下,可以完全忽略該層。

          最后,我們來到作者層。這是您最熟悉的層,因為您編寫的每一段 CSS 代碼都屬于這一層。

          這些層分開的原因是因為它可以很容易地覆蓋瀏覽器樣式和用戶樣式中定義的代碼,因為層定義了自己的層次結構,完全忽略了權重的影響。

          這 3 個 CSS 層是有序的(瀏覽器樣式、用戶樣式、然后是作者樣式),后面層中的每個樣式都將覆蓋前一層的任何樣式。這意味著即使瀏覽器樣式定義了一個超級特定的選擇器,例如#button.btn.super-specific,并且您的作者樣式定義了一個超級通用的選擇器,例如按鈕,您的作者樣式仍然會覆蓋瀏覽器樣式。

          這實際上已經是您可能一直在使用而沒有意識到的東西。

          * {
            box-sizing: border-box;
          }

          上面的選擇器沒有權重,因為 * 符號對權重沒有貢獻。 這意味著例如使用 p 作為選擇器的 p 標簽的瀏覽器樣式在技術上比 * 選擇器更具體,權重更高。 但是,這一切并不重要,因為作者樣式位于比瀏覽器樣式層晚的層中,因此您的代碼將始終覆蓋瀏覽器樣式。

          理解這一點至關重要,因為使用這個新的圖層 API,您可以在作者圖層中創建自己的圖層,從而更輕松地處理特定性。

          如何創建你自己的層

          下面來看個例子:

          很明顯,這是我們正常理解的CSS, ID設置的顏色權重更高,所以按鈕顯示為紅色。讓我們使用@layer給它們加上兩個層,看看是什么效果:

          按鈕變成藍色。為什么會這樣?

          我們給兩條CSS分別建立了base和utilities層,很明顯,后面創建的層的樣式覆蓋了前面層的樣式,盡管前面層的樣式有更高的權重。這就是層的默認工作原理。當然層的順序是可以指定的,

          @layer utilities, base;

          @layer utilities, base;

          您需要做的就是編寫@layer 關鍵字,后跟以逗號分隔的層列表。 這將按從左到右的順序定義所有層,其中列出的第一層到最后一層的權重是依次增加的。 然后,您可以稍后使用普通的@layer 語法向每個層添加代碼,而不必擔心定義層的順序,因為它們都在這一行中定義。 需要注意的是,這行代碼必須在定義任何層之前出現,所以我通常將它作為我的 CSS 文件中的第一行。如上圖,通過指定層的順序,我們讓base層應用在utilities層之后,所以按鈕又顯示為紅色。

          導入層

          上面這兩種方式都是導入bootstrap框架的CSS,并且把他們放在framework層中,這樣你如果想要覆蓋它已有的樣式,只需要新建一個自己的層,放置在framework層后面就行。像下面這樣。

          匿名層

          匿名層不常用,但它寫在后面可以覆蓋其他層的樣式,像下面可以把按鈕設為橙色。

          不在層里的樣式

          不在層里的樣式會有更高的權重,下面這個列表會讓你看得更清楚覆蓋是怎么發生的

          層還可以重疊設置,不過很少用。具體的用法可以查閱相關文檔。

          瀏覽器支持

          自從IE死了以后,所有主流瀏覽器都已支持這一特性。大家請放心使用。

          .內存管理

          前置知識

          絕大多數的程序語言,他們的內存生命周期基本一致:

          1. 分配所需使用的內存 ——(分配內存)
          2. 使用分配到的內存(讀、寫) ——(使用內存)
          3. 不需要時將其釋放\歸還 ——(釋放內存)

          對于所有的編程語言,第二部分都是明確的。而第一和第三部分在底層語言中是明確的。

          但在像JavaScript這些高級語言中,大部分都是隱含的,因為JavaScript具有自動垃圾回收機制(Garbage collected)。

          因此在做JavaScript開發時,不需要關心內存的使用問題,所需內存分配和無用內存回收,都完全實現自動管理。

          1.概述

          像C語言這樣的高級語言一般都有底層的內存管理接口,比如 malloc()和free()。另一方面,JavaScript創建變量(對象,字符串等)時分配內存,并且在不再使用它們時“自動”釋放。 后一個過程稱為垃圾回收。這個“自動”是混亂的根源,并讓JavaScript(和其他高級語言)開發者感覺他們可以不關心內存管理。 這是錯誤的。 ——《MDN JavaScript 內存管理》

          MDN中的介紹告訴我們,作為JavaScript開發者,還是需要去了解內存管理,雖然JavaScript已經給我們做好自動管理。

          2.JavaScript內存生命周期

          2.1 分配內存

          在做JavaScript開發時,我們定義變量的時候,JavaScript便為我們完成了內存分配:

          var num = 100; // 為數值變量分配內存
          var str = 'pingan'; // 為字符串變量分配內存
          var obj = {
           name : 'pingan'
          }; // 為對象變量及其包含的值分配內存
          var arr = [1, null, 'hi']; // 為數組變量及其包含的值分配內存
          function fun(num){
           return num + 2;
          }; // 為函數(可調用的對象)分配內存
          // 函數表達式也能分配一個對象
          someElement.addEventListener('click', function(){
           someElement.style.backgroundColor = 'blue';
          }, false);
          

          另外,通過調用函數,也會分配內存:

          // 類型1. 分配對象內存
          var date = new Date(); // 分配一個Date對象
          var elem = document.createElement('div'); // 分配一個DOM元素
          // 類型2. 分配新變量或者新對象
          var str1 = "pingan";
          var str2 = str1.substr(0, 3); // str2 是一個新的字符串
          var arr1 = ["hi", "pingan"];
          var arr2 = ["hi", "leo"];
          var arr3 = arr1.concat(arr2); // arr3 是一個新的數組(arr1和arr2連接的結果)
          

          2.2 使用內存

          使用內存的過程實際上是對分配的內存進行讀取與寫入的操作。

          通常表現就是使用定義的值。

          讀取與寫入可能是寫入一個變量或者一個對象的屬性值,甚至傳遞函數的參數。

          var num = 1;
          num ++; // 使用已經定義的變量,做遞增操作
          

          2.3 釋放內存

          當我們前面定義好的變量或函數(分配的內存)已經不需要使用的時候,便需要釋放掉這些內存。這也是內存管理中最難的任務,因為我們不知道什么時候這些內存不使用。

          很好的是,在高級語言解釋器中,已經嵌入“垃圾回收器”,用來跟蹤內存的分配和使用,以便在內存不使用時自動釋放(這并不是百分百跟蹤到,只是個近似過程)。

          3.垃圾回收機制

          就像前面提到的,“垃圾回收器”只能解決一般情況,接下來我們需要了解主要的垃圾回收算法和它們局限性。

          3.1 引用

          垃圾回收算法主要依賴于引用的概念。

          即在內存管理環境中,一個對象如果有權限訪問另一個對象,不論顯式還是隱式,稱為一個對象引用另一個對象。

          例如:一個JS對象具有對它原型的引用(隱式引用)和對它屬性的引用(顯式引用)。 注意:

          這里的對象,不僅包含JS對象,也包含函數作用域(或全局詞法作用域)。

          3.2 引用計數垃圾收集

          這個算法,把“對象是否不再需要”定義為:當一個對象沒有被其他對象所引用的時候,回收該對象。這是最初級的垃圾收集算法。

          var obj = {
           leo : {
           age : 18
           };
          };
          

          這里創建2個對象,一個作為leo的屬性被引用,另一個被分配給變量obj。

          // 省略上面的代碼
          /*
          我們將前面的
           {
           leo : {
           age : 18
           };
           };
          稱為“這個對象”
          */
          var obj2 = obj; // obj2變量是第二個對“這個對象”的引用
          obj = 'pingan'; // 將“這個對象”的原始是引用obj換成obj2
          var leo2 = obj2.leo; // 引用“這個對象”的leo屬性
          

          可以看出,現在的“這個對象”已經有2個引用,一個是obj2,另一個是leo2。

          obj2 = 'hi'; 
          // 將obj2變成零引用,因此,obj2可以被垃圾回收
          // 但是它的屬性leo還在被leo2對象引用,所以還不能回收
          leo2 = null;
          // 將leo變成零引用,這樣obj2和leo2都可以被垃圾回收
          

          這個算法有個限制:

          無法處理循環引用。即兩個對象創建時相互引用形成一個循環。

          function fun(){
           var obj1 = {}, obj2 = {};
           obj1.leo = obj2; // obj1引用obj2
           obj2.leo = obj1; // obj2引用obj1
           return 'hi pingan';
          }
          fun();
          

          可以看出,它們被調用之后,會離開函數作用域,已經沒有用了可以被回收,然而引用計數算法考慮到它們之間相互至少引用一次,所以它們不會被回收。

          實際案例:

          在IE6,7中,使用引用計數方式對DOM對象進行垃圾回收,常常造成對象被循環引用導致內存泄露:

          var obj;
          window.onload = function(){
           obj = document.getElementById('myId');
           obj.leo = obj;
           obj.data = new Array(100000).join('');
          };
          

          可以看出,DOM元素obj中的leo屬性引用了自己obj,造成循環引用,若該屬性(leo)沒有移除或設置為null,垃圾回收器總是且至少有一個引用,并一直占用內存,即使從DOM樹刪除,如果這個DOM元素含大量數據(如data屬性)則會導致占用內存永遠無法釋放,出現內存泄露。

          3.3 標記清除算法

          這個算法,將“對象是否不再需要”定義為:對象是否可以獲得。

          標記清除算法,是假定設置一個根對象(root),在JS中是全局對象。垃圾回收器定時找所有從根開始引用的對象,然后再找這些對象引用的對象...直到找到所有可以獲得的對象和搜集所有不能獲得的對象。

          它比引用計數垃圾收集更好,因為“有零引用的對象”總是不可獲得的,但是相反卻不一定,參考“循環引用”。

          循環引用不再是問題:

          function fun(){
           var obj1 = {}, obj2 = {};
           obj1.leo = obj2; // obj1引用obj2
           obj2.leo = obj1; // obj2引用obj1
           return 'hi pingan';
          }
          fun();
          

          還是這個代碼,可以看出,使用標記清除算法來看,函數調用之后,兩個對象無法從全局對象獲取,因此將被回收。相同的,下面案例,一旦 obj 和其事件處理無法從根獲取到,他們將會被垃圾回收器回收。

          var obj;
          window.onload = function(){
           obj = document.getElementById('myId');
           obj.leo = obj;
           obj.data = new Array(100000).join('');
          };
          

          注意: 那些無法從根對象查詢到的對象都將被清除。

          3.4 個人小結

          在日常開發中,應該注意及時切斷需要回收對象與根的聯系,雖然標記清除算法已經足夠強壯,就像下面代碼:

          var obj,ele=document.getElementById('myId');
          obj.div = document.createElement('div');
          ele.appendChild(obj.div);
          // 刪除DOM元素
          ele.removeChild(obj.div);
          

          如果我們只是做小型項目開發,JS用的比較少的話,內存管理可以不用太在意,但是如果是大項目(SPA,服務器或桌面應用),那就需要考慮好內存管理問題了。

          #

          4.內存泄露(Memory Leak)

          #

          4.1 內存泄露概念

          在計算機科學中,內存泄漏指由于疏忽或錯誤造成程序未能釋放已經不再使用的內存。內存泄漏并非指內存在物理上的消失,而是應用程序分配某段內存后,由于設計錯誤,導致在釋放該段內存之前就失去了對該段內存的控制,從而造成了內存的浪費。 ——維基百科

          其實簡單理解:一些不再使用的內存無法被釋放。

          當內存占用越來越多,不僅影響系統性能,嚴重的還會導致進程奔潰。

          4.2 內存泄露案例

          1. 全局變量

          未定義的變量,會被定義到全局,當頁面關閉才會銷毀,這樣就造成內存泄露。如下:

          function fun(){
           name = 'pingan';
          };
          
          1. 未銷毀的定時器和回調函數
          2. 如果這里舉一個定時器的案例,如果定時器沒有回收,則不僅整個定時器無法被內存回收,定時器函數的依賴也無法回收:
          var data = {};
          setInterval(function(){
           var render = document.getElementById('myId');
           if(render){
           render.innderHTML = JSON.stringify(data);
           }
          }, 1000);
          
          1. 閉包
          var str = null;
          var fun = function(){
           var str2 = str;
           var unused = function(){
           if(str2) console.log('is unused');
           };
           str = {
           my_str = new Array(100000).join('--');
           my_fun = function(){
           console.log('is my_fun');
           };
           };
          };
          setInterval(fun, 1000);
          

          定時器中每次調用fun,str都會獲得一個包含巨大的數組和一個對于新閉包my_fun的對象,并且unused是一個引用了str2的閉包。

          整個案例中,閉包之間共享作用域,盡管unused可能一直沒有調用,但my_fun可能被調用,就會導致內存無法回收,內存增長導致泄露。

          1. DOM引用 當我們把DOM的引用保存在一個數組或Map中,即使移除了元素,但仍然有引用,導致無法回收內存。例如:
          var ele = {
           img : document.getElementById('my_img')
          };
          function fun(){
           ele.img.src = "http://www.baidu.com/1.png";
          };
          function foo(){
           document.body.removeChild(document.getElementById('my_img'));
          };
          

          即使foo方法將my_img元素移除,但fun仍有引用,無法回收。

          4.3 內存泄露識別方法

          1. 瀏覽器

          通過Chrome瀏覽器查看內存占用:

          步驟如下:

          • 打開開發者工具,選擇 Timeline 面板
          • 在頂部的Capture字段里面勾選 Memory
          • 點擊左上角的錄制按鈕
          • 在頁面上進行各種操作,模擬用戶的使用情況
          • 一段時間后,點擊對話框的 **stop **按鈕,面板上就會顯示這段時間的內存占用情況

          如果內存占用基本平穩,接近水平,就說明不存在內存泄漏。

          反之,就是內存泄漏了。

          1. 命令行

          命令行可以使用 Node 提供的process.memoryUsage方法。

          console.log(process.memoryUsage());
          // { rss: 27709440,
          // heapTotal: 5685248,
          // heapUsed: 3449392,
          // external: 8772 }
          

          process.memoryUsage返回一個對象,包含了 Node 進程的內存占用信息。該對象包含四個字段,單位是字節,含義如下。

          • rss(resident set size):所有內存占用,包括指令區和堆棧。
          • heapTotal:"堆"占用的內存,包括用到的和沒用到的。
          • heapUsed:用到的堆的部分。
          • external: V8 引擎內部的 C++ 對象占用的內存。

          判斷內存泄漏,以heapUsed字段為準。

          公眾號:前端自習課

          all-admin-web

          前言

          該項目為前后端分離項目的前端部分,后端項目mall地址:傳送門。

          項目介紹

          mall-admin-web是一個電商后臺管理系統的前端項目,基于Vue+Element實現。 主要包括商品管理、訂單管理、會員管理、促銷管理、運營管理、內容管理、統計報表、財務管理、權限管理、設置等功能。

          項目演示

          項目在線演示地址:http://39.98.190.128/index.html

          項目布局

          src -- 源碼目錄
          ├── api -- axios網絡請求定義
          ├── assets -- 靜態圖片資源文件
          ├── components -- 通用組件封裝
          ├── icons -- svg矢量圖片文件
          ├── router -- vue-router路由配置
          ├── store -- vuex的狀態管理
          ├── styles -- 全局css樣式
          ├── utils -- 工具類
          └── views -- 前端頁面
           ├── home -- 首頁
           ├── layout -- 通用頁面加載框架
           ├── login -- 登錄頁
           ├── oms -- 訂單模塊頁面
           ├── pms -- 商品模塊頁面
           └── sms -- 營銷模塊頁面
          

          搭建步驟

          • 下載node并安裝:https://nodejs.org/dist/v8.9.4/node-v8.9.4-x64.msi;
          • 該項目為前后端分離項目,訪問本地訪問接口需搭建后臺環境,搭建請參考后端項目傳送門;
          • 訪問在線接口無需搭建后臺環境,只需將config/dev.env.js文件中的BASE_API改為http://39.98.190.128:8080即可;
          • 克隆源代碼到本地,使用IDEA打開,并完成編譯;
          • 在IDEA命令行中運行命令:npm install,下載相關依賴;
          • 在IDEA命令行中運行命令:npm run dev,運行項目;
          • 訪問地址:http://localhost:8090 即可打開后臺管理系統頁面;
          • 如果遇到無法運行該命令,需要配置npm的環境變量,如在path變量中添加:C:\Users\zhenghong\AppData\Roaming\npm。

          https://github.com/macrozheng/mall-admin-web


          主站蜘蛛池模板: 久久se精品一区二区影院| 日韩免费一区二区三区在线播放| 国产一区三区三区| 蜜臀AV免费一区二区三区| 国产一区在线电影| 国产丝袜美女一区二区三区| 国产高清视频一区二区| 欲色aV无码一区二区人妻| 黑人大战亚洲人精品一区| 一区二区三区精品高清视频免费在线播放 | 国产a∨精品一区二区三区不卡 | 日本成人一区二区三区| 美女视频免费看一区二区| 久久久久久人妻一区二区三区| 无码人妻精品一区二区三18禁| 一区二区三区影院| 成人精品一区二区三区中文字幕| 视频一区视频二区日韩专区| 美女AV一区二区三区| 国产伦精品一区二区三区在线观看| 无码人妻精品一区二区三区99性| 色国产精品一区在线观看| 色婷婷一区二区三区四区成人网 | 亚洲日本va午夜中文字幕一区| 真实国产乱子伦精品一区二区三区| 亚洲一区精品伊人久久伊人| 精品久久国产一区二区三区香蕉| 人妻体内射精一区二区| 久久国产三级无码一区二区| 国产一区麻豆剧传媒果冻精品| 秋霞午夜一区二区| 91精品一区二区三区在线观看| 亚洲香蕉久久一区二区三区四区| 亚洲av无码一区二区三区观看| 伊人色综合网一区二区三区| 精品一区二区ww| 国产成人综合精品一区| 色狠狠一区二区三区香蕉蜜桃| 亚洲一区二区在线免费观看| 国产一区二区久久久| 国产一区二区三区美女|