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 成人18视频在线观看,欧美激情高清整在线,亚洲精品久久久久电影

          整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          CSS常見面試題-flex布局中元素占據(jù)空間的計算過

          CSS常見面試題-flex布局中元素占據(jù)空間的計算過程

          在之前的一篇文章《CSS經(jīng)典面試題-常用的CSS兩欄和三欄布局方案》中,我們有一道題目是通過flex去實現(xiàn)三欄布局的。

          今天這篇文章我們來具體看看,flex是如何實現(xiàn)頁面布局的,希望加深大家對flex的理解。

          CSS

          flex布局的含義

          flex布局又名為‘彈性布局’,主要是通過設(shè)置的屬性值自動調(diào)整元素的寬度和高度值,在容器空間充裕的情況下,使其填滿容器的剩余空間;又或者在容器空間不足的情況下,收縮元素的高度和寬度,使其不會溢出容器。

          使用flex布局,可以靈活的控制元素在容器內(nèi)的展示。尤其是對于移動端小屏幕來說,flex基本已成了主流的布局方式。

          flex布局的基本概念

          在flex布局中,有幾個概念是我們必須掌握的,可以從下面這個圖中看出。

          flex布局

          flex布局,實際就是一個彈性容器內(nèi)部元素的排列。

          flex容器中存在一個主軸和側(cè)軸的概念,表示的是容器內(nèi)元素排列的方向。在默認情況下,彈性項目會沿著主軸方向排列,即上圖所示的水平方向。當(dāng)然也可以通過flex-direction屬性去設(shè)置。

          在flex中有6個可以設(shè)置在容器上的屬性,有6個可以設(shè)置容器內(nèi)項目的屬性,這些基本知識大家可以自行去查看官方文檔,下面我們看看flex布局的計算過程。

          flex布局的實例

          在很多網(wǎng)站中,我們可以看到這樣的效果,當(dāng)鼠標移動到指定的元素后,該元素展示詳情,其他元素收縮。

          基本效果如下圖所示。

          flex布局實例1

          我們先看看代碼部分,再去分析為什么會達到這個效果。

          • HTML代碼

          HTML部分代碼很簡單,無需多講。

          HTML代碼

          • CSS代碼

          首先是容器的基本樣式,設(shè)置display為flex,為了更好的兼容性,在某些屬性上加上-webkit-前綴。

          容器屬性

          然后是給容器內(nèi)子項目設(shè)置flex相關(guān)屬性,為了讓效果看起來更平滑,加上了動畫。

          容器內(nèi)子項目屬性

          最后是很重要的一點,就是在鼠標滑過時,改變該子項目的寬度。

          鼠標滑過

          解析計算過程

          通過以上的屬性,為什么就能達到上面的效果呢?

          • 初始寬度值

          在鼠標未經(jīng)過容器時,容器會根據(jù)設(shè)置的flex值自動計算每個子項目占據(jù)的實際寬度值。

          每個子項目的flex值為1, 1, auto。

          1. 第一個1表示的是,在容器有剩余空間時,每個子項目都進行一等分剩余空間。

          2. 第二個1表示的是,當(dāng)容器空間不足時,每個子項目一等分的減少超出的空間。

          3. 第三個參數(shù)auto表示的是寬度值取決于其他屬性值,這個題目中是width值。

          我們再來看看計算過程。

          容器總寬度為450px,每個div寬度值為30px,則三個div就是30*3=90px。

          那么剩余空間就是450px-90px=360px。

          因為每個div的flex-grow屬性為1,則表示將剩余空間分為1+1+1=3等分。

          那么每等分空間的寬度就是360/3=120px。

          那么最后每個div占據(jù)的實際寬度就是120px+30px=150px。

          • 鼠標滑過

          當(dāng)鼠標滑過時,設(shè)置了:hover類,其中width值變?yōu)?00px,這里會重新計算各個div的寬度值。

          三個div占據(jù)的寬度值為200px+30px+30px=260px。

          剩余空間450px-260px=190px。

          剩余空間三等分后,每等分空間的寬度是190/3=63.33px。

          那么未滑過鼠標的div占據(jù)的實際空間是63.33+30=93.33px。

          滑過鼠標的div占據(jù)是實際空間是63.33+200=263.33px。

          通過以下的圖可以看出。

          結(jié)果圖

          結(jié)束語

          今天這篇文章通過一個布局實例,講解了flex布局的計算過程,其實大家在掌握了flex屬性的幾個特定值后就可以很容易的算出占據(jù)的寬度值。

          今天這篇文章大家有沒有理解呢?

          家好,Echa。

          今天來分享常見的瀏覽器數(shù)據(jù)存儲方案:localStorage、sessionStorage、IndexedDB、Cookies。

          1. 概述

          現(xiàn)代瀏覽器中提供了多種存儲機制,打開瀏覽器的控制臺(Mac 可以使用 Command + Option + J 快捷鍵,Windows 可以使用 Control + Shift + J 快捷鍵)。選擇 Application 選項卡,可以在 Storage中 看到 Local Storage、Session Storage、IndexedDB、Web SQL、Cookies 等:

          那數(shù)據(jù)存儲在瀏覽器中有什么使用場景呢?在以下情況下,將數(shù)據(jù)存儲在瀏覽器中成為更可行的選擇:

          • 在瀏覽器存儲中保存應(yīng)用狀態(tài),比如保持用戶偏好(用戶特定的設(shè)置,例如亮模式或暗模式、字體大小等);
          • 創(chuàng)建離線工作的漸進式 Web 應(yīng)用,除了初始下載和更新之外沒有服務(wù)器端要求;
          • 緩存靜態(tài)應(yīng)用資源,如 HTML、CSS、JS 和圖像等;
          • 保存上一個瀏覽會話中的數(shù)據(jù),例如存儲上一個會話中的購物車內(nèi)容,待辦事項列表中的項目,記住用戶是否以前登錄過等。

          無論哪種方式,將這些信息保存在客戶端可以減少額外且不必要的服務(wù)器調(diào)用,并幫助提供離線支持。不過,需要注意,由于實現(xiàn)差異,瀏覽器存儲機制在不同瀏覽器中的行為可能會有所不同。除此之外,許多瀏覽器已刪除對 Web SQL 的支持,建議將現(xiàn)有用法遷移到 IndexedDB。

          所以下面我們將介紹 Local Storage、Session Storage、IndexedDB、Cookies 的使用方式、使用場景以及它們之間的區(qū)別。

          2. Web Storage

          (1)概述

          HTML5 引入了 Web Storage,這使得在瀏覽器中存儲和檢索數(shù)據(jù)變得更加容易。Web Storage API 為客戶端瀏覽器提供了安全存儲和輕松訪問鍵值對的機制。Web Storage 提供了兩個 API 來獲取和設(shè)置純字符串的鍵值對:

          • localStorage:用于存儲持久數(shù)據(jù),除非用戶手動將其從瀏覽器中刪除,否則數(shù)據(jù)將終身存儲。即使用戶關(guān)閉窗口或選項卡,它也不會過期;
          • sessionStorage:用于存儲臨時會話數(shù)據(jù),頁面重新加載后仍然存在,關(guān)閉瀏覽器選項卡時數(shù)據(jù)丟失。

          (2)方法和屬性

          Web Storage API 由 4 個方法 setItem()getItem()removeItem()clear()key()和一個 length 屬性組成,以 localStorage 為例:

          • setItem() :用于存儲數(shù)據(jù),它有兩個參數(shù),即keyvalue。使用形式:localStorage.setItem(key, value)
          • getItem():用于檢索數(shù)據(jù),它接受一個參數(shù) key,即需要訪問其值得鍵。使用形式:localStorage.getItem(key);
          • removeItem():用于刪除數(shù)據(jù),它接受一個參數(shù) key,即需要刪除其值得鍵。使用形式:localStorage.removeItem(key);
          • clear() :用于清除其中存儲的所有數(shù)據(jù),使用形式:localStorage.clear();
          • key():該方法用于獲取 localStorage 中數(shù)據(jù)的所有key,它接受一個數(shù)字作為參數(shù),該數(shù)字可以是 localStorage 項的索引位置。
          console.log(typeof window.localStorage) // Object
          
          // 存儲數(shù)據(jù)
          localStorage.setItem("colorMode", "dark")
          localStorage.setItem("username", "zhangsan")
          localStorage.setItem("favColor", "green")
          
          console.log(localStorage.length) // 3
          
          // 檢索數(shù)據(jù)
          console.log(localStorage.getItem("colorMode")) // dark
          
          // 移除數(shù)據(jù)
          localStorage.removeItem("colorMode")
          console.log(localStorage.length) // 2
          console.log(localStorage.getItem("colorMode")) // null
          
          // 檢索鍵名
          window.localStorage.key(0); // favColor
          
          // 清空本地存儲
          localStorage.clear()
          console.log(localStorage.length) // 0
          

          localStorage 和 sessionStorage 都非常適合緩存非敏感應(yīng)用數(shù)據(jù)。可以在需要存儲少量簡單值并不經(jīng)常訪問它們是使用它們。它們本質(zhì)上都是同步的,并且會阻塞主 UI 線程,所以應(yīng)該謹慎使用。

          (3)存儲事件

          我們可以在瀏覽器上監(jiān)聽 localStorage 和 sessionStorage 的存儲變化。storage 事件在創(chuàng)建、刪除或更新項目時觸發(fā)。偵聽器函數(shù)在事件中傳遞,具有以下屬性:

          • newValue:當(dāng)在存儲中創(chuàng)建或更新項目時傳遞給 setItem() 的值。當(dāng)從存儲中刪除項目時,此值設(shè)置為 null。
          • oldValue:創(chuàng)建新項目時,如果該鍵存在于存儲中,則該項目的先前的值。
          • key:正在更改的項目的鍵,如果調(diào)用 .clear(),則值為 null。
          • url:執(zhí)行存儲操作的 URL。
          • storageArea:執(zhí)行操作的存儲對象(localStorage 或 sessionStorage)。

          通常,我們可以使用 window.addEventListener("storage", func) 或使用 onstorage 屬性(如 window.onstorage=func)來監(jiān)聽 storage 事件:

          window.addEventListener('storage', e=> {
            console.log(e.key);
            console.log(e.oldValu);
            console.log(e.newValue);
          });
          
          window.onstorage=e=> {
            console.log(e.key);
            console.log(e.oldValu);
            console.log(e.newValue);
          });
          

          注意,該功能不會在發(fā)生更改的同一瀏覽器選項卡上觸發(fā),而是由同一域的其他打開的選項卡或窗口觸發(fā)。此功能用于同步同一域的所有瀏覽器選項卡/窗口上的數(shù)據(jù)。因此,要對此進行測試,需要打開同一域的另一個選項卡。

          (4)存儲限制

          localStorage 和 sessionStorage 只能存儲 5 MB 的數(shù)據(jù),因此需要確保存儲的數(shù)據(jù)不會超過此限制。

          localStorage.setItem('a', Array(1024 * 1024 * 5).join('a'))
          localStorage.setItem('b', 'a')
          
          // Uncaught DOMException: Failed to execute 'setItem' on 'Storage': Setting the value of `a` exceeded the quota.
          

          在上面的例子中,收到了一個錯誤,首先創(chuàng)建了一個5MB的大字符串,當(dāng)再添加其他數(shù)據(jù)時就報錯了。

          另外,localStorage 和 sessionStorage 只接受字符串。可以通過 JSON.stringifyJSON.parse 來解決這個問題:

          const user={
            name : "zhangsan",
            age : 28,
            gender : "male",
            profession : "lawyer" 
          };
          
          localStorage.setItem("user", JSON.stringify(user));
          localStorage.getItem("user");   // '{"name":"zhangsan","age":28,"gender":"male","profession":"lawyer"}'
          JSON.parse(localStorage.getItem("user"))  // {name: 'zhangsan', age: 28, gender: 'male', profession: 'lawyer'}
          

          如果我們直接將一個對象存儲在 localStorage 中,那將會在存儲之前進行隱式類型轉(zhuǎn)換,將對象轉(zhuǎn)換為字符串,再進行存儲:

          const user={
            name : "zhangsan",
            age : 28,
            gender : "male",
            profession : "lawyer" 
          };
          
          localStorage.setItem("user", user);
          localStorage.getItem("user");  // '[object Object]'
          

          Web Storage 使用了同源策略,也就是說,存儲的數(shù)據(jù)只能在同一來源上可用。如果域和子域相同,則可以從不同的選項卡訪問 localStorage 數(shù)據(jù),而無法訪問 sessionStorage 數(shù)據(jù),即使它是完全相同的頁面。

          另外:

          • 無法在 web worker 或 service worker 中訪問 Web Storage;
          • 如果瀏覽器設(shè)置為隱私模式,將無法讀取到 Web Storage;
          • Web Storage 很容易被 XSS 攻擊,敏感信息不應(yīng)存儲在本地存儲中;
          • 它是同步的,這意味著所有操作都是一次一個。對于復(fù)雜應(yīng)用,它會減慢應(yīng)用的運行時間。

          (5)示例

          下面來看一個使用 localStorage 的簡單示例,使用 localStorage 來存儲用戶偏好:

          <input type="checkbox" id="darkTheme" name="darkTheme" onclick='onChange(this);'>
          <label for="darkTheme">黑暗模式</label><br>
          
          html {
            background: white;
          }
          
          .dark {
            background: black;
            color: white;
          }
          
          function toggle(on) {
            if (on) {
              document.documentElement.classList.add('dark'); 
            } else {
              document.documentElement.classList.remove('dark');    
            }
          }
          
          function save(on) {
            localStorage.setItem('darkTheme', on.toString());
          }
          
          function load() {
            return localStorage.getItem('darkTheme')==='true';
          }
          
          function onChange(checkbox) {
            const value=checkbox.checked;
            toggle(value);
            save(value);
          }
          
          const initialValue=load();
          toggle(initialValue);
          document.querySelector('#darkTheme').checked=initialValue;
          

          這里的代碼很簡單,頁面上有一個單選框,選中按鈕時將頁面切換為黑暗模式,并將這個配置存儲在 localStorage 中。當(dāng)下一次再初始頁面時,獲取 localStorage 中的主題設(shè)置。

          3. Cookie

          (1)Cookie 概述

          Cookie 主要用于身份驗證和用戶數(shù)據(jù)持久性。Cookie 與請求一起發(fā)送到服務(wù)器,并在響應(yīng)時發(fā)送到客戶端;因此,cookies 數(shù)據(jù)在每次請求時都會與服務(wù)器交換。服務(wù)器可以使用 cookie 數(shù)據(jù)向用戶發(fā)送個性化內(nèi)容。嚴格來說,cookie 并不是客戶端存儲方式,因為服務(wù)器和瀏覽器都可以修改數(shù)據(jù)。它是唯一可以在一段時間后自動使數(shù)據(jù)過期的方式。

          每個 HTTP 請求和響應(yīng)都會發(fā)送 cookie 數(shù)據(jù)。存儲過多的數(shù)據(jù)會使 HTTP 請求更加冗長,從而使應(yīng)用比預(yù)期更慢:

          • 瀏覽器限制 cookie 的大小最大為4kb,特定域允許的 cookie 數(shù)量為 20 個,并且只能包含字符串;
          • cookie 的操作是同步的;
          • 不能通過 web workers 來訪問,但可以通過全局 window 對象訪問。

          Cookie 通常用于會話管理、個性化以及跨網(wǎng)站跟蹤用戶行為。我們可以通過服務(wù)端和客戶端設(shè)置和訪問 cookie。Cookie 還具有各種屬性,這些屬性決定了在何處以及如何訪問和修改它們,

          Cookie 分為兩種類型:

          • 會話 Cookie:沒有指定 Expires 或 Max-Age 等屬性,因此在關(guān)閉瀏覽器時會被刪除;
          • 持久性 Cookie:指定 Expires 或 Max-Age 屬性。這些 cookie 在關(guān)閉瀏覽器時不會過期,但會在特定日期 (Expires) 或時間長度 (Max-Age) 后過期。

          (2)Cookie 操作

          下面先來看看如何訪問和操作客戶端和服務(wù)器上的 cookie。

          ① 客戶端(瀏覽器)

          客戶端 JavaScript 可以通過 document.cookie 來讀取當(dāng)前位置可訪問的所有 cookie。它提供了一個字符串,其中包含一個以分號分隔的 cookie 列表,使用 key=value 格式。

          document.cookie;
          

          可以看到,在語雀主頁中獲取 cookie,結(jié)果中包含了登錄的 cookie、語言、當(dāng)前主題等。

          同樣,可以使用 document.cookie 來設(shè)置 cookie 的值,設(shè)置cookie也是用key=value格式的字符串,屬性用分號隔開:

          document.cookie="hello=world; domain=example.com; Secure";
          

          這里用到了兩個屬性 SameSite 和 Secure,下面會介紹。如果已經(jīng)存在同名的 cookie 屬性,就會更新已有的屬性值,如果不存在,就會創(chuàng)建一個新的 key=value。

          如果需要經(jīng)常在客戶端處理 Cookie,建議使用像 js-cookie 這樣的庫來處理客戶端 cookie:

          Cookies.set('hello', 'world', { domain: 'example.com', secure: true });
          Cookies.get('hello'); // -> world
          

          這樣不僅為 cookie 上的 CRUD 操作提供了一個干凈的 API,而且還支持 TypeScript,從而幫助避免屬性的拼寫錯誤。

          ② 服務(wù)端(Node.js)

          服務(wù)端可以通過 HTTP 請求的請求頭和響應(yīng)頭來訪問和修改 cookie。每當(dāng)瀏覽器向服務(wù)端發(fā)送 HTTP 請求時,它都會使用 cookie 頭將所有相關(guān) cookie 都附加到該站點。請求標頭是一個分號分隔的字符串。

          這樣就可以從請求頭中讀取這些 cookie。如果在服務(wù)端使用 Node.js,可以像下面這樣從請求對象中讀取它們,將獲得以分號分隔的 key=value 對:

          http.createServer(function (request, response) {
              const cookies=request.headers.cookie;
              // "cookie1=value1; cookie2=value2"
              ...
          }).listen(8124);
          

          如果想要設(shè)置 cookie,可以在響應(yīng)頭中添加 Set-Cookie 頭,其中 cookie 采用 key=value 的格式,屬性用分號分隔:

          response.writeHead(200, {
              'Set-Cookie': 'mycookie=test; domain=example.com; Secure'
          });
          

          通常我們不會直接編寫 Node.js,而是與 ExpressJS 這樣的 Node.js 框架一起使用。使用 Express 可以更輕松地訪問和修改 cookie。只需添加一個像 cookie-parser 這樣的中間件,就可以通過 req.cookies 以 JavaScript 對象的形式獲得所有的 cookie。還可以使用 Express 內(nèi)置的 res.cookie() 方法來設(shè)置 cookie:

          const express=require('express')
          const cookieParser=require('cookie-parser')
              
          const app=express()
          app.use(cookieParser())
              
          app.get('/', function (req, res) {
              console.log('Cookies: ', req.cookies)
              // Cookies: { cookie1: 'value1', cookie2: 'value2' }
          
              res.cookie('name', 'tobi', { domain: 'example.com', secure: true })
          })
              
          app.listen(8080)
          

          (3)Cookie 屬性

          下面來深入了解 cookie 的屬性。除了名稱和值之外,cookie 還具有控制很多方面的屬性,包括安全方面、生命周期以及它們在瀏覽器中的訪問位置和方式等。

          ① Domain

          Domain 屬性告訴瀏覽器允許哪些主機訪問 cookie。如果未指定,則默認為設(shè)置 cookie 的同一主機。因此,當(dāng)使用客戶端 JavaScript 訪問 cookie 時,只能訪問與 URL 域相同的 cookie。同樣,只有與 HTTP 請求的域共享相同域的 cookie 可以與請求頭一起發(fā)送到服務(wù)端。

          注意,擁有此屬性并不意味著可以為任何域設(shè)置 cookie,因為這顯然會帶來巨大的安全風(fēng)險。此屬性存在的唯一原因就是減少域的限制并使 cookie 在子域上可訪問。例如,如果當(dāng)前的域是 abc.xyz.com,并且在設(shè)置 cookie 時如果不指定 Domain 屬性,則默認為 abc.xyz.com,并且 cookie 將僅限于該域。但是,可能希望相同的 cookie 也可用于其他子域,因此可以設(shè)置 Domain=xyz.com 以使其可用于其他子域,如 def.xyz.com 和主域 xyz.com。

          ② Path

          此屬性指定訪問 cookie 必須存在的請求 URL 中的路徑。除了將 cookie 限制到域之外,還可以通過路徑來限制它。路徑屬性為 Path=/store 的 cookie 只能在路徑 /store 及其子路徑 /store/cart、/store/gadgets 等上訪問。

          ③ Expires/Max-size

          該屬性用來設(shè)置 cookie 的過期時間。若設(shè)置其值為一個時間,那么當(dāng)?shù)竭_此時間后,cookie 就會失效。不設(shè)置的話默認值是 Session,意思是cookie會和session一起失效。當(dāng)瀏覽器關(guān)閉(不是瀏覽器標簽頁) 后,cookie 就會失效。

          除此之外,它還可以通過將過期日期設(shè)置為過去來刪除 cookie。

          ④ Secure

          具有 Secure 屬性的 cookie 僅可以通過安全的 HTTPS 協(xié)議發(fā)送到服務(wù)器,而不會通過 HTTP 協(xié)議。這有助于通過使 cookie 無法通過不安全的連接訪問來防止中間人攻擊。除非網(wǎng)站實用不安全的 HTTP 連接,否則應(yīng)該始終將此屬性與所有 cookie 一起使用。

          ⑤ HTTPOnly

          此屬性使 cookie 只能通過服務(wù)端訪問。因此,只有服務(wù)斷可以通過響應(yīng)頭設(shè)置它們,然后瀏覽器會將它們與每個后續(xù)請求的頭一起發(fā)送到服務(wù)器,并且它們將無法通過客戶端 JavaScript 訪問。

          這可以在一定程度上幫助保護帶有敏感信息(如身份驗證 token)的 cookie 免受 XSS 攻擊,因為任何客戶端腳本都無法讀取 cookie。但這并不意味著可以完全免受 XSS 攻擊。因為,如果攻擊者可以在網(wǎng)站上執(zhí)行第三方腳本,那可能無法訪問 cookie,相反,他們可以直接向服務(wù)端執(zhí)行相關(guān)的 API 請求。因此,想象一下用戶訪問了一個頁面,黑客在網(wǎng)站上注入了惡意腳本。他們可以使用該腳本執(zhí)行任何 API,并在他們不知道的情況下代表用戶執(zhí)行操作。

          (4)Cookie 工具庫

          ① Js Cookie(JavaScript)

          Js Cookie 是一個簡單、輕量級的 JavaScript API,用于處理瀏覽器 cookie。其支持 AMD、CommonJS 和 ES 模塊、沒有依賴關(guān)系、經(jīng)過徹底測試、支持自定義編碼和解碼、通用瀏覽器支持。

          安裝:

          npm i js-cookie
          

          使用:

          // 設(shè)置 Cookie
          Cookies.set('cookie-name', 'cookie-value', { expires: 14})
          
          // 讀取 Cookie
          Cookies.get('cookie-name')
          
          // 刪除 Cookie
          Cookies.remove('cookie-name')
          

          ② React Cookie(React)

          React Cookie 是一個專門用于 React 的 cookie 庫,它繼承了 Universal Cookie 庫的功能。它提供了一組組件和 Hooks,使 React 中的 cookie 處理非常簡單。如果使用的是 React 16.8+ 版本,就可以使用 hooks 來處理 cookie。否則,必須使用其提供的組件。

          安裝:

          npm i react-cookie
          

          React Cookie 提供了 3 個 Hook,分別是 cookie、setCookie 和 removeCookie。可以使用這些 Hook 來處理 React 應(yīng)用中的 cookie。

          const [cookies, setCookie, removeCookie]=useCookies(['cookie-name']);
          // 設(shè)置 Cookie
          setCookie(name, value, [options]);
          // 刪除 Cookie
          removeCookie(name, [options])
          

          ③ Cookies(Node.js)

          Cookies 是用于 HTTP cookie 配置的流行 NodeJS 模塊之一。可以輕松地將其與內(nèi)置的 NodeJS HTTP 庫集成或?qū)⑵溆米?Express 中間件。它允許使用 Keygrip 對 cookie 進行簽名以防止篡改、支持延遲 cookie 驗證、不允許通過不安全的套接字發(fā)送安全 cookie、允許其他庫在不知道簽名機制的情況下訪問 cookie。

          安裝:

          npm install cookies
          

          使用:

          const cookie=require('cookie');
          cookies=new Cookies( request, response, [ options ] )
          
          // 讀取 cookies
          cookies.get( name, [ options ] )
          
          // 設(shè)置 cookies
          cookies.set( name, [ value ], [ options ] )
          

          4. IndexedDB

          (1)概述

          IndexedDB 提供了一個類似 NoSQL 的 key/value 數(shù)據(jù)庫,它可以存儲大量結(jié)構(gòu)化數(shù)據(jù),甚至是文件和 blob。每個域至少有 1GB 的可用空間,并且最多可以達到剩余磁盤空間的 60%。

          IndexedDB 于 2011 年首次實現(xiàn),并于 2015 年 1 月成為 W3C 標準,它具有良好的瀏覽器支持:

          key/value 數(shù)據(jù)庫意味著存儲的所有數(shù)據(jù)都必須分配給一個 key。它將key 與 value 相關(guān)聯(lián),key 用作該值的唯一標識符,這意味著可以使用該 key 跟蹤該值。如果應(yīng)用需要不斷獲取數(shù)據(jù),key/value 數(shù)據(jù)庫使用非常高效且緊湊的索引結(jié)構(gòu)來快速可靠地通過 key 定位值。使用該 key,不僅可以檢索存儲的值,還可以刪除、更新和替換該值。

          在說 IndexedDB 之前,先來看一些相關(guān)術(shù)語:

          • 數(shù)據(jù)庫: 一個域可以創(chuàng)建任意數(shù)量的 IndexedDB 數(shù)據(jù)庫,只有同一域內(nèi)的頁面才能訪問數(shù)據(jù)庫。
          • object store:相關(guān)數(shù)據(jù)項的 key/value 存儲。它類似于 MongoDB 中的集合或關(guān)系數(shù)據(jù)庫中的表。
          • key:用于引用 object store 中每條記錄(值)的唯一名稱。它可以使用自動增量數(shù)字生成,也可以設(shè)置為記錄中的任何唯一值。
          • index:在 object store 中組織數(shù)據(jù)的另一種方式。搜索查詢只能檢查 key 或 index。
          • schema:object store、key 和 index 的定義。
          • version:分配給 schema 的版本號(整數(shù))。IndexedDB 提供自動版本控制,因此可以將數(shù)據(jù)庫更新到最新 schema。
          • 操作:數(shù)據(jù)庫活動,例如創(chuàng)建、讀取、更新或刪除記錄。

          (2)特點及使用場景

          indexedDB 特點如下:

          • 可以將任何 JavaScript 類型的數(shù)據(jù)存儲為鍵值對,例如對象(blob、文件)或數(shù)組等。
          • IndexedDB API 是異步的,不會在數(shù)據(jù)加載時停止頁面的渲染。
          • 可以存儲結(jié)構(gòu)化數(shù)據(jù),例如 Date、視頻、圖像對象等。
          • 支持數(shù)據(jù)庫事務(wù)和版本控制。
          • 可以存儲大量數(shù)據(jù)。
          • 可以在大量數(shù)據(jù)中快速定位/搜索數(shù)據(jù)。
          • 數(shù)據(jù)庫是域?qū)S玫模虼巳魏纹渌军c都無法訪問其他網(wǎng)站的 IndexedDB 存儲,這也稱為同源策略。

          IndexedDB 使用場景:

          • 存儲用戶生成的內(nèi)容: 例如表單,在填寫表單的過程中,用戶可以離開并稍后再回來完成表單,存儲之后就不會丟失初始輸入的數(shù)據(jù)。
          • 存儲應(yīng)用狀態(tài): 當(dāng)用戶首次加載網(wǎng)站或應(yīng)用時,可以使用 IndexedDB 存儲這些初始狀態(tài)。可以是登錄身份驗證、API 請求或呈現(xiàn) UI 之前所需的任何其他狀態(tài)。因此,當(dāng)用戶下次訪問該站點時,加載速度會增加,因為應(yīng)用已經(jīng)存儲了狀態(tài),這意味著它可以更快地呈現(xiàn) UI。
          • 對于離線工作的應(yīng)用: 用戶可以在應(yīng)用離線時編輯和添加數(shù)據(jù)。當(dāng)應(yīng)用程序來連接時,IndexedDB 將處理并清空同步隊列中的這些操作。

          (3)IndexedDB 操作

          不同瀏覽器的 IndexedDB 可能使用不同的名稱。可以使用以下方法檢查 IndexedDB 支持:

          const indexedDB=window.indexedDB ||
            window.mozIndexedDB ||
            window.webkitIndexedDB ||
            window.msIndexedDB ||
            window.shimIndexedDB;
          
          if (!indexedDB) {
            console.log("不支持 IndexedDB");
          }
          

          可以使用 indexedDB.open() 來連接數(shù)據(jù)庫:

          const dbOpen=indexedDB.open('performance', 1);
          

          indexedDB.open 的第一個參數(shù)是數(shù)據(jù)庫名稱,第二個參數(shù)是可選的版本整數(shù)。

          可以使用以下三個事件處理函數(shù)監(jiān)聽 indexedDB 的連接狀態(tài):

          ① onerror

          在無法建立 IndexedDB 連接時,將觸發(fā)該事件:

          // 連接失敗
          dbOpen.onerror=e=> {
            reject(`IndexedDB error: ${ e.target.errorCode }`);
          };
          

          如果在無痕模式、隱私模式下運行瀏覽器,可能不支持 IndexedDB,需要禁用這些模式。

          ② onupgradeneeded

          一旦數(shù)據(jù)庫連接打開,就會觸發(fā) onupgradeneeded 事件,該事件可用于創(chuàng)建 object store。

          dbOpen.onupgradeneeded=e=> {
             const db=dbOpen.result;
          
             // 創(chuàng)建 object store
             const store=db.createObjectStore("cars", { keyPath: "id" });
             // 使用自動遞增的id
             // const store=db.createObjectStore('cars', { autoIncrement: true }); 
          
             // 創(chuàng)建索引
             
             store.createIndex("cars_colour", ["colour"], { 
                 unique: true 
             }); 
          
             // 創(chuàng)建復(fù)合索引
             store.createIndex("colour_and_make", ["colour", "make"], {
              unique: false,
            });
          };
          

          IndexedDB 使用了 object store 的概念,其本質(zhì)上是數(shù)據(jù)集合的名稱。可以在單個數(shù)據(jù)庫中創(chuàng)建任意數(shù)量的 object store。keyPath是 IndexedDB 將用來識別對象字段名稱,通常是一個唯一的編號,也可以通過 autoIncrement: true 來自動為 store 設(shè)置唯一遞增的 ID。除了普通的索引,還可以創(chuàng)建復(fù)合索引,使用多個關(guān)鍵詞的組合進行查詢。

          ③ onsuccess

          在連接建立并且所有升級都完成時,將觸發(fā)該事件。上面我們已經(jīng)新建了 schema,接下來就可以在onsuccess 中添加、查詢數(shù)據(jù)。

          // 連接成功
          dbOpen.onsuccess=()=> {
            this.db=dbOpen.result;
          
            //1
            const transaction=db.transaction("cars", "readwrite");
            
            //2
            const store=transaction.objectStore("cars");
            const colourIndex=store.index("cars_colour");
            const makeModelIndex=store.index("colour_and_make");
          
            //3
            store.put({ id: 1, colour: "Red", make: "Toyota" });
            store.put({ id: 2, colour: "Red", make: "Kia" });
            store.put({ id: 3, colour: "Blue", make: "Honda" });
            store.put({ id: 4, colour: "Silver", make: "Subaru" });
          
            //4
            const idQuery=store.get(4);
            const colourQuery=colourIndex.getAll(["Red"]);
            const colourMakeQuery=makeModelIndex.get(["Blue", "Honda"]);
          
            // 5
            idQuery.onsuccess=function () {
              console.log('idQuery', idQuery.result);
            };
            colourQuery.onsuccess=function () {
              console.log('colourQuery', colourQuery.result);
            };
            colourMakeQuery.onsuccess=function () {
              console.log('colourMakeQuery', colourMakeQuery.result);
            };
          
            // 6
            transaction.oncomplete=function () {
              db.close();
            };
          };
          

          這里總共有六部分:

          1. 為了對數(shù)據(jù)庫執(zhí)行操作,我們必須創(chuàng)建一個 schema,一個 schema 可以是單個操作,也可以是多個必須全部成功的操作,否則都不會成功;
          2. 這里用來獲取 cars object store 的引用以及對應(yīng)的索引;
          3. object store 上的 put 方法用于將數(shù)據(jù)添加到數(shù)據(jù)庫中;
          4. 這里就是數(shù)據(jù)的查詢,可以使用 keyPath 的值直接查詢項目(第14行);第15行中的 getAll 方法將返回一個包含它找到的每個結(jié)果的數(shù)組,我們正在根據(jù) cars_colour 索引來搜索 Red,應(yīng)該會查找到兩個結(jié)果。第16行根據(jù)復(fù)合索引查找顏色為Blue,并且品牌為 Honda 的結(jié)果。
          5. 搜索成功的事件處理函數(shù),它們將在查詢完成時觸發(fā)。
          6. 最后,在事務(wù)完成時關(guān)閉與數(shù)據(jù)庫連接。無需使用 IndexedDB 手動觸發(fā)事務(wù),它會自行運行。

          運行上面的代碼,就會得到以下結(jié)果:

          可以在 Chrome Devtools 中查看:

          下面來看看如何更新和刪除數(shù)據(jù)。

          • 更新: 首先使用個 get 來獲取需要更新的數(shù)據(jù),然后使用 store 上的 put 方法更新現(xiàn)有數(shù)據(jù)。put 是一種“插入或更新”方法,它要么覆蓋現(xiàn)有數(shù)據(jù),要么在新數(shù)據(jù)不存在時插入新數(shù)據(jù)。
          const subaru=store.get(4);
          
          subaru.onsuccess=function () {
            subaru.result.colour="Green";
            store.put(subaru.result);
          }
          

          這會將數(shù)據(jù)庫中 Silver 色的 Subaru 的顏色更新為綠色。

          • 刪除:可以使用 delete API 來刪除數(shù)據(jù),最簡單的方法是通過其 key 來刪除:
          const deleteCar=store.delete(1);
          
          deleteCar.onsuccess=function () {
            console.log("Removed");
          };
          

          如果不知道 key 并且希望根據(jù)值來刪除,可以這樣:

          const redCarKey=colourIndex.getKey(["Red"]);
          
          redCarKey.onsuccess=function () {
            const deleteCar=store.delete(redCarKey.result);
          
            deleteCar.onsuccess=function () {
              console.log("Removed");
            };
          };
          

          結(jié)果如下:

          5. 存儲空間分析

          可以使用基于 Promise 的 Storage API 檢查 Web Storage、IndexedDB 和 Cache API 的剩余空間。異步 .estimate() 方法返回:

          • quota 屬性:可用的空間;
          • usage 屬性:已用的空間。
          (async ()=> {
            if (!navigator.storage) return;
          
            const storage=await navigator.storage.estimate();
          
            console.log(`可用大小: ${ storage.quota / 1024 } Kb`);
            console.log(`已用大小: ${ storage.usage / 1024 } Kb`);
            console.log(`已用占比: ${ Math.round((storage.usage / storage.quota) * 100) }%`);
            console.log(`剩余大小: ${ Math.floor((storage.quota - storage.usage) / 1024) } Kb`);
          })();
          

          Storage API 的瀏覽器兼容性如下:

          素的顯示與隱藏

          使用CSS讓元素不可見的方法很多,剪裁、定位到屏幕外、透明度變化等都是可以的。雖然它們都是肉眼看不見,但背后卻在多個維度上都有差別

          下面是總結(jié)的一些比較好的隱藏實踐,大家一起來根據(jù)實際開發(fā)場景來選擇合適的使用

          比較好的隱藏實踐

          不占空間,資源可以加載,DOM可訪問 使用display:none

          不占空間,隱藏顯示時有transition效果

          占空間,不能點擊 visibility: hidden

          不占空間,不能點擊,鍵盤能訪問 clip裁切

          占空間,不能點擊,鍵盤能訪問 relative

          占空間,可以點擊 opacity

          隱藏文字 使用text-indent

          根據(jù)實際的隱藏場景選擇合適的隱藏方法,這里就不再多說了,接著往下看吧

          display與元素的顯隱

          我們都知道display如果值為none,則該元素以及所有后代元素都隱藏,反之如果值是非none的情況,則都為顯示了

          display可以說是web顯隱交互中出場頻率最高的一種隱藏方式,是真正意義上的隱藏,干凈利落,不留痕跡

          none做到了無法點擊、無法使用屏幕閱讀器等輔助設(shè)備訪問,不占空間,其實不僅僅是這樣,更應(yīng)該知道的是

          me: 我有酒,那么別說你沒有故事

          我知道display:none你才不是一個沒有故事的女同學(xué)

          display: none的元素的background-image圖片根據(jù)不同瀏覽器的情況加載情況不一

          在Firefox瀏覽器下,display:none的background-image圖片不加載,包括父元素display:none也是如此在Chrome和Safari瀏覽器,則根據(jù)父元素是否是否為none來影響圖片加載情況,父元素帶有display:none,圖片不加載。

          父元素不帶有display:none,而自身有背景圖元素帶的話,那也照樣加載

          3.在IE瀏覽器下,無論怎么搞都會請求圖片資源,就是這么任性

          因此,在實際開發(fā)的時候,例如頭圖輪播切換效果

          那些默認需要隱藏的圖片作為背景圖藏在display:none元素的子元素上,這樣的細小改動就可以明顯提升頁面的加載體驗,也是非常實用的小技巧

          whatever

          上面說的興致盎然,但實際中不可能全部都是背景圖去加載圖片資源的

          還有另外一個好朋友,img元素,然并卵的是,上面說了一大堆加載不加載的情況,對img來說沒個鳥用,人家不管你none不none的,依舊帶著勇闖天涯的氣概去請求著資源

          活久見

          都說display:none做事最純粹,最干凈,不能被點擊,觸碰到,然而下面這種情況又是什么鬼?

          出來解釋解釋,我們都是文明人是絕對不會動武的!

          隱藏的按鈕會觸發(fā)click,觸發(fā)表單提交,此現(xiàn)象出現(xiàn)在時髦的瀏覽器中(IE9+,現(xiàn)代標準瀏覽器中)

          既然有這種例外情況那加了display:none的意義又是什么呢?

          很多都是純天然的

          HTML中有很多標簽和屬性天然自帶display:none

          HTML5中新增了hidden這個布爾屬性,可以讓元素天生隱藏起來

          既然說到了visibility了,那么就趕緊邀請visibility閃亮登場吧

          visibility與元素的顯隱

          visibility要為自己正名,不僅僅是保留空間這么簡單

          看點多多:

          繼承性(最有意思的一個特點,不是我說的)

          2. 與css計數(shù)器

          visibility:hidden雖然讓元素不可見了,但是不影響其計數(shù)效果,不會重新計算結(jié)果

          3. 與transition

          設(shè)置了visibility:hidden的元素,可以很好的展現(xiàn)transition過渡效果

          這是因為transition支持的css屬性中有visibility(果然是兄弟),而并沒有display屬性

          4.與JS

          visibility:hidden除了對transition友好外,對js來說也很友好

          在實際開發(fā)中,需要對隱藏元素進行尺寸和位置的獲取,來實現(xiàn)布局精確定位的交互

          此時,就建議使用visibility:hidden

          好了以上內(nèi)容要告一段落了,我們繼續(xù)開始新的征程吧,哈哈

          用戶界面樣式

          用戶界面樣式指的是CSS世界中用來幫助用戶進行界面交互的一些CSS樣式,主要有outline和cursor等屬性

          和border形似的outline屬性

          outline表示元素的輪廓,語法也和border一樣,分為寬度、類型和顏色三個值

          樣式表示上相同,但是設(shè)計的初衷卻是不太相同的,這一點天地日月可鑒

          outline是一個和用戶體驗密切相關(guān)的屬性,與focus狀態(tài)以及鍵盤訪問密切相關(guān)

          對于按鈕或鏈接,通常的鍵盤操作是:Tab鍵按次序不斷focus控件元素(鏈接、按鈕、輸入框等表單元素),或者focus設(shè)置了tabindex的普通元素,然后按Shift+Tab是反向訪問

          重點來了!

          默認狀態(tài)下,對于處于focus狀態(tài)的元素,瀏覽器會通過發(fā)光or虛框的形式進行區(qū)分和提示,這是友好的用戶體驗,很有必要,不然用戶很難知道自己當(dāng)前聚焦在了哪個元素上面,會迷失自我

          元素如果聚焦到了a鏈接上,按下回車鍵就會跳轉(zhuǎn)到相應(yīng)鏈接,以上的交互都是基于鍵盤訪問的,這就是為什么outline和鍵盤訪問如此親密了

          不專業(yè)的行為

          很多時候直接在reset樣式的時候,寫成如下形式是非常不可取的

          這樣直接一竿子打死一群鴨子的做法是不對的,更多的時候是因為瀏覽器內(nèi)置的focus效果和設(shè)計風(fēng)格格格不入,才需要重置,而且要使用專門的類名

          最后再強調(diào)一遍:萬萬不可在全局設(shè)置outline: 0 none;

          這樣的操作會造成鍵盤訪問的時候用戶找不到當(dāng)前焦點,容易產(chǎn)生困擾的,為了大家好,收斂一下吧

          下面來點干貨: 在實際開發(fā)中,有時候需要讓普通元素代替表單控件元素有outline效果

          舉個栗子:submit按鈕來完成UI設(shè)計是非常麻煩的,所以使用label元素來移花接木,通過for屬性和這些原生的表單控件相關(guān)聯(lián)

          真正的不占據(jù)空間的outline及其應(yīng)用

          outline是一個真正意義上不占任何空間的屬性,Amazing

          頭像剪裁的矩形鏤空效果

          先來看個效果圖

          上圖就是矩形鏤空效果,那么下面直接上代碼,滿滿的干貨

          用一個大大的outline來實現(xiàn)周圍半透明的黑色遮罩,因為outline無論設(shè)置多么多么大,都不會占據(jù)空間影響布局,至于超出的部分,直接給父元素設(shè)置一個overflow:hidden就搞定了 注意:

          自動填滿屏幕剩余空間的應(yīng)用技巧

          開發(fā)中很多時候,由于頁面內(nèi)容不夠多,導(dǎo)致底部footer會出現(xiàn)尷尬的剩余空間,解決方法往往也有很多種,在此我們還是依然利用outline的功能來完美實現(xiàn)一下

          關(guān)鍵的css就是設(shè)置一個超大輪廓范圍的outline屬性,如給個9999px,保證無論屏幕多高,輪廓顏色都能覆蓋

          值得注意的是,outline無法指定方位,它是直接向四周發(fā)散的,所以需要配合clip剪裁來進行處理,以左邊和上邊為邊界進行裁剪

          光標屬性

          光標屬性cursor我們真的是最熟悉的陌生人啊

          為什么這么說呢,因為在眾多的屬性值面前,我們似乎只用到了pointer(手形)(最常用的,沒有之一),move(移動),default(系統(tǒng)默認)這幾樣

          在cursor的世界里,遠比我們想象的要豐富很多,下面按照功能特性來對其進行分類吧

          琳瑯滿目的cursor屬性值

          友情不友情的小提示:☆(表示常用)

          鏈接和狀態(tài)

          cursor: progress; 進行中

          選擇

          拖拽都是CSS3新增的光標類型

          以上內(nèi)容就介紹完了用戶界面樣式的全部內(nèi)容了,還有最后一章的冷知識,大家不要方,繼續(xù)看下去,了解一下,了解一下,了解一下

          流向的改變

          說出來你可能不信,direction可以改變水平流向,盡管知道或者使用過的人少之又少,但并不妨礙它的發(fā)光發(fā)熱

          而且屬性簡單好記,值少,兼容極好ie6支持,可以來挖掘一下它的神奇功效

          direction

          僅僅兩個值:

          direction: rtl;

          當(dāng)然看到這里你可能會感覺,這些說起來都沒什么鳥用,因為大招是不輕易放出的,而真正有用的地方在于改變網(wǎng)頁布局的時候

          direction屬性默認有一個特性

          可以改變替換元素(img,input,textarea,select)或inline-block/inline-table元素的水平呈現(xiàn)順序

          舉個例子:顛倒順序

          再舉個例子:

          比如制作彈窗組件的時候,確認和取消按鈕有的時候會根據(jù)用戶的使用行為會顯示在不同的位置

          下面來看看這種特性的表現(xiàn)在實際開發(fā)中的作用

          windows用戶看到的樣子

          好了,direction的話題就告一段落,接下來介紹最后一個知識了,堅持住,快休息了

          writing-mode

          改變CSS世界縱橫規(guī)則的writing-mode,如此強大的功能,居然沒有被大家發(fā)掘和廣發(fā)應(yīng)用起來,實屬遺憾了,話不多說,往下看

          writing-mode作用及真正需要關(guān)注的屬性值

          writing-mode可以改變排版,變成垂直流,如下圖所示

          在使用語法上,也是需要記兩套的,一套是IE私有屬性,一套是CSS3規(guī)范屬性

          CSS3語法:

          IE語法:

          針對實戰(zhàn)版來整理一份writing-mode是這樣的

          對于垂直排版來說,實際開發(fā)是很少會遇到的,不過還是要說說writing-mode帶來的改變

          水平方向也能margin合并

          我們都知道兩個相鄰的元素垂直的margin會合并,當(dāng)元素變?yōu)榇怪绷鞯臅r候,水平的margin也會合并

          普通塊元素可以使用margin: auto實現(xiàn)垂直居中

          text-align:center實現(xiàn)圖片垂直居中(同上實現(xiàn)的效果)

          實現(xiàn)全兼容的icon fonts圖標旋轉(zhuǎn)效果

          老IE下讓小圖標旋轉(zhuǎn)很麻煩,writing-mode把文檔變成垂直流的時候,英文、數(shù)字和字符號都天然的轉(zhuǎn)了90°

          @font-face的兼容性很好IE5.5就支持了,所以就算是IE6和IE7也沒問題

          好了,這就是《CSS世界》里最后三章的全部內(nèi)容了,終于寫完了,哈哈,希望大家有收獲一些冷知識。

          簡單說兩句

          做個個人的小總結(jié)吧:

          css有很多奇妙的地方,在某些特性當(dāng)初被設(shè)計出來的時候可能只是為了某些圖文排版而生

          但是我們可以利用它們帶來的特性發(fā)揮自己的創(chuàng)造力,實現(xiàn)其他很多意想不到的效果,因此,上面所講述的所有知識點,盡管很多內(nèi)容都有點奇技淫巧以悅婦孺的過程

          但這也給我們開發(fā)的過程中,提供了一些很出奇的妙招,值得我們好好學(xué)習(xí)領(lǐng)悟

          感謝個位的觀看了,再見了,哈哈


          主站蜘蛛池模板: 日韩精品成人一区二区三区| 一区二区三区电影网| 国产av夜夜欢一区二区三区| 国产爆乳无码一区二区麻豆| 男人免费视频一区二区在线观看 | 国产成人一区二区三区高清| 色欲精品国产一区二区三区AV| 亚洲国模精品一区| 国产一区二区三区樱花动漫| 亚洲AV无码一区二区三区久久精品 | 中文人妻无码一区二区三区| 污污内射在线观看一区二区少妇 | 99国产精品一区二区| 国产一区二区三区在线电影| 激情久久av一区av二区av三区| 亚洲AV无码一区二区乱子仑| 日韩在线一区二区| 亚洲av成人一区二区三区在线播放 | 亚洲狠狠狠一区二区三区| 国产成人AV区一区二区三| 国内精品视频一区二区三区八戒| 亚洲国产一区二区a毛片| 免费av一区二区三区| 日韩免费视频一区二区| 高清一区二区三区免费视频| 久久99精品一区二区三区| 一区二区中文字幕| 亚洲一区电影在线观看| 中文字幕av人妻少妇一区二区| 国产香蕉一区二区精品视频| 极品尤物一区二区三区| 国模无码视频一区二区三区| 国产丝袜无码一区二区视频| 亚洲一区二区三区在线视频| 亚洲线精品一区二区三区影音先锋 | 中文字幕AV一区二区三区| 亚洲av无码一区二区三区天堂| 亚洲熟女综合一区二区三区| 风间由美在线亚洲一区| 中文乱码精品一区二区三区| 日韩人妻精品一区二区三区视频|