精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

從 23.9K 的前端開源項目我學到了啥?

開發 開發工具
在 7年技術寫作,分享6點心得體會 這篇文章中,阿寶哥介紹了自己經常使用的一款不錯的在線繪圖工具 — Excalidraw。

[[430695]]

在 7年技術寫作,分享6點心得體會 這篇文章中,阿寶哥介紹了自己經常使用的一款不錯的在線繪圖工具 — Excalidraw。使用它你可以輕松地繪制各種漂亮的手繪示意圖,目前在 Github 上 Excalidraw 的 Star 數已達 23.9 K,因此它也是一個很不錯的開源項目。

在平時使用 Excalidraw 的時候,阿寶哥發現了該在線工具提供了一些不錯的功能。比如保存 *.excalidraw 文件到指定目錄、拖拽打開 *.excalidraw 文件并保存至當前文件、復制圖片到剪貼板、分享只讀鏈接和實時協作等功能。

提示:上圖演示了拖拽打開 *.excalidraw 文件并保存至當前文件的功能

上述的這些功能,很多都是跟文件操作相關。關于文件處理,阿寶哥之前寫了 文件上傳,搞懂這8種場景就夠了 和 文件下載,搞懂這9種場景就夠了 這兩篇文章。而第三篇文章,阿寶哥就帶大家來分析一下 Excalidraw 背后與文件操作相關的技術。

了解并掌握了這些相關技術之后,在今后的工作中也許就會有用武之地,特別是對于一些在線 Web 編輯器的場景,利用這些技術將會大大提高產品的用戶體驗。比如在支持相關 Web 技術的平臺上,你們開發的在線編輯器就能完美支持 打開->編輯->保存 這個常見的文件處理流程。

話不多說,我們馬上步入正題,這里我們先來分析 保存 .excalidraw 文件到指定目錄 的功能。

一、保存文件到指定目錄

圖片

提示:本文所有演示示例使用的 Chrome 版本為:版本 92.0.4515.159(正式版本) (x86_64)

以上 Gif 動圖演示了保存文件到指定目錄的過程,因為 Excalidraw 這個在線工具是開源的,所以通過分析它的源碼,我們找到了實現 保存文件到指定目錄 功能的實現函數:

  1. // https://github.com/excalidraw/excalidraw/blob/master/src/data/json.ts#L31 
  2. import { fileOpen, fileSave } from "browser-fs-access"
  3.  
  4. export const saveAsJSON = async ( 
  5.   elements: readonly ExcalidrawElement[], 
  6.   appState: AppState, 
  7. ) => { 
  8.   const serialized = serializeAsJSON(elements, appState); 
  9.   const blob = new Blob([serialized], { 
  10.     type: MIME_TYPES.excalidraw, 
  11.   }); 
  12.   
  13.   const fileHandle = await fileSave( 
  14.     blob, 
  15.     { 
  16.       fileName: `${appState.name}.excalidraw`, 
  17.       description: "Excalidraw file"
  18.       extensions: [".excalidraw"], 
  19.     }, 
  20.     isImageFileHandle(appState.fileHandle) ? null : appState.fileHandle, 
  21.   ); 
  22.   return { fileHandle }; 
  23. }; 

由以上代碼可知,在 saveAsJSON 函數內部是通過調用 fileSave 函數來保存文件。fileSave 函數是從 browser-fs-access 這個第三庫導入的。該庫封裝了 File_System_Access_API,該 API 為開發者提供了 讀、寫文件和文件管理 的能力。而 保存文件到指定目錄 的功能,就是通過 showSaveFilePicker 方法來實現的。在 showSaveFilePicker 方法出現之前,在客戶端實現保存文件的功能,比較常見的方案是使用 a 標簽 或 FileSaver.js 這個庫。

  1. const saveFile = async (blob, filename) => { 
  2.   const a = document.createElement('a'); 
  3.   a.download = filename; 
  4.   a.href = URL.createObjectURL(blob); 
  5.   a.addEventListener('click', (e) => { 
  6.     setTimeout(() => URL.revokeObjectURL(a.href), 30 * 1000); 
  7.   }); 
  8.   a.click(); 
  9. }; 

提示:如果你想了解其他的文件下載方式,可以閱讀 文件下載,搞懂這9種場景就夠了 這篇文章。

對于前面介紹的客戶端文件保存的方案來說,它最大的問題就是沒有辦法實現 打開->編輯->保存 這種常見的文件操作流程。因為我們沒有辦法覆蓋原始的文件,只能創建一個新的文件。而使用新的 File_System_Access_API 就可以解決上述的問題,比如我們可以使用 window.showOpenFilePicker 方法來打開文件,在文件編輯完成之后,再使用 window.showSaveFilePicker 來保存文件。

圖片

(文本編輯器地址:https://googlechromelabs.github.io/text-editor/)

下面我們來介紹一下 showSaveFilePicker API,它是 Window 接口中定義的方法,調用該方法后會顯示允許用戶選擇保存路徑的文件選擇器。該方法的簽名如下所示:

  1. let FileSystemFileHandle = Window.showSaveFilePicker(options); 

showSaveFilePicker 方法支持一個對象類型的可選參數,可包含以下屬性:

excludeAcceptAllOption:布爾類型,默認值為 false。默認情況下,選擇器應包含一個不應用任何文件類型過濾器的選項(由下面的 types 選項啟用)。將此選項設置為 true 意味著 types 選項不可用。

types:數組類型,表示允許保存的文件類型列表。數組中的每一項是包含以下屬性的配置對象:

  • description(可選):用于描述允許保存文件類型類別。
  • accept:是一個對象,該對象的 key 是 MIME 類型,值是文件擴展名列表。

調用 showSaveFilePicker 方法之后,會返回一個 FileSystemFileHandle 對象。有了該對象,你就可以調用該對象上的方法來操作文件。比如調用該對象上的 createWritable 方法之后,就會返回 FileSystemWritableFileStream 對象,就可以把數據寫入到文件中。具體的使用方式如下所示:

  1. async function saveFile(blob, filename) { 
  2.   try { 
  3.     const handle = await window.showSaveFilePicker({ 
  4.       suggestedName: filename, 
  5.       types: [ 
  6.         { 
  7.           description: "PNG file"
  8.           accept: { 
  9.             "image/png": [".png"], 
  10.           }, 
  11.         }, 
  12.       ], 
  13.      }); 
  14.     const writable = await handle.createWritable(); 
  15.     await writable.write(blob); 
  16.     await writable.close(); 
  17.     return handle; 
  18.   } catch (err) { 
  19.      console.error(err.name, err.message); 
  20.   } 
  21.  
  22. saveFile(imgBlob, "face.png"); 

當你使用以上的 saveFile 函數,來保存圖片時,就會顯示以下保存文件選擇器:

看到這里是不是覺得 showSaveFilePicker API 功能挺強大的,不過可惜的是該 API 目前的兼容性還不是很好,具體如下圖所示:

(圖片來源:https://caniuse.com/?search=showSaveFilePicker)

showSaveFilePicker 是 File System Access API 中定義的方法,除了 showSaveFilePicker 之外,還有 showOpenFilePicker 和 showDirectoryPicker 等方法。接下來,阿寶哥來簡單介紹一下另外這兩個比較有用的 API。

showOpenFilePicker API,它是 Window 接口中定義的方法,調用該方法后會顯示一個允許用戶選擇一個或多個文件的文件選擇器。該方法的簽名如下所示:

  1. let FileSystemHandles = Window.showOpenFilePicker(); 

showOpenFilePicker 方法支持一個對象類型的可選參數,可包含以下屬性:

multiple:布爾類型,默認值為 false。若設置為 true,則允許選擇多個文件。

excludeAcceptAllOption:布爾類型,默認值為 false。默認情況下,選擇器應包含一個不應用任何文件類型過濾器的選項(由下面的 types 選項啟用)。將此選項設置為 true 意味著 types 選項不可用。

  • types:數組類型,表示允許保存的文件類型列表。數組中的每一項是包含以下屬性的配置對象:
  • description(可選):用于描述允許保存文件類型類別。

accept:是一個對象,該對象的 key 是 MIME 類型,值是文件擴展名列表。

調用 showOpenFilePicker 方法之后,會返回 FileSystemHandles 即 FileSystemFileHandle 對象數組。有了 FileSystemFileHandle 對象,你就可以調用該對象上的方法來操作文件。下面我們來舉一個簡單的使用示例:

  1. <div> 
  2.    <textarea id="container" rows="5" cols="30"></textarea> 
  3. </div> 
  4. <button onclick="openFile()">打開文件</button> 
  5. <script> 
  6.    const container = document.querySelector("#container"); 
  7.    
  8.    async function openFile() { 
  9.      let [fileHandle] = await window.showOpenFilePicker(); 
  10.      const file = await fileHandle.getFile(); 
  11.      const contents = await file.text(); 
  12.      container.value = contents; 
  13.    } 
  14. </script> 

在以上示例中,當用戶點擊 打開文件 按鈕時,就會顯示一個文件選擇器。在選擇文本文件之后,就會把文件中的內容,顯示在 textarea#container 文本框中。對于非文本文件,你可以通過調用 arrayBuffer 方法來讀取文件中的二進制內容。

(圖片來源:https://caniuse.com/?search=showOpenFilePicker)

由上圖可知,目前 showOpenFilePicker API 的兼容性還比較差。但如果你想在支持 File System Access API 的平臺中,優先使用這些 API 的話,可以考慮使用 GoogleChromeLabs 開源的 browser-fs-access 這個庫,該庫可以讓你在支持 File System Access API 的平臺上更方便地使用 File System Access API,而對于不支持的平臺會自動降級使用 <input type="file"> 和 <a download> 的方式。

除了選擇文件之外,我們也可以選擇目錄。針對這種場景,我們就可以使用 showDirectoryPicker API。它是 Window 接口中定義的方法,調用該方法后會顯示一個允許用戶選擇目錄的選擇器。該方法的簽名如下所示:

  1. var FileSystemDirectoryHandle = Window.showDirectoryPicker(); 

與前面介紹的 showOpenFilePicker 方法不同的是,調用 showDirectoryPicker 方法后是,返回的是 FileSystemDirectoryHandle 對象。利用該對象,我們就可以執行一些目錄的相關操作操作。比如讀取目錄的信息、讀取目錄下的指定文件、刪除目錄下的指定文件或在目錄下新建文件等。同樣,我們也來舉一些簡單的示例。

讀取目錄的信息

  1. async function readDirectory() { 
  2.   const dirHandle = await window.showDirectoryPicker(); 
  3.   for await (const entry of dirHandle.values()) { 
  4.     console.log(entry.kind, entry.name); 
  5.   } 

讀取目錄下的指定文件

  1. const container = document.querySelector("#container"); 
  2.  
  3. async function readFile() { 
  4.   const dirHandle = await window.showDirectoryPicker(); 
  5.   const fileHandle = await dirHandle.getFileHandle("hello.txt"); 
  6.   const file = await fileHandle.getFile(); 
  7.   const contents = await file.text(); 
  8.   container.value = contents; 

刪除目錄下的指定文件

  1. async function removeFile() { 
  2.   const dirHandle = await window.showDirectoryPicker(); 
  3.   const result = await dirHandle.removeEntry("hello.copy.txt"); 
  4.   container.value = `刪除hello.copy.txt文件${ 
  5.     typeof result == "undefined" ? "成功" : "失敗" 
  6.   }`; 

需要注意的是,removeEntry 方法除了支持刪除指定文件之外,還可以支持刪除指定目錄。

創建指定文件

  1. async function createFile() { 
  2.   const dirHandle = await window.showDirectoryPicker(); 
  3.   const fileHandle = await dirHandle.getFileHandle("hello.new.txt", { 
  4.     createtrue
  5.   }); 
  6.   container.value = "hello.new.txt文件創建成功!"
  7.   const writable = await fileHandle.createWritable(); 
  8.   await writable.write(new Blob(["大家好,我是阿寶哥!"])); 
  9.   await writable.close(); 

在以上代碼中,我們通過調用 getFileHandle 方法來獲取指定文件,對應的 FileSystemFileHandle 對象。create: true 表示如果在當前目錄下未找到指定文件,則創建新的文件。了解完以上的示例,是不是覺得瀏覽器的文件處理能力越來越強大了。同樣,我們也來看一下 showDirectoryPicker API 的兼容性:

(圖片來源:https://caniuse.com/?search=showDirectoryPicker)

二、拖拽打開 *.excalidraw 文件并保存至當前文件

以上 Gif 動圖演示了拖拽打開 *.excalidraw 文件并保存至當前文件的過程,可以發現在編輯完文件之后,我們只需確認是否保存文件,而無需選擇文件的保存路徑,在大大提高了用戶的使用體驗。

  1. class App extends React.Component<AppProps, AppState> { 
  2.    // 省略大部分代碼 
  3.     const file = event.dataTransfer?.files[0]; 
  4.     if ( 
  5.       file?.type === MIME_TYPES.excalidrawlib || 
  6.       file?.name?.endsWith(".excalidrawlib"
  7.     ) { 
  8.       // 處理導入的控件庫的邏輯 
  9.     } else { 
  10.       this.setState({ isLoading: true }); 
  11.       if (fsSupported) { // 判斷是否支持File System Access API 
  12.         try { 
  13.           const item = event.dataTransfer.items[0]; 
  14.           // 關鍵點:獲取FileSystemHandle對象 
  15.           (file as any).handle = await (item as any).getAsFileSystemHandle(); 
  16.         } catch (error) { 
  17.           console.warn(error.name, error.message); 
  18.         } 
  19.       } 
  20.       // 加載.excalidraw文件到Canvas 
  21.       await this.loadFileToCanvas(file); 
  22.     } 
  23.   }; 

以上代碼的關鍵點是,調用 DataTransferItem.getAsFileSystemHandle() 方法來獲取 FileSystemFileHandle 對象。擁有該對象之后,我們就可以對文件進行讀、寫操作。具體的使用方式如下所示:

讀文件示例

  1. async function getTheFile() { 
  2.   // open file picker 
  3.   [fileHandle] = await window.showOpenFilePicker(pickerOpts); 
  4.  
  5.   // get file contents 
  6.   const fileData = await fileHandle.getFile(); 

寫文件示例

  1. async function writeFile(fileHandle, contents) { 
  2.   // Create a FileSystemWritableFileStream to write to
  3.   const writable = await fileHandle.createWritable(); 
  4.  
  5.   // Write the contents of the file to the stream. 
  6.   await writable.write(contents); 
  7.  
  8.   // Close the file and write the contents to disk. 
  9.   await writable.close(); 

三、復制圖片到剪貼板

  1. // https://github.com/excalidraw/excalidraw/blob/master/src/clipboard.ts 
  2. export const copyBlobToClipboardAsPng = async (blob: Blob) => { 
  3.   await navigator.clipboard.write([ 
  4.     new window.ClipboardItem({ "image/png": blob }), 
  5.   ]); 
  6. }; 

在以上代碼中,copyBlobToClipboardAsPng 函數支持一個 blob 參數,在該函數內部會調用 navigator.clipboard.write 方法,來實現把圖片復制到剪貼板。而對于普通文本來說,你可以通過 navigator.clipboard.writeText 方法,把它們寫入到系統的剪貼板。

其實 navigator.clipboard.write 和 navigator.clipboard.writeText 方法是 Clipboard 接口定義的方法,該接口實現了 Clipboard API,如果用戶授予了相應的權限,就能提供系統剪貼板的讀寫訪問。在 Web 應用程序中,Clipboard API 可用于實現剪切、復制和粘貼功能。該 API 用于取代通過 document.execCommand API 來實現剪貼板的操作。

在實際工作中,我們不需要手動創建 Clipboard 對象,而是通過 navigator.clipboard 來獲取 Clipboard 對象:

在獲取 Clipboard 對象之后,我們就可以利用該對象提供的 API 來訪問剪貼板。比如,通過 navigator.clipboard.readText 方法來讀取剪貼板的內容:

  1. navigator.clipboard.readText().then
  2.   clipText => document.querySelector(".editor").innerText = clipText 
  3. ); 

以上代碼將 HTML 中含有 .editor 類的第一個元素的內容替換為剪貼板的內容。如果剪貼板為空,或者不包含任何文本,則元素的內容將被清空。這是因為在剪貼板為空或者不包含文本時,readText 方法會返回一個空字符串。

異步剪貼板 API 是一個相對較新的 API,瀏覽器仍在逐漸實現它。由于潛在的安全問題和技術復雜性,大多數瀏覽器正在逐步集成這個 API。目前 Navigator API: clipboard 的兼容性如下圖所示:

(圖片來源:https://caniuse.com/mdn-api_navigator_clipboard)

對于瀏覽器擴展來說,你可以請求 clipboardRead 和 clipboardWrite 權限以使用 clipboard.readText() 和 clipboard.writeText()。如果你對 Clipboard 其他 API 感興趣的話,可以閱讀 想要復制圖像?Clipboard API 了解一下 這篇文章。

其實除了上面介紹的技術, Excalidraw 還使用了其他 Web API 來實現特定的功能。比如利用 window.crypto API 來實現導出只讀鏈接時,對畫布數據進行加密保護。利用 WebSocket API 來實現協同編輯和利用 Share API 實現文件共享的功能,感興趣的小伙伴可以閱讀一下 Excalidraw 的相關源碼。

四、總結

本文阿寶哥分析了 Excalidraw 這款在線繪圖工具,所提供的一些不錯功能背后使用的技術。希望閱讀完本文后,你對 File_System_Access_API 中定義的 window.showOpenFilePicker、window.showSaveFilePicker、window.showDirectoryPicker 和 DataTransferItem.getAsFileSystemHandle 這些方法都有一定的了解。

由于目前 File_System_Access_API 的兼容性還不是很好,如果你想在項目中使用它的話。建議你使用 GoogleChromeLabs 開源的 browser-fs-access 這個庫,該庫不僅為我們提供了更簡潔的 API,而且還提供了自動降級的方案。在今后的項目中,有機會的話,小伙伴們可以嘗試一下。

五、參考資源

  • web.dev — excalidraw-and-fugu
  • web.dev — browser-fs-access
  • web.dev — file-system-access
  • MDN — File_System_Access_API
  • MDN — FileSystemFileHandle

 

責任編輯:姜華 來源: 全棧修仙之路
相關推薦

2020-09-25 06:32:25

前端

2021-03-09 09:55:02

Vuejs前端代碼

2020-02-22 15:01:51

后端前端開發

2020-07-07 08:52:16

機器學習機器學習工具人工智能

2022-03-27 09:06:04

React類型定義前端

2020-12-31 10:47:03

開發Vuejs技術

2016-01-18 10:06:05

編程

2021-04-15 08:15:27

Vue.js源碼方法

2024-04-12 08:54:13

從庫數據庫應用

2020-02-22 14:49:30

畢業入職半年感受

2020-11-04 07:13:57

數據工程代碼編程

2021-07-28 07:01:09

薅羊毛架構Vue+SSR

2021-01-02 09:48:13

函數運算js

2020-10-30 12:40:04

Reac性能優化

2019-08-27 10:49:30

跳槽那些事兒技術Linux

2019-08-16 17:14:28

跳槽那些事兒技術Linux

2013-06-27 10:31:39

2015-06-29 13:47:19

創業創業智慧

2011-10-18 11:43:25

UNIXC語言丹尼斯·里奇

2023-06-06 08:14:18

核心Docker應用程序
點贊
收藏

51CTO技術棧公眾號

99在线精品观看| 国产精品xvideos88| 欧美日本在线观看| 伊人久久在线观看| 无码国产精品一区二区免费16| 性一交一乱一区二区洋洋av| 久久久国产精品亚洲一区| 污污免费在线观看| 国产美女久久| 一区二区三区欧美| 色播五月综合| 日本黄色大片视频| 精彩视频一区二区三区| 青青草99啪国产免费| 丝袜美腿小色网| 视频一区欧美| 精品国产乱码久久| 亚洲综合欧美在线| 在线看片国产福利你懂的| 中文字幕在线不卡一区| 欧美乱偷一区二区三区在线| 成人黄色在线观看视频| 轻轻草成人在线| 91精品国产91久久久久久吃药| 小向美奈子av| 欧美综合在线视频观看| 亚洲国产黄色片| 日本黄色www| 成人久久网站| 91国模大尺度私拍在线视频| 欧美男女爱爱视频| 羞羞电影在线观看www| 国产免费成人在线视频| 国产精品乱码| 亚洲精品中文字幕成人片| 精品一区二区三区蜜桃| 国产精品视频一| 中文字幕精品视频在线观看| 99在线精品免费视频九九视| 欧美激情国产高清| 国产这里有精品| 性欧美69xoxoxoxo| www.日韩.com| 国产人与禽zoz0性伦| 激情五月综合| 亚洲欧美激情精品一区二区| 水蜜桃av无码| 婷婷亚洲成人| 精品视频一区在线视频| 无码人妻精品一区二区三区温州| 久久综合另类图片小说| 精品不卡在线视频| 亚洲无人区码一码二码三码| 中文久久电影小说| 欧美xxxxxxxx| 国产婷婷在线观看| 老司机精品视频在线播放| 日韩av网站大全| 人妻无码一区二区三区| 国产成人一区| 丝袜情趣国产精品| 99热6这里只有精品| 欧美激情777| 久久国产精品久久久久| 黄色在线观看免费| 国产欧美一区二区色老头| 69av成年福利视频| 超碰在线观看91| 美国毛片一区二区| 91久热免费在线视频| www.污视频| 97久久人人超碰| 欧美一区二区三区四区夜夜大片| 川上优的av在线一区二区| 国产精品久久久久久久久久久免费看 | 欧美 日韩 综合| 久久这里只有精品首页| 亚洲精品人成| 婷婷在线播放| 黑人欧美xxxx| 日本特黄a级片| 试看120秒一区二区三区| 亚洲国产小视频| www色com| 欧美黄在线观看| 欧美在线观看视频| 97人人爽人人爽人人爽 | 亚洲欧洲久久久| 成人激情免费视频| 久久99久国产精品黄毛片入口| 日韩一区二区视频在线| 麻豆精品在线看| 国产区二精品视| 免费网站黄在线观看| 亚洲网友自拍偷拍| 亚洲最大综合网| youjizz欧美| 中文字幕亚洲综合久久| 国产精品99精品| 经典三级在线一区| 久久亚洲精品欧美| 制服丝袜在线播放| 91国产丝袜在线播放| 人妻互换一二三区激情视频| 成人影院在线| 97国产精品免费视频| 91色在线播放| 久久欧美一区二区| www.亚洲视频.com| 国产一区二区视频在线看| 日韩精品视频在线观看免费| 日韩成人毛片视频| 免费人成网站在线观看欧美高清| 国产精品高清一区二区三区| 免费在线毛片网站| 欧美在线不卡一区| 精品无码在线视频| 亚洲成人中文| 亚洲自拍偷拍在线| 五月婷婷在线观看| 色婷婷综合久久| 中文字幕乱码在线| 激情久久五月| 国产精品久久久久久久久久直播 | 欧美日韩1区2区| 舐め犯し波多野结衣在线观看| 国内视频精品| 成人羞羞国产免费| 日本三级在线视频| 欧美性xxxxxx少妇| 亚洲av综合一区二区| 亚洲毛片视频| 国产欧美丝袜| mm视频在线视频| 精品国产露脸精彩对白 | 麻豆传媒在线观看| 欧美吞精做爰啪啪高潮| 鲁丝一区二区三区| 久久久久久网| 日本亚洲欧洲精品| 日韩av免费| 国产亚洲一区精品| 国产真人无遮挡作爱免费视频| 久久综合丝袜日本网| 国产特级黄色大片| 欧美日韩麻豆| 欧美重口另类videos人妖| 日本福利在线观看| 欧美性猛xxx| 国产精品毛片一区二区| 视频一区二区中文字幕| 日韩欧美精品在线不卡| 99re久久| 久久国产精品偷| 亚洲黄色片视频| 天天综合天天做天天综合| 超碰caoprom| 国产精品一二| 日韩中文字幕av在线| 啪啪av大全导航福利综合导航| 日韩中文字幕欧美| 精品人妻一区二区三区麻豆91| 亚洲精品v日韩精品| 年下总裁被打光屁股sp| 亚洲在线成人| 亚洲精品一区二区三区蜜桃久| 亚洲伊人精品酒店| 欧美风情在线观看| 亚洲AV成人无码一二三区在线| 欧美午夜久久久| 国产福利在线导航| 国产九九视频一区二区三区| 日本福利视频一区| 国产精品三级| 91久久久国产精品| 黄在线观看免费网站ktv| 亚洲人成网站色ww在线| 91福利在线观看视频| 亚洲一区二区在线免费观看视频 | 成人乱码一区二区三区| 黑人巨大精品欧美一区二区一视频 | 中文字幕乱码久久午夜不卡| 色婷婷综合在线观看| 99亚洲一区二区| 亚洲视频在线观看日本a| 91午夜精品| 国产成人一区二区三区电影| 26uuu亚洲电影在线观看| 日韩精品在线观看网站| 国产视频在线一区| 日韩欧美精品中文字幕| 在线观看亚洲网站| 久久综合九色综合欧美亚洲| 男生操女生视频在线观看| 99riav1国产精品视频| 亚洲电影网站| 精品午夜电影| 成人黄色片在线| 欧美特大特白屁股xxxx| 久久99精品国产99久久6尤物| 麻豆国产在线播放| 精品久久久久久久一区二区蜜臀| 在线免费观看国产精品| 午夜在线电影亚洲一区| 激情无码人妻又粗又大| 26uuu国产一区二区三区| 无套白嫩进入乌克兰美女| 亚洲综合欧美| 人人干视频在线| 亚洲精品a级片| 日韩免费毛片| 亚洲午夜久久| 国产精品视频一区二区三区经| 国产成人精品一区二区三区免费| 久久久人成影片一区二区三区| 午夜在线播放| 亚洲视频在线观看视频| 视频一区 中文字幕| 欧美一级二级三级乱码| 亚洲天堂aaa| 色哟哟一区二区三区| 国产真实乱偷精品视频| 亚洲欧美另类图片小说| 美国一级片在线观看| 国产精品久久影院| www色com| 国产欧美日韩激情| 亚洲AV无码成人精品区明星换面| 99精品久久免费看蜜臀剧情介绍| 亚洲av综合色区无码另类小说| 黄色日韩网站视频| 午夜剧场在线免费观看| 蜜桃一区二区三区在线观看| 黄色国产小视频| 丝瓜av网站精品一区二区| 美女av免费在线观看| 亚洲人成人一区二区三区| 免费的一级黄色片| 欧美日韩亚洲三区| 成年人深夜视频| 亚洲欧美一级二级三级| 少妇久久久久久被弄到高潮| 亚洲一区二区三区无吗| 日本xxx免费| 欧美在线国产| 国产在线观看欧美| 亚洲精品激情| 中文字幕日本最新乱码视频| 久久久一二三| 欧美日韩在线免费播放| 麻豆精品在线播放| 久久久久久久久久一区二区| 国产美女精品在线| 无码人妻aⅴ一区二区三区玉蒲团| 国产精品一级片| 久草视频福利在线| 91美女蜜桃在线| 五月婷婷欧美激情| 亚洲品质自拍视频网站| 国产极品国产极品| 亚洲午夜三级在线| 国产三级av片| 欧美日韩国产色站一区二区三区| 一级片在线观看视频| 日韩欧美电影一区| 网站黄在线观看| 亚洲人成在线观看网站高清| 国产福利在线看| 久久av.com| 九色porny自拍视频在线播放 | 欧美中日韩在线| 国产一区二区高清| 在线观看av网页| 懂色av一区二区在线播放| 国产女人18毛片水真多18| 久久精子c满五个校花| 性少妇xx生活| 亚洲福利国产精品| 婷婷激情五月综合| 欧美一区二区视频在线观看2022| 成人毛片在线免费观看| 亚洲剧情一区二区| 日本高清视频在线播放| 97国产suv精品一区二区62| 精品三区视频| 成人高清在线观看| 成人羞羞视频播放网站| 国产精品国产三级国产专区51| 久久福利一区| 奇米777在线视频| 久久久久久电影| 久久久久久国产精品视频| 色菇凉天天综合网| 亚洲精品字幕在线| 深夜福利亚洲导航| 高清在线视频不卡| 成人观看高清在线观看免费| 色先锋久久影院av| 日本黄网站色大片免费观看| 久久一区亚洲| 中文字幕天堂网| 亚洲视频免费看| www.久久久久久久| 亚洲爱爱爱爱爱| 国产写真视频在线观看| 日本成人激情视频| 超碰成人97| 可以免费看的黄色网址| 日韩电影免费在线看| 亚洲色偷偷色噜噜狠狠99网| 1024国产精品| 91黑人精品一区二区三区| 精品国产电影一区二区| 国产在线激情视频| 国产精品视频一| 综合综合综合综合综合网| www.av91| 国产精品夜夜爽| 婷婷国产成人精品视频| 色综合久久99| 五月天婷婷视频| 久久频这里精品99香蕉| 日本亚州欧洲精品不卡| 中文字幕欧美日韩一区二区三区| 日韩激情视频在线观看| 国产精品1000部啪视频| 精品免费在线观看| 亚洲欧美黄色片| 欧美寡妇偷汉性猛交| 高清不卡一区| 2021狠狠干| 激情综合网av| 在线看的片片片免费| 欧美精品久久久久久久多人混战 | 国产麻豆剧传媒精品国产| 椎名由奈av一区二区三区| 亚洲熟女乱色一区二区三区久久久| 一个人看的www久久| 国产精品迅雷| 欧美亚州在线观看| 日韩国产精品久久久| 天堂在线中文视频| 欧美午夜电影在线播放| 在线观看精品一区二区三区| 国产剧情久久久久久| 久久久久av| 日本一本在线视频| 一区二区不卡在线播放 | www.com欧美| 欧美日韩999| 国产精品主播在线观看| 日韩av高清在线看片| 99re8在线精品视频免费播放| 男人午夜免费视频| 亚洲热线99精品视频| 国产成人福利夜色影视| 国产高清免费在线| 国产成人免费网站| 日韩欧美中文字幕一区二区| 亚洲欧美第一页| 国产精品久久久久77777丨| 无码毛片aaa在线| www.成人在线| 无码人妻丰满熟妇区五十路| 色妞一区二区三区| 日韩精品一区二区三区中文| 人妻少妇精品无码专区二区| 久久亚洲二区三区| 国产一区二区三区中文字幕| 欧美美女操人视频| 天堂99x99es久久精品免费| 国产成人精品无码播放| 亚洲欧洲www| 少妇av在线播放| 国产精品丝袜久久久久久高清 | 国产精品免费久久| 国内精品久久久久久久久久| 97视频在线看| 99久久亚洲精品蜜臀| 久久性爱视频网站| 欧美性猛交xxxx黑人交| av中文字幕在线看| 视频一区视频二区视频三区视频四区国产 | 91禁国产网站| 五月精品视频| 手机在线成人av| 欧美精品亚洲一区二区在线播放| 欧洲性视频在线播放| 欧美少妇一区| 国产精品一区二区在线看| 久久久久99精品成人片我成大片| 精品国产一区二区三区久久狼5月 精品国产一区二区三区久久久狼 精品国产一区二区三区久久久 | 91免费国产精品| 国产日韩精品一区二区三区 | 九九99久久精品在免费线bt| 国产午夜福利在线播放| 1000部国产精品成人观看| 日本亚洲一区| 国产精品久久久久久久免费大片| 久久99国产精品成人|