日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

IndexedDB_Web 离线数据库

發布時間:2025/3/8 数据库 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 IndexedDB_Web 离线数据库 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

IndexedDB_Web 離線數據庫

本文會從頭剖析一下 IndexedDB 在前端里面的應用的發展。

indexedDB 目前在前端慢慢得到普及和應用。它正朝著前端離線數據庫技術的步伐前進。以前一開始是 manifest、localStorage、cookie 再到 webSQL,現在 indexedDB 逐漸被各大瀏覽器認可。我們也可以針對它來進行技術上創新的開發。比如,現在小視頻非常流行,那么我們可以在用戶觀看時,通過 cacheStorage 緩存,然后利用 WebRTC 技術實現 P2P 分發的控制,不過需要注意,一定要合理利用大小,不然后果真的很嚴重。

indexedDB 的整體架構,是由一系列單獨的概念串聯而成,全部概念如下列表。一眼看去會發現沒有任何邏輯,不過,這里我順手畫了一幅邏輯圖,中間會根據 函數 的調用而相互串聯起來

  • IDBRequest
  • IDBFactory
  • IDBDatabase
  • IDBObjectStore
  • IDBIndex
  • IDBKeyRange
  • IDBCursor
  • IDBTransaction

整體邏輯圖如下:

本文講解流程:

下文主要介紹了 indexedDB 的基本概念,以及在實際應用中的實操代碼。

  • indexedDB 基礎概念。在 indexedDB 里面會根據索引 index 來進行整體數據結構的劃分。
  • indexedDB 數據庫的更新是一個非常蛋疼的事情,因為,Web 的靈活性,你既需要做好向上版本的更新,也需要完善向下版本的容錯性。
  • indexedDB 高效索引機制,在內部,indexedDB 已經提供了 index、cursor等高效的索引機制,推薦不要直接將所有數據都取回來,再進行篩選,而是直接利用 cursor 進行。
  • 最后推薦幾個常用庫

離線存儲

IndexedDB 可以存儲非常多的數據,比如 Object,files,blobs 等,里面的存儲結構是根據 Database 來進行存儲的。每個 DB 里面可以有不同的 object stores。具體結構如下圖:

并且,我們可以給 key 設定相關特定的值,然后在索引的時候,可以直接通過 key 得到具體的內容。使用 IndexDB 需要注意,其遵循的是同域原則。

indexDB 基本概念

在 indexDB 中,有幾個基本的操作對象:

  • Database: 通過 open 方法直接打開,可以得到一個實例的 DB。每個頁面可以創建多個 DB,不過一般都是一個。
idb.open(name, version, upgradeCallback)
  • Object store: 這個就是 DB 里面具體存儲的對象。這個可以對應于 SQL 里面的 table 內容。其存儲的結構為:

  • index: 有點類似于外鏈,它本身是一種 Object store,主要是用來在本體的 store 中,索引另外 object store 里面的數據。需要區別的是,key 和 index 是不一樣的。可以參考: index DEMO,mdn index。如下圖表示:

如下 code 為:

// 創建 index var myIndex = objectStore.index('lName');
  • transaction: 事務其實就是一系列 CRUD 的集合內容。如果其中一個環節失敗了,那么整個事務的處理都會被取消。例如:
var trans1 = db.transaction("foo", "readwrite"); var trans2 = db.transaction("foo", "readwrite"); var objectStore2 = trans2.objectStore("foo") var objectStore1 = trans1.objectStore("foo") objectStore2.put("2", "key"); objectStore1.put("1", "key");
  • cursor: 主要是用來遍歷 DB 里面的數據內容。主要是通過 openCursor 來進行控制。
function displayData() {var transaction = db.transaction(['rushAlbumList'], "readonly");var objectStore = transaction.objectStore('rushAlbumList');objectStore.openCursor().onsuccess = function(event) {var cursor = event.target.result;if(cursor) {var listItem = document.createElement('li');listItem.innerHTML = cursor.value.albumTitle + ', ' + cursor.value.year;list.appendChild(listItem); cursor.continue();} else {console.log('Entries all displayed.');}}; }

如何使用 IndexDB

上面說了幾個基本的概念。那接下來我們實踐一下 IndexDB。實際上入門 IndexDB 就是做幾個基本的內容

  • 打開數據庫表
  • 設置指定的 primary Key
  • 定義好索引的 index

前期搭建一個 IndexedDB 很簡單的代碼如下:

var request = indexedDB.open(dbName, 2);request.onerror = function(event) {// 錯誤處理程序在這里。 }; request.onupgradeneeded = function(event) {var db = event.target.result;// 設置 id 為 primaryKey 參數var objectStore = db.createObjectStore("customers", { keyPath: "id",{autoIncrement:true} });// 設置指定索引,并確保唯一性objectStore.createIndex("name", "name", { unique: false });objectStore.createIndex("email", "email", { unique: true });};

上面主要做了 3 件事:

  • 打開數據庫表
  • 新建 Store,并設置 primary Key
  • 設置 index

打開數據庫表主要就是版本號和名字,沒有太多講的,我們直接從創建 store 開始吧。

創建 Object Store

使用的方法就是 IDBDatabase 上的 createObjectStore 方法。

var objectStore = db.createObjectStore("customers", { keyPath: "id",{autoIncrement:true} });

基本函數構造為:

IDBObjectStore createObjectStore(DOMString name,optional IDBObjectStoreParameters options)dictionary IDBObjectStoreParameters {(DOMString or sequence<DOMString>)? keyPath = null;boolean autoIncrement = false; };
  • keyPath: 用來設置主鍵的 key,具體區別可以參考下面的 keyPath 和 generator 的區別。
  • autoIncrement: 是否使用自增 key 的特性。

設置索引 index

在完成 PK(Primary key) 創建完畢后,為了更好的搜索性能我們還需要額外創建 index。這里可以直接使用:

objectStore.createIndex('indexName', 'property', options);
  • indexName: 設置當前 index 的名字
  • property: 從存儲數據中,指明 index 所指的屬性。

其中,options 有三個選項:

  • unique: 當前 key 是否能重復 (最常用)
  • multiEntry: 設置當前的 property 為數組時,會給數組里面每個元素都設置一個 index 值。
# 創建一個名字叫 titleIndex 的 index,并且存儲的 index 不能重復 DB.createIndex('titleIndex', 'title', {unique: false});

具體可以參考:MDN createIndex Prop 和 googleDeveloper Index。

增刪數據

在 IndexedDB 里面進行數據的增刪,都需要在 transaction 中完成。而這個增刪數據,大家可以理解為一次 request,相當于在一個 transaction 里面管理所有當前邏輯操作的 request。所以,在正式開始進行數據操作之前,還需要給大家簡單介紹一些如果創建一個事務。

事務的創建

transaction API,如下 [代碼1]。在創建時,你需要手動指定當前 transaction 是那種類型的操作,基本的內容有:

  • “readonly”:只讀
  • “readwrite”:讀寫
  • “versionchange”:這個不能手動指定,會在 upgradeneeded 回調事件里面自動創建。它可以用來修改現有 object store 的結構數據,比如 index 等。

你可以通過在數據庫打開之后,通過 IDBDataBase 上的 transaction 方法創建,如 [代碼2]。

[代碼1][NewObject] IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames,optional IDBTransactionMode mode = "readonly");[代碼2] var transaction = db.transaction(["customers"], "readwrite"); var objectStore = transaction.objectStore("customers"); # 遍歷存儲數據 for (var i in customerData) {var request = objectStore.add(customerData[i]);request.onsuccess = function(event) {// success, done?}; }

事務在創建的時候不僅僅可以制定執行的模式,還可以指定本次事務能夠影響的 ObjectStore 范圍,具體細節就是在第一個 transaction 參數里面傳入的是一個數據,然后通過 objectStore() 方法打開多個 OS 進行操作,如下 [代碼3]。

[代碼3] var tx = db.transaction(["books","person"], "readonly"); var books = tx.objectStore("books"); var person = tx.objectStore("person");

操作數據

完成了事務的創建之后,我們就可以正式的開始進行數據的交互操作了,也就是寫我們具體的業務邏輯。如下 [代碼1],一個完整數據事務的操作。

[代碼1] var tx = db.transaction("books", "readwrite"); var store = tx.objectStore("books");store.put({title: "Quarry Memories", author: "Fred", isbn: 123456}); store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567}); store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});tx.oncomplete = function() {// All requests have succeeded and the transaction has committed. };

通過 objectStore 回調得到的 IDBObjectStore 對象,我們就可以進行一些列的增刪查改操作了。可以參考 [代碼2]。詳細的可以參考文末的 appendix。

[代碼2][NewObject] IDBRequest put(any value, optional any key);[NewObject] IDBRequest add(any value, optional any key);[NewObject] IDBRequest delete(any query);

索引數據

索引數據是所有數據庫里面最重要的一個。這里,我們可以使用游標,index 來做。例如,通過 index 來快速索引 key 值,參考 [代碼1]。

[代碼1] var index = objectStore.index("name"); index.get("Donna").onsuccess = function(event) {alert("Donna's SSN is " + event.target.result.ssn); };

更詳細的內容,可以參考下文 數據索引方式。

keyPath 和 key Generator

何謂 keyPath 和 keyGenerator 應該算是 IndexedDB 里面比較難以理解的概念。簡單來說,IndexedDB 在創建 Store 的時候,必須保證里面的數據是唯一的,那么得需要像其它數據庫一樣設置一個 primary Key 來區分不同數據。而 keyPath 和 Generator 就是兩種不同的設置 key 的方式。

設置 keyPath

# 設置預先需要存放的數據const customerData = [{ ssn: "444-44-4444", name: "Bill", age: 35, email: "bill@company.com" },{ ssn: "555-55-5555", name: "Donna", age: 32, email: "donna@home.org" } ];# 通過 keyPath 設置 Primary Key var objectStore = db.createObjectStore("customers", { keyPath: "ssn" });

因為 ssn 在該數據集是唯一的,所以,我們可以利用它來作為 keyPath 保證 unique 的特性。或者,可以設置為自增的鍵值,比如 id++ 類似的。

upgradeDb.createObjectStore('logs', {keyPath: 'id', autoIncrement:true});

使用 generator

generator 會每次在添加數據時,自動創建一個 unique value。這個 unique value 是和你的實際數據是分開的。里面直接通過 autoIncrement:true 來設置即可。

upgradeDb.createObjectStore('notes', {autoIncrement:true});

indexDB 打開注意事項

檢查是否支持 indexDB

if (!('indexedDB' in window)) {console.log('This browser doesn\'t support IndexedDB');return; }

版本更新: indexDB

在生成一個 indexDB 實例時,需要手動指定一個版本號。而最常用的

idb.open('test-db7', 2, function(upgradeDb) {})

這樣會造成一個問題,比如上線過程中,用戶A第一次請求返回了新版本的網頁,連接了版本2。之后又刷新網頁命中了另一臺未上線的機器,連接了舊版本1 出錯。主要原因是:

indexedDB API 中不允許數據庫中的數據倉庫在同一版本中發生變化. 并且當前 DB 版本不能和低版本的 version 連接。

比如,你一開始定義的 DB 版本內容為:

# 版本一定義的內容 db.version(1).stores({friends: "++id,name"});# 版本二修改結構為: db.version(2).stores({friends: "++id,name,shoeSize"});

如果此時,用戶先打開了 version(1),但是后面,又得到的是 version(2) 版本的 HTML,這時就會出現 error 的錯誤。

參考:
- 版本更替

版本更新

這個在 IndexDB 是一個很重要的問題。主要原因在于

indexedDB API 中不允許數據庫中的數據倉庫在同一版本中發生變化. 并且當前 DB 版本不能和低版本的 version 連接。

上面就可以抽象為一個問題:

你什么情況下需要更新 IndexDB 的版本呢?

  • 該表數據庫里面的 keyPath 時。
  • 你需要重新設計數據庫表結構時,比如新增 index
  • # 版本 1 的 DB 設計,有一個主鍵 idindex-name db .version(1) .stores({friends: '++id,name'})# 如果直接想新增一個 key,例如 male,是無法成功的 db .version(1) .stores({friends: '++id,name,male'})# 正確辦法是直接修改版本號更新 db .version(2) .stores({friends: '++id,name,male'})

    不過,如果直接修改版本號,會出現這樣一個 case:

    • 由于原始 HTML 更新問題,用戶首先訪問的是版本 1 的 A 頁面,然后,訪問更新過后的 B 頁面。這時,IndexDB 成功更新為高版本。但是,用戶下次又命中了老版本的 A 頁面,此時 A 中還是連接低版本的 IndexDB ,就會報錯,導致你訪問失敗。

    解決辦法就是,設置過濾,在 open 的時候,手動傳入版本號:

    # 打開版本 1 的數據庫 var dbPromise = idb.open('db1', 1, function(upgradeDb){...})# 打開版本 2 的數據庫 var dbPromise = idb.open('db2', 2, function(upgradeDb){...})

    不過,這樣又會造成另外一個問題,即,數據遷移(老版本數據,不可能不要吧)。這里,IndexDB 會有一個 updateCallback 給你觸發,你可以直接在里面做相關的數據遷移處理。

    var dbPromise = idb.open('test-db7', 2, function(upgradeDb) {switch (upgradeDb.oldVersion) {case 0:upgradeDb.createObjectStore('store', {keyPath: 'name'});case 1:var peopleStore = upgradeDb.transaction.objectStore('store');peopleStore.createIndex('price', 'price');} });

    在使用的時候,一定要注意 DB 版本的升級處理,比如有這樣一個 case,你的版本已經是 3,不過,你需要處理版本二的數據:

    # 將版本二 中的 name 拆分為 firstName 和 lastName db.version(3).stores({friends: "++id,shoeSize,firstName,lastName"}).upgrade(function(t) {return t.friends.toCollection().modify(function(friend) {// Modify each friend:friend.firstName = friend.name.split(' ')[0];friend.lastName = friend.name.split(' ')[1];delete friend.name;}); });

    對于存在版本 2 數據庫的用戶來說是 OK 的,但是對于某些還沒有訪問過你數據庫的用戶來說,這無疑就報錯了。解決辦法有:

    • 保留每個版本時,創建的字段和 stores
    • 在更新 callback 里面,對處理的數據判斷是否存在即可

    在 Dexie.js DB 數據庫中,需要你保留每次 DB 創建的方法,實際上是通過 添加 swtich case ,來完成每個版本的更新:

    # Dexie.js 保留 DB 數據庫 db.version(1).stores({friends: "++id,name"}); db.version(2).stores({friends: "++id,name,shoeSize"}); db.version(3).stores({friends: "++id,shoeSize,firstName,lastName"}).upgrade(...)# 內部原理,直接添加 switch case 完成版本更新 var dbPromise = idb.open('test-db7', 2, function(upgradeDb) {switch (upgradeDb.oldVersion) {case 0:upgradeDb.createObjectStore('store', {keyPath: 'name'});case 1:var peopleStore = upgradeDb.transaction.objectStore('store');peopleStore.createIndex('price', 'price');} });

    如果遇到一個頁面打開,但是另外一個頁面拉取到新的代碼進行更新時,這個時候還需要將低版本 indexedDB 進行顯式的關閉。具體操作辦法就是監聽 onversionchange 事件,當版本升級時,通知當前 DB 進行關閉,然后在新的頁面進行更新操作。

    openReq.onupgradeneeded = function(event) {// 所有其它數據庫都已經被關掉了,直接更新代碼db.createObjectStore(/* ... */);db.onversionchange = function(event) {db.close();};}

    最后,更新是還有幾個注意事項:

    • 版本更新不能改變 primary key
    • 回退代碼時,千萬注意版本是否已經更新。否則,只能增量更新,重新修改版本號來修復。

    存儲加密特性

    有時候,我們存儲時,想得到一個由一串 String 生成的 hash key,那在 Web 上應該如何實現呢?

    這里可以直接利用 Web 上已經實現的 WebCrypto,為了實現上述需求,我們可以直接利用里面的 digest 方法即可。這里 MDN 上,已經有現成的辦法,我們直接使用即可。

    參考:

    WebCrypto 加密手段

    存儲上限值

    基本限制為:

    瀏覽器限制
    Chrome可用空間 < 6%
    Firebox可用空間 < 10%
    Safari< 50MB
    IE10< 250MB

    逐出策略為:

    瀏覽器逐出政策
    Chrome在 Chrome 耗盡空間后采用 LRU 策略
    Firebox在整個磁盤已裝滿時采用 LRU 策略
    Safari無逐出
    IE10無逐出

    參考:

    存儲上限值 瀏覽器內核存儲上限值處理

    數據索引方式

    在數據庫中除了基本的 CRUD 外,一個高效的索引架構,則是里面的重中之重。在 indexedDB 中,我們一共可以通過三種方式來索引數據:

    • 固定的 key 值
    • 索引外鍵(index)
    • 游標(cursor)

    固定 key 索引

    IDBObjectStore 提供給了我們直接通過 primaryKey 來索引數據,參考 [代碼1],這種方式需要我們一開始就知道目標的 key 內容。當然,也可以通過 getAll 全部索引數據。

    [代碼1][NewObject] IDBRequest get(any query);[NewObject] IDBRequest getKey(any query);[NewObject] IDBRequest getAll(optional any query,optional [EnforceRange] unsigned long count);[NewObject] IDBRequest getAllKeys(optional any query,optional [EnforceRange] unsigned long count);

    比如,我們通過 primaryKey 得到一條具體的數據:

    db.transaction("customers").objectStore("customers").get("id_card_1118899").onsuccess = function(event) {// data is event.target.result.name };

    也可以 fetch 整個 Object Store 的數據。這些場景用處比較少,這里就不過多講解。我們主要來了解一下 index 的索引方式。

    index 索引

    如果想要查詢某個數據,直接通過整個對象來進行遍歷的話,這樣做性能耗時是非常大的。如果我們結合 index 來將 key 加以分類,就可以很快速的實現指定數據的索引。這里,我們可以直接利用 IDBObjectStore 上面的 index() 方法來獲取指定 index 的值,具體方法可以參考 [代碼1]。

    [代碼1]IDBIndex index(DOMString name);

    該方法會直接返回一個 IDBIndex 對象。這你也可以理解為一個類似 ObjectStore 的微型 index 數據內容。接著,我們可以使用 get() 方法來獲得指定 index 的數據,參考[代碼2]。

    [代碼2] var index = objectStore.index("name"); index.get("Donna").onsuccess = function(event) {alert("Donna's SSN is " + event.target.result.ssn); };

    使用 get 方法不管你的 index 是否是 unique 的都會只會返回第一個數據。如果想得到多個數據的話,可以使用 getAll(key) 來做。通過 getAll() 得到的回調函數,直接通過 event.target.result 可以得到對應的 value 內容。

    objectStore.getAll().onsuccess = function(event) {printf(event.target.result); // Array};

    除了通過 getAll() 得到所有數據外,還可以采用更高效的 cursor 方法遍歷得到的數據。

    參考:

    getAll() 和 openCursor 實例

    游標索引

    所謂的游標,大家心里應該可以有一個初步的印象,就像我們物理尺子上的那個東西,可以自由的移動,來標識指向的對象內容。cursor 里面有兩個核心的方法:

    • advance(count): 將當前游標位置向前移動 count 位置
    • continue(key): 將當前游標位置移動到指定 key 的位置,如果沒提供 key 則代表的移動下一個位置。

    比如,我們使用 cursor 來遍歷 Object Store 的具體數據。

    objectStore.openCursor().onsuccess = function(event) {var cursor = event.target.result;if(cursor) {// cursor.key // cursor.valuecursor.continue();} else {console.log('Entries all displayed.');}};

    通常,游標可以用來遍歷兩個類型的數據,一個是 ObjectStore、一個是 Index。

    • Object.store: 如果在該對象上使用游標,那么會根據 primaryKey 遍歷整個數據,注意,這里不會存在重復的情況,因為 primaryKey 是唯一的。
    • index: 在 index 上使用游標的話,會以當前的 index 來進行遍歷,其中可能會存在重復的現象。

    在 IDBObjectStore 對象上有兩種方法來打開游標:

    • openCursor: 遍歷的對象是 具體的數據值,最常用的方法
    • openKeyCursor: 遍歷的對象是 數據 key 值

    這里,我們通過 openCursor 來直接打開一個 index 數據集,然后進行遍歷。

    PersonIndex.openCursor().onsuccess = function(event) {var cursor = event.target.result;if (cursor) {customers.push(cursor.value);cursor.continue();}else {alert("Got all customers: " + customers);} };

    在游標中,還提供給了一個 update 和 delete 方法,我們可以用它來進行數據的更新操作,否則的話就直接使用 ObjectStore 提供的 put 方法。

    游標里面我們還可以限定其遍歷的范圍和方向。這個設置是我們直接在 openCursor() 方法里面傳參完成的,該方法的構造函數參考 [代碼1]。他里面可以傳入兩個參數,第一個用來指定范圍,第二個用來指定 cursor 移動的方向。

    [代碼1] IDBRequest openCursor(optional any query,optional IDBCursorDirection direction = "next");

    如果需要對 cursor 設置范圍的話,就需要使用到 IDBKeyRange 這個對象,使用樣板可以參考 [代碼2]。IDBKeyRange 里面 key 參考的對象 因使用者的不同而不同。如果是針對 ObjectStore 的話,則是針對 primaryKey,如果是針對 Index 的話,則是針對當前的 indexKey

    / 匹配所有在 “Bill” 前面的, 但是不需要包括 "Bill" var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true);

    比如,我們這里對 PersonIndex 設置一個 index 范圍,即,索引 在 villainhr 和 jimmyVV 之間的數據集合。

    # 都包括 villainhr 和 jimmyVV 的數據 var boundKeyRange = IDBKeyRange.bound("villainhr", "jimmyVV", true, true);PersonIndex.openCursor(boundKeyRange).onsuccess = function(event) {var cursor = event.target.result;if (cursor) {// Do something with the matches.cursor.continue();} };

    如果你還想設置遍歷的方向和是否排除重復數據,還可以根據 [代碼2] 的枚舉類型來設置。比如,在 [代碼3] 中,我們改變默認的 cursor 遍歷數據的方向為 prev,從末尾開始。

    [代碼2] enum IDBCursorDirection {"next","nextunique","prev","prevunique" };[代碼3] objectStore.openCursor(null, IDBCursor.prev).onsuccess = function(event) {var cursor = event.target.result;if (cursor) {// cursor.value cursor.continue();} };

    事務讀取性能

    在 indexDB 里面的讀寫全部是基于 transaction 模式來的。也就是 IDBDataBase 里面的 transaction 方法,如下 [代碼1]。所有的讀寫都可以比作在 transaction 作用域下的請求,只有當所有請求完成之后,該次 transaction 才會生效,否則就會拋出異常或者錯誤。transaction 會根據監聽 error,abort,以及 complete 三個事件來完成整個事務的流程管理,參考[代碼2]。

    [代碼1][NewObject] IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames,optional IDBTransactionMode mode = "readonly");[代碼2]attribute EventHandler onabort;attribute EventHandler oncomplete;attribute EventHandler onerror;

    例如:

    var request = db.transaction(["customers"], "readwrite").objectStore("customers").delete("gg"); request.onsuccess = function(event) {// delete, done };

    你可以在 transaction 方法里面手動傳入 readwrite 或者其他表示事務的 readonly 參數,來表示本次事務你會進行如何的操作。IndexedDB 在初始設計時,就已經決定了它的性能問題。

    只含有 readonly 模式的 transaction 可以并發進行執行 含有 write 模式的 transaction 必須按照隊列 來 執行

    這就意味著,如果你使用了 readwrite 模式的話,那么后續不管是不是 readonly 都必須等待該次 transaction 完成才行。

    常用技巧

    生成 id++ 的主鍵

    指定 primaryKey 生成時,是通過 createObjectStore 方法來操作的。有時候,我們會遇到想直接得到一個 key,并且存在于當前數據集中,可以在 options 中同時加上 keyPath 和 autoIncrement 屬性。該 key 的范圍是 [1- ],參考 keygenerator key 的大小

    db.createObjectStore('table1', {keyPath: 'id', autoIncrement: true});

    推薦

    閱讀推薦

    indexedDB W3C 文檔 indexedDB 入門 MDN indexedDB 入門

    好用庫推薦

    idb: 一個 promise 的 DB 庫

    Indexed Appendix

    • IndexedDB 數據庫使用key-value鍵值對儲存數據.你可以對對象的某個屬性創建索引(index)以實現快速查詢和列舉排序。.key可以使二進制對象
    • IndexedDB 是事務模式的數據庫. IndexedDB API提供了索引(indexes), 表(tables), 指針(cursors)等等, 但是所有這些必須是依賴于某種事務的。
    • The IndexedDB API 基本上是異步的.
    • IndexedDB 數據庫的請求都會包含 onsuccess和onerror事件屬性。
    • IndexedDB 在結果準備好之后通過DOM事件通知用戶
    • IndexedDB是面向對象的。indexedDB不是用二維表來表示集合的關系型數據庫。這一點非常重要,將影響你設計和建立你的應用程序。
    • indexedDB不使用結構化查詢語言(SQL)。它通過索引(index)所產生的指針(cursor)來完成查詢操作,從而使你可以迭代遍歷到結果集合。
    • IndexedDB遵循同源(same-origin)策略

    局限和移除 case

    • 全球多種語言混合存儲。國際化支持不好。需要自己處理。
    • 和服務器端數據庫同步。你得自己寫同步代碼。
    • 全文搜索。

    在以下情況下,數據庫可能被清除:

    • 用戶請求清除數據。
    • 瀏覽器處于隱私模式。最后退出瀏覽器的時候,數據會被清除。
    • 硬盤等存儲設備的容量到限。
    • 不正確的
    • 不完整的改變.

    常規概念

    數據庫

    • 數據庫: 通常包含一個或多個 object stores. 每個數據庫必須包含以下內容:
      • 名字(Name): 它標識了一個特定源中的數據庫,并且在數據庫的整個生命周期內保持不變. 此名字可以為任意字符串值(包括空字符串).
      • 當前版本(version). 當一個數據庫首次創建時,它的 version 為1,除非另外指定. 每個數據庫在任意時刻只能有一個 version
    • 對象存儲(object store): 用來承載數據的一個分區.數據以鍵值對形式被對象存儲永久持有。在 OS 中,創建一個 key 可以使用 key generator 和 key path。
      • key generator: 簡單來說就是在存儲數據時,主動生成一個 id++ 來區分每條記錄。這種情況下 存儲數據的 key 是和 value 分開進行存儲的,也就是 (out of line)。
      • key path: 需要用戶主動來設置儲存數據的 key 內容
      • request: 每次讀寫操作,可以當做一次 request.
      • transaction: 一系列讀寫請求的集合。
      • index: 一個特殊的 Object Store,用來索引另外一個 Store 的數據。
    • 具體數據 key/value
      • key: 這個 key 的值,可以通過三種方式生成。 a key generator, a key path, 用戶指定的值。并且,這個 key 在當前的 Object Store 是唯一的。一個 key 類型可以是 string, date, float, and array 類型。不過,在老版本的時候,一般只支持 string or integer。(現在,版本應該都 OK 了)
        • key generator: 相當于以一種 id++ 的形式來生成一個 key 值。
        • key path: 當前指定的 key 可以根據 value 里面的內容來指定。里面可以為一些分隔符。
        • 指定的 key:這個就是需要用戶手動來指定生成。
      • value: 可以存儲 boolean, number, string, date, object, array, regexp, undefined, and null。現在還可以存儲 files and blob 對象。

    操作作用域

    • scope:這可以比作 transaction 的作用域,即,一系列 transaction 執行的順序。該規定,多個 reading transaction 能夠同時執行。但是 writing 則只能排隊進行。
    • key range: 用來設置取出數據的 key 的范圍內容。

    參考:

    原生概念 IndexedDB

    IDBFactory

    這其實就是 indexDB 上面掛載的對象。主要 API 如下:

    [Exposed=(Window,Worker)] interface IDBFactory {[NewObject] IDBOpenDBRequest open(DOMString name,optional [EnforceRange] unsigned long long version);[NewObject] IDBOpenDBRequest deleteDatabase(DOMString name);short cmp(any first, any second); };

    你可以直接通過 open 來打開一個數據庫。通過 返回一個 Request 對象,來進行結果監聽的回調:

    var request = indexedDB.open('AddressBook', 15); request.onsuccess = function(evt) {...}; request.onerror = function(evt) {...};

    參考:

    IndexDB Factory API

    IDBRequest

    當你通過 open 方法處理過后,就會得到一個 Request 回調對象。這個就是 IDBRequest 的實例。

    [Exposed=(Window,Worker)] interface IDBRequest : EventTarget {readonly attribute any result; // 通過 open 打開過后的 IDBObjectStore 實例 readonly attribute DOMException? error;readonly attribute (IDBObjectStore or IDBIndex or IDBCursor)? source;readonly attribute IDBTransaction? transaction;readonly attribute IDBRequestReadyState readyState;// Event handlers:attribute EventHandler onsuccess;attribute EventHandler onerror; };enum IDBRequestReadyState {"pending","done" };[Exposed=(Window,Worker)] interface IDBOpenDBRequest : IDBRequest {// Event handlers:attribute EventHandler onblocked;attribute EventHandler onupgradeneeded; };

    你可以通過 result 得到當前數據庫操作的結果。如果你打開更新后的版本號的話,還需要監聽 onupgradeneeded 事件來實現。最常通過 indexedDB.open 遇見的錯誤就是 VER_ERR 版本錯誤。這表明存儲在磁盤上的數據庫的版本高于你試圖打開的版本。

    db.onerror = function(event) {// Generic error handler for all errors targeted at this database's// requests!alert("Database error: " + event.target.errorCode); };

    所以,一般在創建 IndexDB 時,還需要管理它版本的更新操作,這里就需要監聽 onupgradeneeded 來是實現。

    request.onupgradeneeded = function(event) { // 更新對象存儲空間和索引 .... };

    或者我們可以直接使用 idb 微型庫來實現讀取操作。

    var dbPromise = idb.open('test-db3', 1, function(upgradeDb) {if (!upgradeDb.objectStoreNames.contains('people')) {upgradeDb.createObjectStore('people', {keyPath: 'email'});}if (!upgradeDb.objectStoreNames.contains('notes')) {upgradeDb.createObjectStore('notes', {autoIncrement: true});}if (!upgradeDb.objectStoreNames.contains('logs')) {upgradeDb.createObjectStore('logs', {keyPath: 'id', autoIncrement: true});}});

    其中通過 onupgradeneeded 回調得到的 event.result 就是 IDBDatabase 的實例,常常用來設置 index 和插入數據。參考下面內容。

    參考:

    IDBRequest API

    IDBDatabase

    該對象常常用來做 Object Store 和 transaction 的創建和刪除。該部分是 onupgradeneeded 事件獲得的 event.target.result 對象:

    request.onupgradeneeded = function(event) { // 更新對象存儲空間和索引 .... // event.target.result 對象 };

    具體 API 內容如下:

    [Exposed=(Window,Worker)] interface IDBDatabase : EventTarget {readonly attribute DOMString name;readonly attribute unsigned long long version;readonly attribute DOMStringList objectStoreNames;[NewObject] IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames,optional IDBTransactionMode mode = "readonly");void close();[NewObject] IDBObjectStore createObjectStore(DOMString name,optional IDBObjectStoreParameters options);void deleteObjectStore(DOMString name);// Event handlers:attribute EventHandler onabort;attribute EventHandler onclose;attribute EventHandler onerror;attribute EventHandler onversionchange; };dictionary IDBObjectStoreParameters {(DOMString or sequence<DOMString>)? keyPath = null;boolean autoIncrement = false; };

    如果它通過 createObjectStore 方法,那么得到的就是一個 IDBObjectStore 實例對象。如果是 transaction 方法,那么就是 IDBTransaction 對象。

    IDBObjectStore

    該對象一般是用來創建 index 和插入數據使用。

    可以參考:

    [Exposed=(Window,Worker)] interface IDBObjectStore {attribute DOMString name;readonly attribute any keyPath;readonly attribute DOMStringList indexNames;[SameObject] readonly attribute IDBTransaction transaction;readonly attribute boolean autoIncrement;[NewObject] IDBRequest put(any value, optional any key);[NewObject] IDBRequest add(any value, optional any key);[NewObject] IDBRequest delete(any query);[NewObject] IDBRequest clear();[NewObject] IDBRequest get(any query);[NewObject] IDBRequest getKey(any query);[NewObject] IDBRequest getAll(optional any query,optional [EnforceRange] unsigned long count);[NewObject] IDBRequest getAllKeys(optional any query,optional [EnforceRange] unsigned long count);[NewObject] IDBRequest count(optional any query);[NewObject] IDBRequest openCursor(optional any query,optional IDBCursorDirection direction = "next");[NewObject] IDBRequest openKeyCursor(optional any query,optional IDBCursorDirection direction = "next");IDBIndex index(DOMString name);[NewObject] IDBIndex createIndex(DOMString name,(DOMString or sequence<DOMString>) keyPath,optional IDBIndexParameters options);void deleteIndex(DOMString name); };dictionary IDBIndexParameters {boolean unique = false;boolean multiEntry = false; };

    IDBIndex

    該對象是用來進行 Index 索引的操作對象,里面也會存在 get 和 getAll 等方法。詳細內容如下:

    [Exposed=(Window,Worker)] interface IDBIndex {attribute DOMString name;[SameObject] readonly attribute IDBObjectStore objectStore;readonly attribute any keyPath;readonly attribute boolean multiEntry;readonly attribute boolean unique;[NewObject] IDBRequest get(any query);[NewObject] IDBRequest getKey(any query);[NewObject] IDBRequest getAll(optional any query,optional [EnforceRange] unsigned long count);[NewObject] IDBRequest getAllKeys(optional any query,optional [EnforceRange] unsigned long count);[NewObject] IDBRequest count(optional any query);[NewObject] IDBRequest openCursor(optional any query,optional IDBCursorDirection direction = "next");[NewObject] IDBRequest openKeyCursor(optional any query,optional IDBCursorDirection direction = "next"); };

    參考:

    idb 開源庫,微型代碼庫 treo 開源庫 dexie.js 開源庫 indexeddb 原生概念 IndexedDB

    總結

    以上是生活随笔為你收集整理的IndexedDB_Web 离线数据库的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    国产丝袜 | 国产精品午夜av | 日韩av电影中文字幕在线观看 | 亚洲免费在线观看视频 | 黄污视频大全 | 日韩视频一区二区三区在线播放免费观看 | 香蕉视频啪啪 | 99视频| 成人黄大片视频在线观看 | 国产精品久久99综合免费观看尤物 | 日韩在线观看中文字幕 | 国产麻豆精品免费视频 | 国产在线一区二区三区播放 | 久久午夜免费视频 | 色偷偷人人澡久久超碰69 | 亚州精品在线视频 | 天天天天色综合 | 五月婷婷在线观看视频 | 黄色毛片在线观看 | 国产精品一区二区免费视频 | 国产99久久99热这里精品5 | 国产69精品久久久久9999apgf | 在线中文字母电影观看 | 免费在线观看av网址 | 超碰成人网 | 99久久精品国产网站 | 中文字幕色在线 | 69久久久久久久 | 欧美在一区 | 久久免费中文视频 | 国产中文在线观看 | 一本一本久久a久久精品综合 | 91黄色免费网站 | 久久久999免费视频 日韩网站在线 | 亚洲成人动漫在线观看 | 美女网站黄在线观看 | 日韩激情第一页 | 成人小视频在线播放 | 91桃花视频 | 成人免费在线视频观看 | 五月婷婷一区二区三区 | 在线观看亚洲国产 | 久久综合九色综合久99 | 成人性生交视频 | 91成人在线网站 | 国产黄色高清 | 午夜国产在线 | 免费观看国产精品 | 99re国产视频 | 视频在线一区 | 97国产情侣爱久久免费观看 | 国产成人精品国内自产拍免费看 | 亚洲精品久久久久中文字幕m男 | 奇米影视8888在线观看大全免费 | 成人在线免费av | 三级av免费| 九九久久视频 | 国产精品嫩草69影院 | 天天干婷婷 | 91久久久久久久 | 91免费日韩 | 久草五月 | 精品视频在线观看 | 国产中文字幕久久 | 狠狠干 狠狠操 | 天天干天天做 | 香蕉久草在线 | 在线观看亚洲精品视频 | 色婷婷激婷婷情综天天 | 成年人毛片在线观看 | 日本性生活免费看 | 丁香激情网 | 精品产品国产在线不卡 | 九九在线国产视频 | 人人插人人玩 | 九九免费在线看完整版 | 青青河边草免费观看 | 亚洲午夜精 | 婷婷深爱网| 婷婷爱五月天 | 国产色拍 | 国产精品女 | 91亚洲网 | 免费日韩av电影 | 久久精品欧美一区 | 美女免费视频黄 | 狠狠躁日日躁狂躁夜夜躁 | 国产一区二区播放 | 欧美日韩1区2区 | 又污又黄网站 | 久久久久久免费网 | 国模精品一区二区三区 | 麻豆视频成人 | а天堂中文最新一区二区三区 | 亚洲精品xx | 成人cosplay福利网站 | 国产精品久久久久久婷婷天堂 | 免费观看黄 | 日韩欧美精品在线 | 亚洲精选在线 | 在线看毛片网站 | 国产在线视频导航 | 久久草在线精品 | 东方av免费在线观看 | 91看片网址| 国产精品久久久 | 国产福利a | 天堂在线一区二区 | 欧美va天堂va视频va在线 | 色狠狠一区二区 | 日韩网站一区二区 | 黄色软件在线看 | 视频福利在线观看 | 久久草在线免费 | 国产99久久99热这里精品5 | 国产视频一区在线 | 久久久久久美女 | 亚洲精品国偷拍自产在线观看蜜桃 | 成人在线观看网址 | 久久公开免费视频 | 国产一级在线免费观看 | 依人成人综合网 | 国产日女人 | 欧美日韩高清在线一区 | 蜜臀aⅴ国产精品久久久国产 | 99在线热播 | 久久久人 | 夜夜爽www | 国产一区二区午夜 | 最新动作电影 | 中文字幕视频免费观看 | 精品国产免费久久 | 一级电影免费在线观看 | 日韩专区在线观看 | 精品久久久久国产免费第一页 | 韩国三级在线一区 | 激情网在线视频 | 超碰在线观看97 | 久久久久国产一区二区三区 | 免费国产在线观看 | av在线短片 | 天天爽天天碰狠狠添 | 激情黄色一级片 | 久久呀| 日躁夜躁狠狠躁2001 | 人人操日日干 | 成人免费视频网 | 激情网站免费观看 | 人人草网站| 亚洲精品综合欧美二区变态 | av大片免费在线观看 | 亚洲精品一区二区三区高潮 | 成人av一区二区兰花在线播放 | 国产小视频你懂的 | 在线观看小视频 | 一级c片 | 青春草免费在线视频 | 黄色小网站在线 | 精品视频www | 免费av电影网站 | 婷婷亚洲激情 | 亚州精品成人 | 成人av在线直播 | 日韩精品一区二区三区免费视频观看 | 国产精品麻豆果冻传媒在线播放 | 亚洲国产欧洲综合997久久, | 少妇av网 | 国产99久久九九精品免费 | 午夜12点 | 精品专区一区二区 | 国产成人区 | 欧美日韩国产精品一区二区三区 | 久久精品超碰 | av成人资源 | 午夜在线观看影院 | 精品一区二区在线免费观看 | 日韩欧美在线国产 | 成人在线视频你懂的 | 精品国产乱码久久久久 | 日韩免费视频线观看 | 成人午夜影院在线观看 | 国产婷婷久久 | 国产精品久久久久久影院 | 免费97视频 | 在线观看播放av | 亚洲成人二区 | 国产精品成人免费一区久久羞羞 | 国产精品久久嫩一区二区免费 | 91亚洲综合 | 91视频 - v11av| 久久另类小说 | 午夜少妇 | 欧美精品久久久久久久久久丰满 | 亚洲精品乱码久久久久 | 91电影福利 | 欧美精品中文在线免费观看 | 综合久久久久久久久 | 天天草天天干天天射 | 蜜臀aⅴ精品一区二区三区 久久视屏网 | 国产精品自产拍 | 中日韩三级视频 | 婷婷色在线播放 | 4hu视频 | 在线观看国产91 | 国产午夜在线观看 | 中文字幕在线免费观看视频 | 成人a v视频 | 久久乱码卡一卡2卡三卡四 五月婷婷久 | 免费合欢视频成人app | 亚洲美女在线国产 | 久色伊人 | 亚洲人久久| 国产一区网 | 伊人永久在线 | 中文字幕4| www.五月婷婷 | 日韩激情久久 | 久久精品官网 | 日韩免费一级a毛片在线播放一级 | 99国产精品久久久久老师 | 中文字幕欧美日韩va免费视频 | 亚洲国产精品成人综合 | 中文字幕高清有码 | 国产免费一区二区三区网站免费 | 国模视频一区二区 | 69久久久 | 九九激情视频 | 国产精品九九视频 | 色综合久久88色综合天天人守婷 | www.99热精品 | 在线看黄色的网站 | 久久伦理视频 | 91麻豆精品国产91久久久更新时间 | 在线天堂亚洲 | 免费看十八岁美女 | 人人超碰人人 | 99婷婷狠狠成为人免费视频 | 久久精品9 | 视频一区二区免费 | 96视频在线 | 国产精品一区二区三区在线看 | 国产麻豆成人传媒免费观看 | 国产精品福利小视频 | 午夜久久美女 | 亚洲狠狠婷婷综合久久久 | 国产美女在线精品免费观看 | 久久久久久久久久久电影 | 97精品免费视频 | 韩日精品中文字幕 | 四虎影院在线观看av | 日韩一级成人av | 97色视频在线 | 精品免费观看视频 | 狠狠地操 | 最近免费中文视频 | 91亚色在线观看 | 国产精品二区在线观看 | 91成人久久| 久免费| 国产精品久久久久久久久久 | 亚洲影院天堂 | 九九国产视频 | 狠狠色伊人亚洲综合成人 | 日韩在线高清免费视频 | 四虎永久国产精品 | 免费视频一级片 | 免费av 在线 | 久久夜靖品 | 国产精品一区二区三区免费看 | 亚洲一区日韩精品 | 99精品免费久久久久久久久日本 | 成人中文字幕av | 免费看黄色毛片 | 久99热| 日韩一级电影在线观看 | 久久视讯 | 在线网址你懂得 | 日韩欧美国产精品 | 色a资源在线 | 欧美精品在线观看 | av丁香花 | 日本中文字幕在线视频 | 日日夜夜草| 亚洲精品欧美精品 | 亚洲午夜久久久久 | 麻豆国产精品va在线观看不卡 | 亚洲视频久久久久 | 日本在线视频网址 | 成年人在线观看网站 | 久久中文精品视频 | 国产精品99久久久精品免费观看 | 综合天天久久 | 国产成人精品一区二区三区福利 | 亚洲精品免费视频 | 久久这里只有精品9 | 国产精品21区 | 国产一级黄色免费看 | 色多视频在线观看 | 五月天六月婷婷 | 国产乱码精品一区二区三区介绍 | 国模精品在线 | 国产精品色视频 | 国产在线超碰 | 操操操天天操 | 看片一区二区三区 | 国产一级在线免费观看 | 96超碰在线| 国产一区视频免费在线观看 | 日韩午夜一级片 | 久久久久久久久久久影视 | 9992tv成人免费看片 | 日韩av黄 | 欧美成人黄色 | 夜夜爽天天爽 | 日韩在线电影一区二区 | www.日日日.com| 国产日韩精品一区二区在线观看播放 | 97自拍超碰| 久久精品国产免费看久久精品 | 91精品网站 | 欧美日韩亚洲在线观看 | 91精品国产成人观看 | 午夜久久成人 | 亚洲精品国产精品99久久 | 亚洲免费在线视频 | 久久国产精品成人免费浪潮 | 九九久久在线看 | 91在线看片| 国产尤物一区二区三区 | 国产h片在线观看 | 91精品国产一区 | 成人在线播放av | a视频在线播放 | 日韩高清免费在线观看 | 国产69精品久久久久久 | 又湿又紧又大又爽a视频国产 | 色永久免费视频 | 国产二区视频在线观看 | 成人午夜剧场在线观看 | 激情婷婷| 国产美女在线精品免费观看 | 精品二区视频 | 国产午夜精品一区二区三区嫩草 | 国产免费区 | 午夜av激情 | 在线久热 | 国产在线久久久 | 国产精品视频地址 | 久久国产免费看 | 91丨九色丨国产在线观看 | 欧美日韩国产二区三区 | 色婷婷伊人| 精品一区二区三区久久久 | 中文字幕黄色网址 | 日韩精品免费一线在线观看 | 亚洲精品国产精品国自产 | 日韩精品一区二区三区视频播放 | 国产精品九九久久久久久久 | 99这里精品 | 国产一二区免费视频 | www.久艹 | 色狠狠综合天天综合综合 | h视频在线看 | a色视频 | 亚洲国产视频网站 | 99久高清在线观看视频99精品热在线观看视频 | 91视频com| 国产91精品一区二区麻豆网站 | 永久精品视频 | 中文字幕成人av | 久久久久成人精品亚洲国产 | 婷婷激情5月天 | 丝袜美腿在线 | 开心激情五月网 | 欧美一级免费片 | japanesexxxhd奶水 国产一区二区在线免费观看 | avav片| 久久在线观看视频 | www狠狠操 | 一区二区三区视频在线 | 天天做天天爱夜夜爽 | 久久超级碰视频 | 97视频免费 | 97精品视频在线 | 久草线 | 午夜视频在线观看一区二区三区 | 五月综合激情网 | 精品女同一区二区三区在线观看 | 国产精品s色 | 视频一区二区视频 | 国产99久久九九精品免费 | 亚洲高清在线精品 | 丁香激情婷婷 | 亚洲最新av在线网址 | 日韩三级成人 | 成人国产精品久久久久久亚洲 | 日本精品一 | av解说在线观看 | 日韩中文字幕免费在线播放 | 久草在线视频在线观看 | 婷婷色狠狠 | 韩国在线一区二区 | 午夜视频一区二区三区 | 午夜精品视频在线 | av网站地址 | 色婷婷激情 | 国产精品 国内视频 | 狠狠狠综合 | www免费看片com | 天天碰天天操视频 | 91免费在线看片 | 婷婷午夜激情 | 日韩av片免费在线观看 | 久久免费看毛片 | 91久久精品日日躁夜夜躁国产 | 成年人在线观看视频免费 | 国产亚洲精品久久久久久网站 | av在线收看 | 又黄又爽又刺激 | 99久久精品一区二区成人 | 久久草草热国产精品直播 | 欧美日韩精品在线观看 | 91av色| 91成人蝌蚪 | 国产精品久久久久免费 | 亚洲九九九在线观看 | 天天操导航 | 国产亚洲精品日韩在线tv黄 | 日韩中文字幕电影 | 久久综合色8888 | 日韩性色 | 精品国产理论片 | 国产视频第二页 | 日韩伦理片hd | 97精品国产91久久久久久 | 中文字幕在线观看你懂的 | 亚洲色图激情文学 | 2024国产精品视频 | 精品中文字幕在线 | 久久久久伦理电影 | 免费www视频 | 91精品国产网站 | 在线 视频 一区二区 | 欧美国产日韩在线视频 | 久久国产精品免费一区 | 五月婷婷影视 | 日韩在线电影一区二区 | 久久国产精品久久精品国产演员表 | 亚洲精品视频久久 | 久久亚洲在线 | 精品国产色 | 黄色毛片一级片 | 日韩高清不卡在线 | 久久成人在线视频 | 中文字幕久久精品亚洲乱码 | 天天天综合网 | 免费男女网站 | 色视频在线免费观看 | 日日干av | 国产白浆视频 | 波多野结衣视频在线 | 丝袜网站在线观看 | 国产污视频在线观看 | 国产最新在线视频 | 丁香综合网| 国产麻豆精品在线观看 | 国产精品二区三区 | 视频国产精品 | 久久只精品99品免费久23小说 | 国产精品美女久久久久久久久久久 | 久久国内精品 | 欧美日韩免费观看一区二区三区 | 中文字幕一区二区三 | 欧美成人影音 | 国产视频亚洲精品 | 夜夜操狠狠干 | 日韩在线电影一区二区 | 91久久国产露脸精品国产闺蜜 | 欧美精品九九 | 一区二区视频免费在线观看 | 亚洲狠狠操 | 日本九九视频 | 四虎成人精品永久免费av | 日日爱av | 天堂入口网站 | 超碰在线公开免费 | 伊人色**天天综合婷婷 | 91成人网在线 | 国产一区免费在线观看 | 国产麻豆精品久久一二三 | 成人黄色电影在线 | 亚洲视频在线视频 | 欧美精品久久久久久久亚洲调教 | 毛片在线播放网址 | 国产98色在线 | 日韩 | 亚洲精欧美一区二区精品 | 韩国在线一区二区 | 国产在线观看高清视频 | 久久久99精品免费观看乱色 | 中文字幕专区高清在线观看 | 日韩精品中文字幕av | 国产成人精品日本亚洲999 | 亚洲精品免费在线观看 | 国产成人亚洲精品自产在线 | 男女视频91 | 99免费在线播放99久久免费 | 久久伦理 | 一区二区伦理电影 | 九九久久久久久久久激情 | 国产精品一区二区你懂的 | 就要干b | 国内精品久久久久久久久久清纯 | 亚洲成人av影片 | 亚洲欧美综合精品久久成人 | 最近2019年日本中文免费字幕 | 狠狠干狠狠久久 | 狠狠躁日日躁狂躁夜夜躁 | 99视频国产精品免费观看 | 中文字幕在 | 亚洲视频456 | 91香蕉亚洲精品 | 丁香久久婷婷 | 色网址99 | 黄色av网站在线观看免费 | 91最新视频 | 成人va在线观看 | 在线99视频 | 成年人网站免费在线观看 | 在线黄色免费 | 久久久久亚洲精品 | 国产不卡在线看 | 91麻豆精品国产91久久久久久久久 | 在线成人性视频 | 欧美色综合久久 | av网站免费线看精品 | 97视频精品 | 国产成人一区二区三区 | 又黄又爽的免费高潮视频 | 美女福利视频在线 | 国产综合小视频 | 91精品国自产在线观看欧美 | 91麻豆精品国产91久久久久久 | 精品超碰| 久久蜜臀av | 97超碰在线人人 | 五月婷婷视频在线观看 | 国产永久免费高清在线观看视频 | 亚洲欧洲国产日韩精品 | 午夜精品99久久免费 | 在线国产欧美 | 国产精品9999久久久久仙踪林 | 天天干天天操天天做 | www.色的| 国产精品久久一卡二卡 | 精品国产乱码 | 一级黄色在线免费观看 | 欧美aa在线 | 久久精品波多野结衣 | 色综合综合 | 国产视频黄| 日韩中文字幕免费在线观看 | 在线小视频你懂得 | 久久久噜噜噜久久久 | 亚洲亚洲精品在线观看 | 中文字幕一区二区三区四区 | 波多野结衣一区二区三区中文字幕 | 成人资源在线观看 | 日本护士三级少妇三级999 | 国产又粗又长又硬免费视频 | 久久成人欧美 | 日韩乱码中文字幕 | 国产日韩av在线 | av免费在线看网站 | 欧美成人中文字幕 | 欧美日韩视频网站 | 国产成a人亚洲精v品在线观看 | 91麻豆精品国产91久久久久 | 亚洲精品综合久久 | a在线v| 欧美日韩精品在线视频 | 在线观看av网站 | 久久超级碰 | 日韩精品视频免费专区在线播放 | 去干成人网 | 国产理论影院 | 国产99久久久国产精品成人免费 | 国产精品女主播一区二区三区 | 国产黄a三级三级 | 97国产精品视频 | 99r在线播放 | 在线观看国产www | 四虎影视8848dvd | 欧美乱码精品一区 | 免费在线观看av网站 | 91色在线观看 | 国产精品成人自产拍在线观看 | 国产青春久久久国产毛片 | 日韩美精品视频 | 精品久久久久久国产偷窥 | 欧美国产日韩在线观看 | 激情五月在线视频 | 六月激情 | 麻豆系列在线观看 | 丁香综合五月 | 国产又粗又硬又长又爽的视频 | 国产成人精品久久二区二区 | 高清视频一区 | 在线免费观看一区二区三区 | 日本精品一区二区三区在线观看 | 国产欧美高清 | 久久综合九色综合97_ 久久久 | 久久国产精品久久精品国产演员表 | 国产成人精品亚洲a | 亚洲国产wwwccc36天堂 | 国产免费一区二区三区网站免费 | 在线免费av播放 | 91av社区 | 久久系列| 国产精品一区二区麻豆 | av福利网址导航 | 成人午夜电影网 | 18性欧美xxxⅹ性满足 | 91精品国产自产在线观看 | 色婷婷成人 | 亚洲一区av | 天天干天天射天天插 | 国色天香永久免费 | 国产高清无线码2021 | 97免费 | 亚洲精品在线观看网站 | 91片黄在线观看动漫 | 91激情小视频 | 91色亚洲| 91精品1区| 欧美a影视 | 亚洲精品一区中文字幕乱码 | 欧美久久久久久久久久久久久 | 欧美国产日韩久久 | 美女久久视频 | 视频高清 | 日韩欧美xx | 免费国产在线精品 | 精品成人a区在线观看 | 日韩中文字幕一区 | 有码视频在线观看 | 久久五月天色综合 | 免费成人av网站 | 国模精品一区二区三区 | 日韩高清免费无专码区 | 美女免费视频一区 | 狠狠撸电影 | 五月婷婷一级片 | 99在线观看 | 久久视频 | 四虎成人精品永久免费av九九 | 免费观看国产精品 | 久久99国产精品久久 | 日产乱码一二三区别免费 | 特及黄色片 | 久久久久成人精品免费播放动漫 | 亚洲无吗视频在线 | 国产精品福利无圣光在线一区 | 97色涩| www.888av| 中文字幕日韩在线播放 | 天天操天天艹 | 久久韩国免费视频 | 日韩电影久久久 | 最近中文字幕完整高清 | 国产在线视频导航 | 国产亚洲一区二区在线观看 | 亚洲精品视频免费在线 | 狠狠伊人 | 97网在线观看 | 亚洲乱码在线 | 色婷婷亚洲综合 | 亚洲精品久久久蜜桃直播 | bayu135国产精品视频 | 福利片视频区 | 韩国av不卡 | 一区二区 久久 | 97超碰人 | 久久精品欧美一区 | 欧美淫aaa免费观看 日韩激情免费视频 | 久久精品视频一 | 2022中文字幕在线观看 | 在线综合 亚洲 欧美在线视频 | 欧美综合色在线图区 | 国产欧美中文字幕 | 亚洲成人黄色在线观看 | 欧美性受极品xxxx喷水 | 婷婷丁香色 | 一级黄色大片 | 国产在线观看你懂得 | 97人人视频 | 成人激情开心网 | 久久午夜视频 | av网站地址| 69精品久久 | 亚洲国产日韩一区 | 人人干人人搞 | 一区二区三区www | 黄色资源在线 | www.色婷婷| 97国产精品久久 | 999久久国精品免费观看网站 | 日韩视频欧美视频 | 国产精品美女999 | 久久久久久高清 | 日日夜夜操操操操 | 99热精品久久 | 国产理论免费 | 亚洲精品在线一区二区三区 | 婷婷激情久久 | 日韩久久精品一区二区三区下载 | 免费在线黄色av | 国产高清在线一区 | 天天操天天能 | 91精品久久久久久久久久久久久 | 欧美不卡视频在线 | 日日爽日日操 | 久草久热| 麻豆久久精品 | 欧美国产大片 | 久久久久人人 | 国产在线视频导航 | 五月婷婷亚洲 | 精品国产自在精品国产精野外直播 | 日产乱码一二三区别在线 | 97成人精品区在线播放 | 久久av电影| 免费av大全| 日韩视频中文字幕在线观看 | 久久99精品久久久久久清纯直播 | 中文字幕在线观看免费高清完整版 | 日本中文字幕在线播放 | 人人爽人人爽人人爽 | 久久综合五月天婷婷伊人 | 亚洲 成人 欧美 | 精品久久久亚洲 | 国产黄av | 九九久久国产精品 | 在线亚洲精品 | 久久不卡日韩美女 | 久草视频在线免费看 | 亚洲男人天堂2018 | 国产区免费在线 | 精品国产一区二区三区日日嗨 | 国产一卡二卡四卡国 | 国产精品久久久一区二区三区网站 | 欧美三级高清 | 伊人影院得得 | 欧美激情视频免费看 | 亚洲专区欧美专区 | 91视频免费| 国产日韩中文在线 | 黄色av免费在线 | 久草视频在线观 | 国产看片免费 | 国产精品久久久久久久久久ktv | av一区在线 | 亚洲国产精品500在线观看 | 色av网站| 欧美爽爽爽 | 久久久99精品免费观看乱色 | 18久久久久久 | 国产成人61精品免费看片 | 久久久在线| 在线免费观看黄 | 天天射天天做 | 波多野结衣在线观看一区二区三区 | 又黄又爽又刺激 | 伊人色综合久久天天网 | 99久久精品日本一区二区免费 | 国产精品对白一区二区三区 | 九九导航 | 免费看成人| 国产在线精品国自产拍影院 | 国产精品久久久久影院日本 | 免费观看国产视频 | 免费看毛片网站 | 日本丶国产丶欧美色综合 | 超碰人人乐 | 天天天干天天天操 | 久久成人高清 | 美女黄频网站 | 在线亚洲成人 | 亚洲精品视频免费看 | 久久久久久久久久亚洲精品 | 久久精品视频国产 | 久久精品99国产精品 | 欧美日韩一级久久久久久免费看 | 中文字幕在线观看完整版 | 激情综合五月网 | 久久av不卡| 国产中文欧美日韩在线 | 欧美色图88| 欧美日韩精品在线播放 | 亚洲经典中文字幕 | 久久99中文字幕 | av一二三区| 中文字幕大全 | www五月天com | 日韩在线视频观看免费 | 黄色官网在线观看 | 人人艹视频 | 国产九九九视频 | 久久8精品| 国精产品999国精产 久久久久 | 日本中文字幕在线播放 | 日韩h在线观看 | 日韩一二三区不卡 | 成年人视频在线免费观看 | 一区二区三区免费在线观看视频 | 日韩视频一二三区 | 日日夜夜操操操操 | 成 人 黄 色 片 在线播放 | 精品影院一区二区久久久 | 欧美日韩大片在线观看 | 香蕉久久久久 | 日韩中文字幕一区 | 91av在线免费播放 | 97成人在线视频 | 欧美三人交 | 4438全国亚洲精品在线观看视频 | 在线免费观看国产黄色 | 在线一区电影 | 毛片网在线| 免费性网站 | 免费看黄在线看 | 日韩精品中文字幕久久臀 | 91精品老司机久久一区啪 | 国产亚洲精品久久久久5区 成人h电影在线观看 | 99国产精品一区二区 | 国产成人精品一区二区三区在线观看 | 久久精品中文字幕一区二区三区 | 狠狠色综合网站久久久久久久 | 日本不卡123区| 四虎欧美| 在线免费色视频 | 奇米网网址 | 免费看搞黄视频网站 | 九九天堂| 国产一区二区三区在线免费观看 | 日韩婷婷| 五月婷婷av在线 | 久色婷婷 | 婷婷久久国产 | 国产精品 国内视频 | 日韩精品免费在线观看 | 日本性动态图 | 国产精品久久久久国产精品日日 | 日韩激情中文字幕 | 96精品在线| 手机色在线 | www.黄色网.com | 一级片在线 | 中文字幕文字幕一区二区 | 国产精品小视频网站 | 国产资源站| 99视频国产精品 | 色播五月激情五月 | 色婷婷www | 国产精品网在线观看 | 91精品国自产在线观看 | 亚洲国产天堂av | 午夜久久影视 | 久久久久久久18 | 人人干狠狠干 | 国产精品2020 | 日本久久精品视频 | 亚洲久久视频 | 天天射天天操天天色 | 曰本免费av | 中文字幕免费高清在线 | 91av免费在线观看 | 国产成人精品免费在线观看 | 日本精品视频在线观看 | 亚洲色图激情文学 | 成人黄色小说在线观看 | 激情电影在线观看 | 日本韩国中文字幕 | 婷婷久久网 | 天天碰天天操视频 | 91插插影库 | 国产三级香港三韩国三级 | 日韩免费观看一区二区三区 | 亚洲人成网站精品片在线观看 | 日韩精品免费 | 亚洲欧美乱综合图片区小说区 | 国产精在线 | 亚洲高清视频在线 | 午夜精品一区二区三区免费视频 | 精品国产欧美一区二区 | 17videosex性欧美 | 成年人在线观看 | 精品在线观看免费 | 欧美 激情在线 | 国模视频一区二区三区 | 一级黄色免费 | 探花视频网站 | 亚av在线 | 亚洲国产色一区 | 精品久久久成人 | 日韩免费电影网 | 免费观看一级特黄欧美大片 | 亚洲国产wwwccc36天堂 | 夜夜躁狠狠躁日日躁 | 国产精品爽爽久久久久久蜜臀 | 天天狠狠干 | 国产一区二区在线免费视频 | 激情视频网页 | 国产精品久久久久久吹潮天美传媒 | 成人理论电影 | 欧美一级日韩三级 | 91免费观看视频网站 | 久久精品视频在线观看免费 | 精品在线一区二区三区 | 国产精品普通话 | 黄色一二级片 | 日本不卡一区二区三区在线观看 | 波多野结衣一区二区 | 国产午夜小视频 | 久久国产精品影片 | 五月天激情综合网 | 国产一区国产精品 | 欧美另类高潮 | 国产精品系列在线观看 | 免费看污片| 精品成人a区在线观看 | 国内小视频在线观看 | 成年人免费电影 | 日韩久久久久久久久久久久 | 黄av免费 | 欧美极品少妇xbxb性爽爽视频 | 91久久精品一区 | 97碰在线视频 | 成人在线观看你懂的 | 日韩欧美v| www.天天射 | 91日韩国产 | 2019天天干夜夜操 | 色偷偷88888欧美精品久久 | 韩日电影在线 | 日韩欧美亚州 | 日本韩国中文字幕 | 欧美在线视频免费 | 欧美大片在线观看一区 | 日日干天天操 | 国产精品21区 | 国产专区视频在线观看 | 黄色一级在线免费观看 | 久久精品视 | 欧美一级黄色视屏 | 色多视频在线观看 | av天天澡天天爽天天av | 99精品久久久久久久久久综合 | 黄色免费在线视频 | 亚洲综合小说电影qvod | 国产99爱 | 天堂在线免费视频 | 国产伦精品一区二区三区免费 | 综合网久久 | 丁香在线观看完整电影视频 | 亚洲日韩精品欧美一区二区 | 国产一区久久久 | 九九九九九九精品任你躁 | 91在线免费视频观看 | 色综合天天综合在线视频 | 97超碰伊人| 日韩毛片一区 | 五月婷av | 欧美久草在线 | 91精品国产麻豆国产自产影视 | 五月婷婷中文 | 在线电影av | 九九视频网站 | 蜜臀av免费一区二区三区 | 夜夜躁狠狠躁日日躁 | 香蕉视频在线视频 | 99久久夜色精品国产亚洲96 | 在线视频 影院 | 国产精品igao视频网网址 | 国产精品毛片一区视频播 | 国产精品女主播一区二区三区 | 国产亚洲精品久久久久久网站 | 国产精品久久久久免费a∨ 欧美一级性生活片 | 国产一区二区视频在线播放 | 麻豆视频免费入口 | 国产成人免费观看久久久 | 免费h在线观看 | 久久精品79国产精品 | 国产黄色片免费观看 | 中文字幕在线精品 | 99亚洲国产 | 久草视频中文在线 | 国产精品国产亚洲精品看不卡15 | 国产视频精品视频 |