整合營銷服務商

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

          免費咨詢熱線:

          驚艷的動畫引擎,簡單、輕盈、開源-Animejs

          驚艷的動畫引擎,簡單、輕盈、開源-Animejs

          Anime.js是一個輕量級的JavaScript動畫庫,具有簡單但功能強大的API。它與CSS屬性,SVG,DOM屬性和JavaScript對象一起使用。






          Github

          在Github上已收獲近35k的star數,可見其非常受廣大使用者的熱愛!

          https://github.com/juliangarnier/anime/

          特性

          • 復雜的交錯動畫變得簡單


          • css分層轉換

          在單個HTML元素上同時以不同的時間對多個CSS變換屬性進行動畫處理。


          • 控件和回調

          時間就是一切


          使用完整的內置回調和控件功能同步播放,暫停,控制,倒退和觸發事件。

          • 動畫任何東西

          HTML,JS,CSS,SVG



          安裝使用

           npm install animejs --save

          ES6:

          import anime from 'animejs/lib/anime.es.js';

          CommonJS:

          const anime=require('animejs');
          <script src="anime.min.js"></script>
          anime({
            targets: 'div',
            translateX: 250,
            rotate: '1turn',
            backgroundColor: '#FFF',
            duration: 800
          });

          Demo

          • 文字動畫

          <h1 class="ml1">
            <span class="text-wrapper">
              <span class="line line1"></span>
              <span class="letters">THURSDAY</span>
              <span class="line line2"></span>
            </span>
          </h1>
          .ml1 {
            font-weight: 900;
            font-size: 3.5em;
          }
          
          .ml1 .letter {
            display: inline-block;
            line-height: 1em;
          }
          
          .ml1 .text-wrapper {
            position: relative;
            display: inline-block;
            padding-top: 0.1em;
            padding-right: 0.05em;
            padding-bottom: 0.15em;
          }
          
          .ml1 .line {
            opacity: 0;
            position: absolute;
            left: 0;
            height: 3px;
            width: 100%;
            background-color: #fff;
            transform-origin: 0 0;
          }
          
          .ml1 .line1 { top: 0; }
          .ml1 .line2 { bottom: 0; }
          var textWrapper=document.querySelector('.ml1 .letters');
          textWrapper.innerHTML=textWrapper.textContent.replace(/\S/g, "<span class='letter'>$&</span>");
          
          anime.timeline({loop: true})
            .add({
              targets: '.ml1 .letter',
              scale: [0.3,1],
              opacity: [0,1],
              translateZ: 0,
              easing: "easeOutExpo",
              duration: 600,
              delay: (el, i)=> 70 * (i+1)
            }).add({
              targets: '.ml1 .line',
              scaleX: [0,1],
              opacity: [0.5,1],
              easing: "easeOutExpo",
              duration: 700,
              offset: '-=875',
              delay: (el, i, l)=> 80 * (l - i)
            }).add({
              targets: '.ml1',
              opacity: 0,
              duration: 1000,
              easing: "easeOutExpo",
              delay: 1000
            });
          • 塊狀動畫


          • 徽標動畫


          • 球狀動畫


          總結

          anime是一個非常值得使用的動畫引擎,它足夠簡單,足夠滿足需求,足夠的輕量,足夠的驚艷!enjoy it!

          、Mustache簡介

          mustache.js 是一個簡單強大的 JavaScript 模板引擎。使用mustache前需要通過script標簽引入它的js文件,然后按以下步驟操作:

          (1)定義模板字符串

          定義字符模板有兩種方式,

          • 方式一:在 js 代碼中定義
          • var template=['<ul>',
          • '<li>',
          • '</li>',
          • '</ul>
          • ].join('');
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 方式二:直接把模板內容用 script 定義在 HTML 中
          • <script id="tpl" type="text/html">
          • {{name}}
          • </script>
          • 1
          • 2
          • 3
          • 4
          • 然后在編譯模板之前,通過獲取 tpl 的 innerHTML 定義原始模板串:
          • var template=document.getElementById('tpl')
          • .innerHTML.trim();
          • 1
          • 2
          • 3

          (2)預編譯模板

          使用 parse 函數進行預編譯模板,即

          Mustache.parse(template);

          • 1
          • 2

          要注意,經過預編譯后的 template 已經不是原來的模板字符串了,連接數據類型都變成了數組類型。

          (3)渲染模板

          使用 render 函數進行渲染,即

          var rendered=Mustache.render(template, obj)

          • 1
          • 2

          obj 是數據源對象,mustache 會把模板中屬性標簽替換成與 obj 對象屬性名相同的屬性值。

          (4)替換 DOM 內容

          將渲染后的數據掛載到DOM樹上。

          2、mustache 標簽

          (1)變量:{{prop}}

          該標簽可將數據源對象上 prop 屬性對應的值,轉換成字符串進行輸出,該標簽渲染邏輯為:

          1)如果 prop 引用的值是 null 或 undefined,則渲染成空串;

          2)如果 prop 引用的是一個函數,則在渲染是自動執行這個函數,并把這個函數返回值作為渲染結果,假如這個返回值是 null 或 undefined,那么渲染結果仍然為空串,否則把返回值轉成字符串作為渲染結果;

          3)其他場景,直接把 prop 引用的值轉為字符串作為渲染結果;

          4)默認情況下,在渲染該標簽時,是對 prop 的原始值進行 URL 編碼或者 HTML 編碼之后再輸出,若要阻止這種編碼行為,應該使用 {{{prop}}}

          (2)帶有 HTML 的變量:{{{arg}}}

          (3){{#variable}} … {{/variable}}

          該標簽可以同時完成 if-else 和 for-each 以及動態渲染的模板功能。在這對標簽之間,可以定義其他模板內容,嵌套說有標簽。

          1)if-else

          只有 variable 屬性在數據源對象上存在,并且不為 falsy 值(JavaScript 6 個 falsy 值:null,undefined,NaN,0,false,空字符串),并且不為空數組的情況下,標簽之間的內容才會被渲染,否則不會被渲染。

          注意:當 variable 屬性引用的是一個函數的時候,{{#variable}}會自動調用這個函數,并把函數的返回值作為 if-else 渲染邏輯的判斷依據,也就是說如果這個函數的返回值是 falsy 值或者是空數組的時候,那么這對標簽之間的內容還是不會顯示。

          2)for-each

          當 variable 屬性所引用的是一個非空數組時,這對標簽之間的內容將會根據數組大小進行迭代,并且當數組元素為對象時,還會把該對象作為每一次迭代的上下文,以便迭代時標簽可以直接引用數組元素上的屬性。

          數組循環時 . 作為下標,或者使用對象屬性名提取屬性值。

          3)動態渲染

          當 variable 屬性所引用的是一個函數,并且這個函數的返回值還是一個函數的話,mustache 會再次調用這個返回的函數,并給它傳遞 2 個參數: text 表示原來的模板內容, render 表示 mustache 內部的執行渲染的對象,以便在這個函數內部可以通過這個 render對象,結合原來的模板內容,自定義渲染邏輯,并把函數的返回值作為渲染結果。

          (4){{^variable}}…{{/variable}}

          這對標簽,與{{#variable}} … {{/variable}}的 if-else 渲染執行相反邏輯,即只有在 variable 屬性不存在或者引用的是一個 falsy 值,或者是一個空數組時才會顯示標簽之間的內容,否則不會顯示。

          (5)注解:{{!注解}}

          (6)舉例:對象

          {

          "name":{

          "first":"Mi",

          "last":"Jack"

          }

          "age": "20"

          }

          {{name.first}}{{name.last}}

          {{age}}

          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10
          • 11

          循環使用:

          {

          "stooges":[

          {"name":"MOE"},

          {"name":"LARRY"}

          ]

          }

          {{#stooges}}

          {{name}}

          {{/stooges}}

          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10
          • 11

          3、示例

          (1)index.html

          <!DOCTYPE html>

          <html lang="en">

          <head>

          <meta charset="UTF-8">

          <title>test</title>

          </head>

          <body>

          <div id="J_wrapper"></div>

          <script src="require.js" charset="UTF-8"></script>

          <script>require(['app/tpl']);</script>

          </body>

          </html>

          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10
          • 11
          • 12
          • 13

          (2)tpl/helloworld.mustache

          <div>

          {{value}}

          </div>

          • 1
          • 2
          • 3
          • 4

          (3)app/tpl.js

          define(["mustache"],function(mustache){

          require(['text!tpl/helloworld.mustache'],function(tpl){

          mustache.parse(tpl)

          var view={value : "hello world"},

          html=mustache.render(tpl, view); // 第二個參數必須是對象

          document.getElementById("J_wrapper").innerHTML=html;

          })

          });

          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10

          (4)引入的 js 有: mustache.js、require.js、text.js

          參考:http://www.cnblogs.com/lyzg/p/5133250.html

          4、注意

          • 問題

          當我們雙擊HTML文件,或者在Sublime中右鍵選擇“open in browser”,瀏覽器會報一個錯:

          Failed to load file:///E:/testspace/mustache_test/tpl/helloworld.mustache:

          Cross origin requests are only supported for protocol schemes:

          http, data, chrome, chrome-extension, https.

          • 1
          • 2
          • 3
          • 4

          錯誤消息為:

          跨域請求僅支持:http, data, chrome, chrome-extension, https 等,不支持 file協議。這是由于瀏覽器(Webkit內核)的安全策略決定了file協議訪問的應用無法使用 XMLHttpRequest對象。

          sublime 默認是沒有內置HTTP服務器的,所以是以 file 的方式打開,并產生了該問題。

          • 解決方法

          (1)配置瀏覽器

          Windows:

          設置Chrome的快捷方式屬性,在“目標”后面加上--allow-file-access-from-files,注意前面有個空格,重新打開Chrome即可。

          Mac:

          只能通過終端打開瀏覽器:打開終端,輸入下面命令:open -a “Google Chrome” –args –disable-web-security然后就可以屏蔽安全訪問了[ –args:此參數可有可無]

          (2)安裝HTTP服務器

          若使用IDE,則無需配置,因為每個用于Web開發的IDE都內置HTTP服務器。

          編輯器一般沒有內置HTTP服務器,下面以sublime為例進行安裝 Sublime Server插件。

          1、在package control install中搜索 sublime server,然后安裝。(具體安裝不做略,與其他插件安裝步驟一樣)

          2、啟動sublime server。方法:Tool → SublimeServer → Start SublimeServer

          3、打開HTML文件,在右鍵菜單中選擇View in SublimeServer,此時就可以以HTTP方式在瀏覽器中訪問該文件了。

          若View in SublimeServer 為灰色不可點時,可能是未啟動成功,或者端口已被占用(SublimeServer默認使用8080端口

          用原生的js實現簡易的圖片延時加載。

          什么是延時加載?

          圖片延遲加載也稱 “懶加載”,通常應用于圖片比較多的網頁

          為什么要使用延時加載?

          假如一個網頁中,含有大量的圖片,當用戶訪問網頁時,那么瀏覽器會發送n個圖片的請求,加載速度會變得緩慢,性能也會下降。如果使用了延時加載,當用戶訪問頁面的時候,只加載首屏中的圖片;后續的圖片只有在用戶滾動時,即將要呈現給用戶瀏覽時再按需加載,這樣可以提高頁面的加載速度,也提升了用戶體驗。而且,統一時間內更少的請求也減輕了服務器中的負擔。

          延時加載的原理

          基本原理就是最開始時,所有圖片都先放一張占位圖片(如灰色背景圖),真實的圖片地址則放在 data-src 中,這么一來,網頁在打開時只會加載一張圖片。

          然后,再給 window 或 body 或者是圖片主體內容綁定一個滾動監聽事件,當圖片出現在可視區域內,即滾動距離 + 窗體可視距離 > 圖片到容器頂部的距離時,將講真實圖片地址賦值給圖片的 src,否則不加載。

          使用原生js實現圖片的延時加載

          延時加載需要傳入的參數:

          var selector=options.selector || 'img',
           imgSrc=options.src || 'data-src',
           defaultSrc=options.defaultSrc || '',
           wrapper=options.wrap || body;
          

          其中:

          • wrapper :延時加載的容器。在該容器下,所有符合圖片選擇器條件的圖片均會延時加載。
          • selector :圖片選擇器。表示需要延遲加載的圖片的選擇器,如 img.lazyload-image ,默認為所有的 img 標簽。
          • imgSrc :圖片真實地址存放屬性。表示圖片的真實路徑存放在標簽的哪個屬性中,默認為 data-src。
          • defaultSrc :初始加載的圖片地址,默認為空,當為空時,不處理延時加載的圖片的路徑,若圖片本身沒有路徑,則顯示為空。
          • 獲取容器中所有的圖片。
          function getAllImages(selector){
           return Array.prototype.concat.apply([], wrapper.querySelectorAll(selector));
          }
          

          該函數在容器中查找出所有需要延時加載的圖片,并將 NodeList 類型的對象轉換為允許使用 map 函數的數組。

          如果設置了初始圖片地址,則加載。

          function setDefault(){
           images.map(function(img){
           img.src=defaultSrc;
           })
          }
          

          給 window 綁定滾動事件

          function loadImage(){
           var nowHeight=body.scrollTop || doc.documentElement.scrollTop;
           console.log(nowHeight);
           if (images.length > 0){
           images.map(function(img, index) {
           if (nowHeight + winHeight > img.offsetTop) {
           img.src=img.getAttribute(imgSrc);
           images.splice(index, 1);
           }
           })
           }else{
           window.onscroll=null;
           }
          }
          window.onscroll=loadImage();
          

          每次滾動網頁時,都會遍歷所有的圖片,將圖片的位置與當前滾動位置作對比,當符合加載條件時,將圖片的真實地址賦值給圖片,并將圖片從集合中移除;當所有需要延時加載的圖片都加載完畢后,將滾動事件取消綁定。

          測試是否可行

          測試結果:

          從chrome的網絡請求圖中可見,5張圖片并不是在網頁打開的時候就請求了,而是當滑動到某個區域時才觸發加載,基本實現了圖片的延時加載。

          測試結果

          性能調整

          上述只是簡單的實現了一個延時加載的 demo,還有很多地方需要調整和完善。

          調整 1:onscroll 函數可能會被覆蓋

          問題:

          因為有時候頁面需要滾動無限加載時,插件會重寫 window 的 onscroll 函數,從而導致圖片的延時加載滾動監聽失效。

          解決辦法:

          需要更改為將監聽事件注冊到 window 上,移除時只需要移除相應的事件即可。

          調整后的代碼

          function bindListener(element, type, callback){
           if (element.addEventListener) {
           element.addEventListener(type, callback);
           }else if (element.attachEvent) {
           //兼容至 IE8
           element.attachEvent('on'+type, callback)
           }else{
           element['on'+type]=callback;
           }
          }
          function removeListener(element, type, callback){
           if (element.removeEventListener) {
           element.removeEventListener(type, callback);
           }else if (element.detachEvent) {
           element.detachEvent('on'+type, callback)
           }else{
           element['on'+type]=callback;
           }
          }
          function loadImage(){
           var nowHeight=body.scrollTop || doc.documentElement.scrollTop;
           console.log(nowHeight);
           if (images.length > 0){
           images.map(function(img, index) {
           if (nowHeight + winHeight > img.offsetTop) {
           img.src=img.getAttribute(imgSrc);
           images.splice(index, 1);
           }
           })
           }else{
           //解綁滾動事件
           removeListener(window, 'scroll', loadImage)
           }
          }
          //綁定滾動事件
          bindListener(window, 'scroll', loadImage)
          

          調整2:滾動時的回調函數執行次數太多

          問題

          在本次測試中,從動圖最后可以看到,當滾動網頁時,loadImage 函數執行了非常多次,滾輪每向下滾動 100px 基本上就要執行 10 次左右的 loadImage,若處理函數稍微復雜,響應速度跟不上觸發頻率,則會造成瀏覽器的卡頓甚至假死,影響用戶體驗。

          解決辦法

          使用 throttle 控制觸發頻率,讓瀏覽器有更多的時間間隔去執行相應操作,減少頁面抖動。

          調整后的代碼:

          //參考 `underscore` 的源碼
          var throttle=function(func, wait, options) {
           var context, args, result;
           var timeout=null;
           // 上次執行時間點
           var previous=0;
           if (!options) options={};
           // 延遲執行函數
           var later=function() {
           // 若設定了開始邊界不執行選項,上次執行時間始終為0
           previous=options.leading===false ? 0 : _now();
           timeout=null;
           result=func.apply(context, args);
           if (!timeout) context=args=null;
           };
           return function() {
           var now=_now();
           // 首次執行時,如果設定了開始邊界不執行選項,將上次執行時間設定為當前時間。
           if (!previous && options.leading===false) previous=now;
           // 延遲執行時間間隔
           var remaining=wait - (now - previous);
           context=this;
           args=arguments;
           // 延遲時間間隔remaining小于等于0,表示上次執行至此所間隔時間已經超過一個時間窗口
           // remaining大于時間窗口wait,表示客戶端系統時間被調整過
           if (remaining <=0 || remaining > wait) {
           clearTimeout(timeout);
           timeout=null;
           previous=now;
           result=func.apply(context, args);
           if (!timeout) context=args=null;
           //如果延遲執行不存在,且沒有設定結尾邊界不執行選項
           } else if (!timeout && options.trailing !==false) {
           timeout=setTimeout(later, remaining);
           }
           return result;
           };
          };
          //在調用高頻率觸發函數處使用 throttle 控制頻率在 次/wait
          var load=throttle(loadImage, 250);
          //綁定滾動事件
          bindListener(window, 'scroll', load);
          //解綁滾動事件
          removeListener(window, 'scroll', load)
          

          調整后的測試

          調整后的測試結果

          封裝為插件形式

          ;(function(window, undefined){
           function _now(){
           return new Date().getTime();
           }
           //輔助函數
           var throttle=function(func, wait, options) {
           var context, args, result;
           var timeout=null;
           // 上次執行時間點
           var previous=0;
           if (!options) options={};
           // 延遲執行函數
           var later=function() {
           // 若設定了開始邊界不執行選項,上次執行時間始終為0
           previous=options.leading===false ? 0 : _now();
           timeout=null;
           result=func.apply(context, args);
           if (!timeout) context=args=null;
           };
           return function() {
           var now=_now();
           // 首次執行時,如果設定了開始邊界不執行選項,將上次執行時間設定為當前時間。
           if (!previous && options.leading===false) previous=now;
           // 延遲執行時間間隔
           var remaining=wait - (now - previous);
           context=this;
           args=arguments;
           // 延遲時間間隔remaining小于等于0,表示上次執行至此所間隔時間已經超過一個時間窗口
           // remaining大于時間窗口wait,表示客戶端系統時間被調整過
           if (remaining <=0 || remaining > wait) {
           clearTimeout(timeout);
           timeout=null;
           previous=now;
           result=func.apply(context, args);
           if (!timeout) context=args=null;
           //如果延遲執行不存在,且沒有設定結尾邊界不執行選項
           } else if (!timeout && options.trailing !==false) {
           timeout=setTimeout(later, remaining);
           }
           return result;
           };
           };
           //分析參數
           function extend(custom, src){
           var result={};
           for(var attr in src){
           result[attr]=custom[attr] || src[attr]
           }
           return result;
           }
           //綁定事件,兼容處理
           function bindListener(element, type, callback){
           if (element.addEventListener) {
           element.addEventListener(type, callback);
           }else if (element.attachEvent) {
           element.attachEvent('on'+type, callback)
           }else{
           element['on'+type]=callback;
           }
           }
           //解綁事件,兼容處理
           function removeListener(element, type, callback){
           if (element.removeEventListener) {
           element.removeEventListener(type, callback);
           }else if (element.detachEvent) {
           element.detachEvent('on'+type, callback)
           }else{
           element['on'+type]=null;
           }
           }
           //判斷一個元素是否為DOM對象,兼容處理
           function isElement(o) {
           if(o && (typeof HTMLElement==="function" || typeof HTMLElement==="object") && o instanceof HTMLElement){
           return true;
           }else{
           return (o && o.nodeType && o.nodeType===1) ? true : false;
           };
           };
           var lazyload=function(options){
           //輔助變量
           var images=[],
           doc=document,
           body=document.body,
           winHeight=screen.availHeight;
           //參數配置
           var opt=extend(options, {
           wrapper: body,
           selector: 'img',
           imgSrc: 'data-src',
           defaultSrc: ''
           });
           if (!isElement(opt.wrapper)) {
           console.log('not an HTMLElement');
           if(typeof opt.wrapper !='string'){
           //若 wrapper 不是DOM對象 或者不是字符串,報錯
           throw new Error('wrapper should be an HTMLElement or a selector string');
           }else{
           //選擇器
           opt.wrapper=doc.querySelector(opt.wrapper) || body;
           }
           }
           //查找所有需要延時加載的圖片
           function getAllImages(selector){
           return Array.prototype.concat.apply([], opt.wrapper.querySelectorAll(selector));
           }
           //設置默認顯示圖片
           function setDefault(){
           images.map(function(img){
           img.src=opt.defaultSrc;
           })
           }
           //加載圖片
           function loadImage(){
           var nowHeight=body.scrollTop || doc.documentElement.scrollTop;
           console.log(nowHeight);
           if (images.length > 0){
           images.map(function(img, index) {
           if (nowHeight + winHeight > img.offsetTop) {
           img.src=img.getAttribute(opt.imgSrc);
           console.log('loaded');
           images.splice(index, 1);
           }
           })
           }else{
           removeListener(window, 'scroll', load)
           }
           }
           var load=throttle(loadImage, 250);
           return (function(){
           images=getAllImages(opt.selector);
           bindListener(window, 'scroll', load);
           opt.defaultSrc && setDefault()
           loadImage();
           })()
           };
           window.lazyload=lazyload;
          })(window);
          

          上述代碼拷貝到項目中即可使用,使用方式:

          //使用默認參數
          new lazyload();
          //使用自定義參數
          new lazyload({
           wrapper: '.article-content',
           selector: '.image',
           src: 'data-image',
           defaultSrc: 'example.com/static/images/default.png'
          });
          

          若在 IE8 中使用,沒有 map 函數時,請在引用插件前加入下列處理 map 函數兼容性的代碼:

          // 實現 ECMA-262, Edition 5, 15.4.4.19
          // 參考: http://es5.github.com/#x15.4.4.19
          if (!Array.prototype.map) {
           Array.prototype.map=function(callback, thisArg) {
           var T, A, k;
           if (this==null) {
           throw new TypeError(" this is null or not defined");
           }
           // 1. 將O賦值為調用map方法的數組.
           var O=Object(this);
           // 2.將len賦值為數組O的長度.
           var len=O.length >>> 0;
           // 3.如果callback不是函數,則拋出TypeError異常.
           if (Object.prototype.toString.call(callback) !="[object Function]") {
           throw new TypeError(callback + " is not a function");
           }
           // 4. 如果參數thisArg有值,則將T賦值為thisArg;否則T為undefined.
           if (thisArg) {
           T=thisArg;
           }
           // 5. 創建新數組A,長度為原數組O長度len
           A=new Array(len);
           // 6. 將k賦值為0
           k=0;
           // 7. 當 k < len 時,執行循環.
           while (k < len) {
           var kValue, mappedValue;
           //遍歷O,k為原數組索引
           if (k in O) {
           //kValue為索引k對應的值.
           kValue=O[k];
           // 執行callback,this指向T,參數有三個.分別是kValue:值,k:索引,O:原數組.
           mappedValue=callback.call(T, kValue, k, O);
           // 返回值添加到新數組A中.
           A[k]=mappedValue;
           }
           // k自增1
           k++;
           }
           // 8. 返回新數組A
           return A;
           };
          }
          

          希望本文能幫助到您!

          點贊+轉發,讓更多的人也能看到這篇內容(收藏不點贊,都是耍流氓-_-)

          關注 {我},享受文章首發體驗!

          每周重點攻克一個前端技術難點。更多精彩前端內容私信 我 回復“教程”


          主站蜘蛛池模板: 黑巨人与欧美精品一区| 欧美日韩精品一区二区在线视频| 无码国产精成人午夜视频一区二区| 亚洲熟妇av一区二区三区| 亚洲一区二区三区夜色| 精品国产天堂综合一区在线| 日本一区高清视频| 亚洲第一区香蕉_国产a| 国产亚洲欧洲Aⅴ综合一区| 国产成人一区二区三区电影网站| 色一乱一伦一图一区二区精品 | 国产日韩视频一区| 国产精品久久一区二区三区| 亚洲中文字幕无码一区二区三区| 国产亚洲综合一区二区三区 | 色综合视频一区二区三区44| 国产精品无码一区二区三级 | 午夜视频久久久久一区 | 免费看一区二区三区四区| 国产一区二区在线|播放| 精品国产AV无码一区二区三区| 亚洲欧美一区二区三区日产| 亚洲午夜在线一区| 亚洲中文字幕在线无码一区二区| 国产精品无码一区二区三区电影| 男人免费视频一区二区在线观看| 日韩久久精品一区二区三区| 韩国资源视频一区二区三区| 亚洲AV网一区二区三区| 国产一区二区在线| 国产SUV精品一区二区四 | 精品福利一区二区三区免费视频| 亚洲AV色香蕉一区二区| 性无码免费一区二区三区在线| 亚洲熟妇av一区二区三区| 亚洲无删减国产精品一区| 国产精品熟女一区二区| 一区二区三区视频在线观看| 日韩一区二区三区无码影院| 亚洲宅男精品一区在线观看| 无码日韩人妻av一区免费|