92国产精品视频_亚洲a级在线观看_国产精品电影观看_国产精品免费观看在线_精品伊人久久97_亚洲人成在线观_尤物九九久久国产精品的特点_成人激情在线播放_成人黄色大片在线免费观看_亚洲成人精品久久久_久久免费视频在线观看_久久精品国产一区_国产一区二区三区18_亚洲欧美中文字幕在线一区_日韩美女中文字幕_日韩视频免费在线

首頁

jQuery-瀑布流

seo達人

如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

html與css:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
/* 標簽重定義 */

* {
margin: 0;
padding: 0;
border: none;
}

body {
background: #ddd;
}

img {
border: none;
}

a {
text-decoration: none;
color: #444;
}

a:hover {
color: #999;
}
/* wrap */

#wrap {
position: relative;
width: auto;
height: auto;
margin: 0 auto;
}

#wrap>div {
float: left;
box-sizing: border-box;
width: 280px;
height: auto;
margin: 10px;
padding: 10px;
border-radius: 5px;
background: #fff;
}

#wrap>div>img {
width: 260px;
margin: 0 auto;
}

#wrap>div>a {
display: block;
font-size: 18px;
font-weight: bold;
line-height: 40px;
text-align: center;
}
</style>
</head>


<body>
<div id="wrap">
<div>
<img src="img/1.jpg">
<a target="_blank">第一張 路飛與艾斯</a>
</div>
<div>
<img src="img/2.jpg">
<a target="_blank">第二張 艾博</a>
</div>
<div>
<img src="img/3.jpg">
<a target="_blank">第三張 路飛</a>
</div>
<div>
<img src="img/4.jpg">
<a target="_blank">第四張 艾斯</a>
</div>
<div>
<img src="img/5.jpg">
<a target="_blank">第五張 女王</a>
</div>
<div>
<img src="img/6.jpg">
<a target="_blank">第六張 香吉士</a>
</div>
<div>
<img src="img/7.jpg">
<a target="_blank">第七張 艾斯</a>
</div>
<div>
<img src="img/8.jpg">
<a target="_blank">第八張 霸氣</a>
</div>
</div>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/script.js"></script>
</body>

</html>

JS:

var waterfall = function(wrap, boxes) {
// 獲取屏幕可以顯示的列數
var boxWidth = boxes.eq(0).width() + 40;
var windowWidth = $(window).width();
var colsNumber = Math.floor(windowWidth / boxWidth);


// 設置容器的寬度
wrap.width(boxWidth * colsNumber);


// 定義一個數組并存儲每一列的高度
var everyHeight = new Array();
for (var i = 0; i < boxes.length; i++) {
if (i < colsNumber) {
everyHeight[i] = boxes.eq(i).height() + 40;
} else {
var minHeight = Math.min.apply(null, everyHeight);
var minIndex = getIndex(minHeight, everyHeight);
boxes.eq(i).css({
'position': 'absolute',
'top': minHeight,
'left': boxes.eq(minIndex).position().left,
'opacity': '0'
}).stop().animate({
'opacity': '1'
}, 1000);
everyHeight[minIndex] += boxes.eq(i).height() + 40;
};
}
};


// 獲取最小列的索引
function getIndex(minHeight, everyHeight) {
for (index in everyHeight) {
if (everyHeight[index] == minHeight) {
return index;
};
};
};

$(document).ready(function(event) {
var wrap = $('#wrap');
var boxes = $('#wrap').children('div');
waterfall(wrap, boxes);
});

藍藍設計m.skdbbs.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務

js json的格式、存儲與發送

高勁

1.Json的格式

其實json就是對象。源生的js代碼并沒有類的概念。對象救就是object。對象有自己的屬性,也可以有自己的方法。json是一種輕量級的存儲和交換信息的語言。他有自己的格式。

較為簡單的json。里面只有簡單的對象,key+value的形式:

  • var CellInfo = {


  •                 "CellId":         document.getElementById("CellId").value,


  •                 "UEAmount":         document.getElementById("UE value").innerText,


  •                 "BearAddDel":         document.getElementById("bearvalue").innerText,


  •                 "UEAttachDe":         document.getElementById("attachvalue").innerText,


  •                 "TotalDLTP":         document.getElementById("dlvalue").innerText,

  •               "TotalULTP":         document.getElementById("ulvalue").innerText,


  •                 };



每個元素之間用逗號隔開。調用每個key的值可用語句。例如:CellInfo.UEAmunt,就可取出其中的值。

較為復雜的json。里面包含了對象。


  • var UEGroup1 = {



  •                 "UEAmount": ua[1],



  •                 "DBR1": {



  •                         "DLPackageSize": DS[1],



  •                         "ULPackageSize": US[1],



  •                         "DLTP": DP[1],



  •                         "ULTP": UP[1],



  •                         "QCI": QCI[0]



  •                 },



  •                 "DBR2": {



  •                         "DLPackageSize": DS[2],



  •                         "ULPackageSize": US[2],



  •                         "DLTP": DP[2],



  •                         "ULTP": UP[2],



  •                         "QCI": QCI[1]



  •                 },



  •                 "DBR3": {



  •                         "DLPackageSize": DS[3],



  •                         "ULPackageSize": US[3],



  •                         "DLTP": DP[3],



  •                         "ULTP": UP[3],



  •                         "QCI": QCI[2]



  •                 }



  •         };




例如這個UEGroup1,里面的元素不僅有簡單的key+value,還包含了三個對象。對象里的元素用{}括起來,彼此之間用逗號隔開。想具體訪問某個元素的值也是通過逐層key,例如:UEGrooup1.DBR1.DLPackageSize

動態的往json只增加元素,增加對象。

前面說的幾個都是靜態的,提前寫好的。那如果臨時想加一個元素,例如在Cellinfo這個json中相加一個number的元素:

CellInfo.number=10;

對于往json中添加對象。例如我們想把Cellinfo和UEGroup1這兩個object作為兩個元素加入到另外一個大的json中:

  • var PETInfo = {};//聲明了一個空的對象



  • var CellInfo = {



  •                 "CellId":         document.getElementById("CellId").value,



  •                 "UEAmount":         document.getElementById("UE value").innerText,



  •                 "BearAddDel":         document.getElementById("bearvalue").innerText,



  •                 "UEAttachDe":         document.getElementById("attachvalue").innerText,



  •                 "TotalDLTP":         document.getElementById("dlvalue").innerText,



  •                 "TotalULTP":         document.getElementById("ulvalue").innerText,



  •                 };



  • str_CellInfo = JSON.stringify(CellInfo);//將CellInfo轉為字符串對象



  • PETInfo.CellInfo=str_CellInfo;//在PETInfo中添加名為Cellinfo的屬性,并賦值


2.json的發送

json寫好后,發送給后臺。至于后臺怎么處理數據我們不關心。發送json的函數如下:

  • function post(path, params, method) {



  •         method = method || "post";



  •         var form = document.createElement("form");



  •         form.setAttribute("method", method);



  •         form.setAttribute("action", path);





  •         for (var key in params) {



  •                 if (params.hasOwnProperty(key)) {



  •                         var hiddenField = document.createElement("input");



  •                         hiddenField.setAttribute("type", "hidden");



  •                         hiddenField.setAttribute("name", key);



  •                         hiddenField.setAttribute("value", params[key]);



  •                         form.appendChild(hiddenField);



  •                 }



  •         }



  •         document.body.appendChild(form);



  •         form.submit();



  • }

    參數分別是后臺的地址,變量,方法。變量就是我們自己寫好的json,方法默認為post。例如我們想發剛剛的PETInfo

    $.post('http://10.140.160.64:3012/users/ueinfo', PETInfo);

    數據的發送、并獲取結果的實例:

    需求描述:用戶填寫一系列的輸入框,前端獲取數據,封裝成json并發送給服務器,服務器會返回一個返回值,表示狀態。前端需要展示這個內容提示客戶。

    • function sendBook(){



    •         var Book={



    •                 "openstackIP":document.getElementById("openstackIP").value,



    •                 "RAPName":document.getElementById("RAPName").value,



    •                 "RAPVer":document.getElementById("ver").value,



    •                 "OAMIP":document.getElementById("OAMIP").value



    •         };//json封裝用戶輸入的數據



    •         $.post('http://10.140.160.64:3012/servers/env/book', Book)//調用post傳輸數據



    •         .done((resp) => {//傳輸后獲取服務器的返回值



    •         alert(resp);//展示返回值



    •        // window.location.href = 'Environment-List.html';//選擇性界面跳轉



    •     });



    • }

    3.json在本地的存儲

    存儲數據有很多方法。這里我用的是localStorage。localStorage與cookie的區別如下:

    ① cookie在瀏覽器與服務器之間來回傳遞。
    sessionStorage和localStorage不會把數據發給服務器,僅在本地保存

    ②數據有效期不同:
    cookie只在設置的cookie過期時間之前一直有效,即使窗口或瀏覽器關閉。
    sessionStorage:僅在當前瀏覽器窗口關閉前有效。
    localStorage  始終有效,長期保存。

    ③cookie數據還有路徑的概念,可以限制cookie只屬于某個路徑下。
    存儲大小也不同,cookie數據不能超過4k,sessionStorage和localStorage 雖然也有存儲大小的限制,但比cookie大得多,可以達到5M或更大。

    ④ 作用域不用
    sessionStorage不在不同的瀏覽器窗口中共享;
    localStorage在所有同源窗口中都是共享的;
    cookie也是在所有同源窗口中都是共享的;

    WebStorage 支持事件通知機制,可以將數據更新的通知發送給監聽者。Web Storage 的 api 接口使用更方便。

    用localstage存儲json的實例:

    • str_PETInfo=JSON.stringify(PETInfo);//將json轉為字符串對象



    • window.localStorage.setItem("PET",str_PETInfo);//存入本地,該json的key為PET


    將json取出來:



    • var PET=JSON.parse(window.localStorage.getItem("PET"));//將字符串轉化為json



    • var CellInfo=JSON.parse(PET.CellInfo);//json中的Cellinfo對象轉化為json



jquery 關于table的全選與反選

seo達人

如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

控制表格的多選和反選,直接上代碼,順便安利一個小知識點:tr的底邊框不顯示的問題,解決辦法是:table{border-collapse:collapse;}    


  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title></title>
  5. <style>
  6. *{margin:0;padding:0;}
  7. table{border-collapse:collapse}
  8. .detail_tb {width: 100%;border: 1px solid #ccc;}
  9. .detail_tb .fied_header {height: 38px;line-height: 38px;border-left: none;border-bottom: 1px solid #ccc;background-color: #ececec;}
  10. .detail_tb .fied_header th {text-align: center;border-right: 1px solid #ccc;color: #333;font-size: 14px;}
  11. .detail_tb .fied_header th input {vertical-align: middle;}
  12. .detail_tb tr {height: 38px;line-height: 38px;border-left: none;border-bottom: 1px solid #ccc;background-color: #fff;}
  13. .detail_tb tr td {text-align: center;border-right: 1px solid #ccc;color: #666;font-size: 14px;}
  14. .detail_tb tr td input {float: left;margin: 12px 5px 0 10px;}
  15. .detail_tb tr td span {float: left;}
  16. .detail_tb tr td select {display: inline-block;width: 90px;height: 24px;}
  17. </style>
  18. </head>
  19. <body>
  20. <table class="detail_tb" >
  21. <thead>
  22. <tr class="fied_header">
  23. <th width="65"><input type="checkbox" value="number" id="number"> 序號</th>
  24. <th width="110">孩子姓名</th>
  25. <th width="130">家長電話</th>
  26. <th width="110">介紹人孩子姓名</th>
  27. <th width="130">介紹人電話</th>
  28. <th width="150">報名時間</th>
  29. <th width="100">分組情況</th>
  30. <th width="100">拉新數量</th>
  31. <th width="100">是否簽到</th>
  32. <th width="100">是否發獎</th>
  33. </tr>
  34. </thead>
  35. <tbody id="tbody">
  36. <tr>
  37. <td width="65"><input type="checkbox" value="" id="" ><span>1</span></td>
  38. <td width="110">張三</td>
  39. <td width="130">13888888888</td>
  40. <td width="110">李四</td>
  41. <td width="130">13888888888</td>
  42. <td width="150">2016/08/6 21:00</td>
  43. <td width="100">
  44. <select name="" id="">
  45. <option value="">未分組</option>
  46. <option value="">1</option>
  47. <option value="">2</option>
  48. </select>
  49. </td>
  50. <td width="100">33</td>
  51. <td width="100"></td>
  52. <td width="100">
  53. <select name="" id="">
  54. <option value=""></option>
  55. <option value="">獎品1</option>
  56. <option value="">獎品2</option>
  57. </select>
  58. </td>
  59. </tr>
  60. <tr>
  61. <td width="65"><input type="checkbox" value="" id=""><span>2</span></td>
  62. <td width="110">張四</td>
  63. <td width="130">13888888888</td>
  64. <td width="110">李四</td>
  65. <td width="130">13888888888</td>
  66. <td width="150">2016/08/6 21:00</td>
  67. <td width="100">
  68. <select name="" id="">
  69. <option value="">未分組</option>
  70. <option value="">1</option>
  71. <option value="">2</option>
  72. </select>
  73. </td>
  74. <td width="100">33</td>
  75. <td width="100"></td>
  76. <td width="100">
  77. <select name="" id="">
  78. <option value=""></option>
  79. <option value="">獎品1</option>
  80. <option value="">獎品2</option>
  81. </select>
  82. </td>
  83. </tr>
  84. <tbody>
  85. </table>
  86. <script src="https://cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
  87. <script type="text/javascript">
  88. // 全選和反選
  89. $("#number").click(function () {
  90. var isChecked = $("#number").prop("checked");
  91. $("#tbody input").prop("checked", isChecked);
  92. })
  93. // 單獨選項控制全選
  94. $("#tbody input").click(function () {
  95. var allLength = $("#tbody input").length;
  96. var checkedLength = $("#tbody input:checked").length;
  97. if(allLength == checkedLength){
  98. $("#number").prop("checked",true);
  99. }else {
  100. $("#number").prop("checked",false);
  101. }
  102. });
  103. </script>
  104. </body>
  105. </html>



藍藍設計m.skdbbs.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務


手機端頁面常見的問題

高勁

1.解決頁面使用overflow: scroll在iOS上滑動卡頓的問題?



首先你可能會給頁面的html和body增加了height: 100%, 然后就可能造成IOS上頁面滑動的卡頓問題。解決方案是:



(1) 看是否能把body和html的height: 100%去除掉。

(2) 在滾動的容器中增加:-webkit-overflow-scrolling: touch或者給body增加:body {overflow-x: hidden}。



2.ios頁面橡皮彈回效果遮擋頁面選項卡?



(1) 有時body和html的height: 100%去除掉問題可能就沒有了。

(2) 到達臨界值的時候在阻止事件默認行為

var startY,endY;
//記錄手指觸摸的起點坐標
$('body').on('touchstart',function (e) {
     startY = e.touches[0].pageY;
});
$('body').on('touchmove',function (e) {
     endY = e.touches[0].pageY;  //記錄手指觸摸的移動中的坐標
     //手指下滑,頁面到達頂端不能繼續下滑
     if(endY>startY&& $(window).scrollTop()<=0){
         e.preventDefault();
     }
   //手指上滑,頁面到達底部能繼續上滑
     if(endY<startY&& $(window).scrollTop()+ 
         $(window).height()>=$('body')[0].scrollHeight){
         e.preventDefault();
     }
})
有時也會碰見彈窗出來后兩個層的橡皮筋效果出現問題,我們可以在彈出彈出時給底層頁面加上一個類名,類名禁止頁面滑動這樣下層的橡皮筋效果就會被禁止,就不會影響彈窗層。 3.IOS機型margin屬性無效問題? (1) 設置html body的高度為百分比時,margin-bottom在safari里失效 (2) 直接padding代替margin 4.Ios綁定點擊事件不執行?  (1)添加樣式cursor :pointer。點擊后消除背景閃一下的css:-webkit-tap-highlight-color:transparent;  5.Ios鍵盤換行變為搜索? 首先,input 要放在 form里面。 這時 "換行" 已經變成 “前往”。 如果想變成 “搜索”,input 設置 type="search"。 6.Jq對a標簽點擊事件不生效? 出現這種情況的原因不明,有的朋友解釋:我們平時都是點擊的A標簽中的文字了。 所以要想用JS模擬點擊A標簽事件,就得先往A標簽中的文字添加能被JS捕獲的元素,然后再用JS模擬點擊該元素即可。但是我覺得不合理,雖然找不到原因但是解決辦法還是有的。 (1)document.getElementById("abc ").click(); (2)$("#abc ")[0].click(); 7.有時因為服務器或者別的原因導致頁面上的圖片沒有找到? 這是我們想需要用一個本地的圖片代替沒有找的的圖片
<script type="text/javascript"> 
function nofind(){ 
var img=event.srcElement; 
img.src="images/logoError.png"; 
img.onerror=null; 控制不要一直跳動 
} 
</script> 
<img src="images/logo.png" />
8.transform屬性影響position:fixed?

(1)規范中有規定:如果元素的transform值不為none,則該元素會生成包含塊和層疊上下文。CSS Transforms Module Level 1不只在手機上,電腦上也一樣。除了fixed元素會受影響之外,z-index(層疊上下文)值也會受影響。絕對定位元素等和包含塊有關的屬性都會受到影響。當然如果transform元素的display值為inline時又會有所不同。最簡單的解決方法就是transform元素內部不能有absolute、fixed元素.

9.ios對position: fixed不太友好,有時我們需要加點處理?

在安卓上面,點擊頁面底部的輸入框,軟鍵盤彈出,頁面移動上移。
而ios上面,點擊頁面底部輸入框,軟鍵盤彈出,輸入框看不到了。。。查資料說什么的都有,iscroll,jquery-moblie,absolute,fixe,static都非常復雜,要改很多。。。
讓他彈出時讓滾動條在部
var u = navigator.userAgent, app = navigator.appVersion;
var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios終端
if (isiOS) {
    $('textarea').focus(function () {
        window.setTimeout('scrollBottom()', 500);
    });
}
function scrollBottom() {
    window.scrollTo(0, $('body').height());
}
10.jq validate插件驗證問題?

(1)所以的input必須有name不然會出錯

11.有時手機會出現斷網的情況,我沒可能會對斷網的情況做一些處理?

(1)navigator.onLine可判斷是否是脫機狀態.

12.判斷對象的長度?

(1)用Object.keys,Object.keys方法返回的是一個數組,數組里面裝的是對象的屬性
var person = {
    "name" : "zhangshan",
    "sex" : "man",
    "age" : "50",
    "height" : "180",
    "phone" : "1xxxxxxxxxx",
    "email" : "xxxxxxxxx@xxx.com"
};
var arr = Object.keys(person);
console.log(arr.length);
(2)Object.getOwnPropertyNames(obj).length

13.上一題我們用到了Object.keys與Object.getOwnPropertyNames他們的區別?

Object.keys定義:返回一個對象可枚舉屬性的字符串數組;
Object.getOwnPropertyNames定義:返回一個對象可枚舉、不可枚舉屬性的名稱;
屬性的可枚舉性、不可枚舉性:定義:可枚舉屬性是指那些內部 “可枚舉” 標志設置為 true 的屬性,對于通過直接的賦值和屬性初始化的屬性,該標識值默認為即為 true,對于通過 Object.defineProperty 等定義的屬性,該標識值默認為 false。
var obj = { "prop1": "v1" };
Object.defineProperty(obj, "prop2", { value: "v2", enumerable: false });
console.log(Object.keys(obj).length);           //output:1
console.log(Object.getOwnPropertyNames(obj).length);    //output:2
console.log(Object.keys(obj));           //output:Array[1] => [0: "prop1"]
console.log(Object.getOwnPropertyNames(obj));    //output:Array[2] => [0: "prop1", 1: "prop2"]

綜合實例


var obj = { "prop1": "v1" };
Object.defineProperty(obj, "prop2", { value: "v2", enumerable: false});
console.log(obj.hasOwnProperty("prop1")); //output: true
console.log(obj.hasOwnProperty("prop2")); //output: true
console.log(obj.propertyIsEnumerable("prop1")); //output: true
console.log(obj.propertyIsEnumerable("prop2")); //output: false
console.log('prop1' in obj);    //output: true
console.log('prop2' in obj);    //output: true
for (var item in obj) {
    console.log(item);
}
//output:prop1
for (var item in Object.getOwnPropertyNames(obj)) {
    console.log(Object.getOwnPropertyNames(obj)[item]);
}
//ouput:[prop1,prop2]

14.移動開發不同手機彈出數字鍵盤問題?



(1)type="tel"

iOS和Android的鍵盤表現都差不多

(2)type="number"

優點是Android下實現的一個真正的數字鍵盤

缺點一:iOS下不是九宮格鍵盤,輸入不方便

缺點二:舊版Android(包括微信所用的X5內核)在輸入框后面會有超級雞肋的小尾巴,好在Android 4.4.4以后給去掉了。

不過對于缺點二,我們可以用webkit私有的偽元素給fix掉:


input[type=number]::-webkit-inner-spin-button,  
input[type=number]::-webkit-outer-spin-button { 
        -webkit-appearance: none; 
        appearance: none; 
        margin: 0; 
}

(3)pattern屬性



pattern用于驗證表單輸入的內容,通常HTML5的type屬性,比如email、tel、number、data類、url等,已經自帶了簡單的數據格式驗證功能了,加上pattern后,前端部分的驗證更加簡單了。

顯而易見,pattern的屬性值要用正則表達式。

實例 簡單的數字驗證

數字的驗證有兩個:

<input type="number" pattern="d"> 

<input type="number" pattern="[0-9]*">



15.input[number]類型輸入非數字字符



js獲取的值是空;比如-12,+123等



16.Javascript:history.go()和history.back()的用法與區別?




簡單的說就是:go(-1):返回上一頁,原頁面表單中的內容會丟失;back():返回上一頁,原頁表表單中的內容會保留。history.go(-1):后退+刷新history.back():后退

之所以注意到這個區別,是因為不同的瀏覽器后退行為也是有區別的,而區別就跟javascript:history.go()和history.back()的區別類似。

Chrome和ff瀏覽器后退頁面,會刷新后退的頁面,若有數據請求也會提交數據申請。類似于history.go(-1);

而safari(包括桌面版和ipad版)的后退按鈕則不會刷新頁面,也不會提交數據申請。類似于javascript:history.back();



17.Meta基礎知識:



<meta name="viewport"content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />

// width    設置viewport寬度,為一個正整數,或字符串‘device-width’

// height   設置viewport高度,一般設置了寬度,會自動解析出高度,可以不用設置

// initial-scale    默認縮放比例,為一個數字,可以帶小數

// minimum-scale    允許用戶最小縮放比例,為一個數字,可以帶小數

// maximum-scale    允許用戶最大縮放比例,為一個數字,可以帶小數

// user-scalable    是否允許手動縮放 

空白頁基本meta標簽

<!-- 設置縮放 -->

<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, minimal-ui" />

<!-- 可隱藏地址欄,僅針對IOS的Safari(注:IOS7.0版本以后,safari上已看不到效果) -->

<meta name="apple-mobile-web-app-capable" content="yes" />

<!-- 僅針對IOS的Safari頂端狀態條的樣式(可選default/black/black-translucent ) -->

<meta name="apple-mobile-web-app-status-bar-style" content="black" />

<!-- IOS中禁用將數字識別為電話號碼/忽略Android平臺中對郵箱地址的識別 -->

<meta name="format-detection"content="telephone=no, email=no" />

其他meta標簽

<!-- 啟用360瀏覽器的極速模式(webkit) -->

<meta name="renderer" content="webkit">

<!-- 避免IE使用兼容模式 -->

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<!-- 針對手持設備優化,主要是針對一些老的不識別viewport的瀏覽器,比如黑莓 -->

<meta name="HandheldFriendly" content="true">

<!-- 微軟的老式瀏覽器 -->

<meta name="MobileOptimized" content="320">

<!-- uc強制豎屏 -->

<meta name="screen-orientation" content="portrait">

<!-- QQ強制豎屏 -->

<meta name="x5-orientation" content="portrait">

<!-- UC強制全屏 -->

<meta name="full-screen" content="yes">

<!-- QQ強制全屏 -->

<meta name="x5-fullscreen" content="true">

<!-- UC應用模式 -->

<meta name="browsermode" content="application">

<!-- QQ應用模式 -->

<meta name="x5-page-mode" content="app">

<!-- windows phone 點擊無高光 -->

<meta name="msapplication-tap-highlight" content="no">



18.移動端如何定義字體font-family?



@ --------------------------------------中文字體的英文名稱

@ 宋體 SimSun

@ 黑體 SimHei

@ 微信雅黑 Microsoft Yahei

@ 微軟正黑體 Microsoft JhengHei

@ 新宋體 NSimSun

@ 新細明體 MingLiU

@ 細明體 MingLiU

@ 標楷體 DFKai-SB

@ 仿宋 FangSong

@ 楷體 KaiTi

@ 仿宋_GB2312 FangSong_GB2312

@ 楷體_GB2312 KaiTi_GB2312 

@

@ 說明:中文字體多數使用宋體、雅黑,英文用Helvetica



body { font-family: Microsoft Yahei,SimSun,Helvetica; }



19.打電話發短信寫郵件怎么實現?


// 一、打電話
<a href="tel:0755-10086">打電話給:0755-10086</a>
//  二、發短信,winphone系統無效
<a href="sms:10086">發短信給: 10086</a>
// 三、寫郵件
<a href="mailto:863139978@qq.com">點擊我發郵件</a>
//2.收件地址后添加?cc=開頭,可添加抄送地址(Android存在兼容問題)
<a href="mailto:863139978@qq.com?cc=zhangqian0406@yeah.net">點擊我發郵件</a>
//3.跟著抄送地址后,寫上&bcc=,可添加密件抄送地址(Android存在兼容問題)
<a href="mailto:863139978@qq.com?cc=zhangqian0406@yeah.net&bcc=384900096@qq.com">點擊我發郵件</a>
//4.包含多個收件人、抄送、密件抄送人,用分號(;)隔開多個郵件人的地址
<a href="mailto:863139978@qq.com;[url=mailto:384900096@qq.com]384900096@qq.com[/url]">點擊我發郵件</a>
//5.包含主題,用?subject=
<a href="mailto:863139978@qq.com?subject=郵件主題">點擊我發郵件</a>
//6.包含內容,用?body=;如內容包含文本,使用%0A給文本換行 
<a href="mailto:863139978@qq.com?body=郵件主題內容%0A騰訊誠信%0A期待您的到來">點擊我發郵件</a>
//7.內容包含鏈接,含http(s)://等的文本自動轉化為鏈接
<a href="mailto:863139978@qq.com?body=http://www.baidu.com">點擊我發郵件</a>
//8.內容包含圖片(PC不支持)
<a href="mailto:863139978@qq.com?body=<img src='images/1.jpg' />">點擊我發郵件</a>
//9.完整示例
<a href="mailto:863139978@qq.com;[url=mailto:384900096@qq.com]384900096@qq.com[/url]?cc=zhangqian0406@yeah.net&bcc=993233461@qq.com&subject=[郵件主題]&body=騰訊誠邀您參與%0A%0A[url=http://www.baidu.com]http://www.baidu.com[/url]%0A%0A<img src='images/1.jpg' />">點擊我發郵件</a>
20.移動端touch事件(區分webkit和winphone)?

// 以下支持webkit
touchstart——當手指觸碰屏幕時候發生。不管當前有多少只手指
touchmove——當手指在屏幕上滑動時連續觸發。通常我們再滑屏頁面,會調用event的preventDefault()可以阻止默認情況的發生:阻止頁面滾動
touchend——當手指離開屏幕時觸發
touchcancel——系統停止跟蹤觸摸時候會觸發。例如在觸摸過程中突然頁面alert()一個提示框,此時會觸發該事件,這個事件比較少用

//TouchEvent說明:
touches:屏幕上所有手指的信息
targetTouches:手指在目標區域的手指信息
changedTouches:最近一次觸發該事件的手指信息
touchend時,touches與targetTouches信息會被刪除,changedTouches保存的最后一次的信息,最好用于計算手指信息

//參數信息(changedTouches[0])
clientX、clientY在顯示區的坐標
target:當前元素

//事件響應順序
ontouchstart > ontouchmove > ontouchend > onclick


React Native原生與JS層交互

seo達人

如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

最近在對《React Native移動開發實戰》一書進行部分修訂和升級。在React Native開發中,免不了會涉及到原生代碼與JS層的消息傳遞等問題,那么React Native究竟是如何實現與原生的互相操作的呢?

原生給React Native傳參

原生給React Native傳值

原生給JS傳值,主要依靠屬性,也就是通過initialProperties,這個RCTRootView的初始化函數的參數來完成。通過RCTRootView的初始化函數你可以將任意屬性傳遞給React Native應用,參數initialProperties必須是NSDictionary的一個實例。RCTRootView有一個appProperties屬性,修改這個屬性,JS端會調用相應的渲染方法。

使用RCTRootView將React Natvie視圖封裝到原生組件中。RCTRootView是一個UIView容器,承載著React Native應用。同時它也提供了一個聯通原生端和被托管端的接口。

例如有下面一段OC代碼:

NSURL *jsCodeLocation;

  jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; NSArray *imageList = @[@"http://foo.com/bar1.png",
                         @"http://foo.com/bar2.png"]; NSDictionary *wjyprops = @{@"images" : imageList};

  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"ReactNativeProject" initialProperties:wjyprops
                                                   launchOptions:launchOptions];
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

下面是JS層的處理:

import React, { Component } from 'react'; import {
  AppRegistry,
  View,
  Image,
} from 'react-native'; class ImageBrowserApp extends Component { renderImage(imgURI) { return (
      <Image source={{uri: imgURI}} />
    );
  }
  render() { return (
      <View>
        {this.props.images.map(this.renderImage)}
      </View>
    );
  }
}

AppRegistry.registerComponent('ImageBrowserApp', () => ImageBrowserApp);
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

不管OC中關于initialProperties的名字叫什么,在JS中都是this.props開頭,然后接下來才是key名字。

{"rootTag":1,"initialProps":{"images":["http://foo.com/bar1.png","http://foo.com/bar2.png"]}}. 
    
  • 1

使用appProperties進行參數傳遞

RCTRootView同樣提供了一個可讀寫的屬性appProperties。在appProperties設置之后,React Native應用將會根據新的屬性重新渲染。當然,只有在新屬性和舊的屬性有更改時更新才會被觸發。

NSArray *imageList = @[@"http://foo.com/bar3.png", @"http://foo.com/bar4.png"]; rootView.appProperties = @{@"images" : imageList};
    
  • 1
  • 2
  • 3

可以隨時更新屬性,但是更新必須在主線程中進行,讀取則可以在任何線程中進行。

React Native執行原生方法及回調

React Native執行原生方法

.h的文件代碼:

#import <Foundation/Foundation.h> #import <RCTBridgeModule.h> @interface wjyTestManager : NSObject<RCTBridgeModule> @end
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

.m的文件代碼:

#import "wjyTestManager.h" @implementation wjyTestManager RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(doSomething:(NSString *)aString withA:(NSString *)a)
{ NSLog(@"%@,%@",aString,a);
} @end
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

為了實現RCTBridgeModule協議,你的類需要包含RCT_EXPORT_MODULE()宏。這個宏也可以添加一個參數用來指定在Javascript中訪問這個模塊的名字。如果你不指定,默認就會使用這個Objective-C類的名字。

并且必須明確的聲明要給Javascript導出的方法,否則React Native不會導出任何方法。OC中聲明要給Javascript導出的方法,通過RCT_EXPORT_METHOD()宏來實現。

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Alert,
  TouchableHighlight,
} from 'react-native';

import {
  NativeModules,
  NativeAppEventEmitter
} from 'react-native'; var CalendarManager = NativeModules.wjyTestManager; class ReactNativeProject extends Component { render() { return (
          <TouchableHighlight onPress={()=>CalendarManager.doSomething('sdfsdf','sdfsdfs')}>
          <Text style={styles.text}
      >點擊 </Text>
          </TouchableHighlight>

        );
      }
} const styles = StyleSheet.create({
text: {
  flex: 1,
  marginTop: 55,
  fontWeight: 'bold' },
});

AppRegistry.registerComponent('ReactNativeProject', () => ReactNativeProject);
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

要用到NativeModules則要引入相應的命名空間import { NativeModules } from ‘react-native’;然后再進行調用CalendarManager.doSomething(‘sdfsdf’,’sdfsdfs’);橋接到Javascript的方法返回值類型必須是void。React Native的橋接操作是異步的,所以要返回結果給Javascript,你必須通過回調或者觸發事件來進行。

傳參并回調

RCT_EXPORT_METHOD(testCallbackEvent:(NSDictionary *)dictionary callback:(RCTResponseSenderBlock)callback)
{ NSLog(@"當前名字為:%@",dictionary); NSArray *events=@[@"callback ", @"test ", @" array"];
  callback(@[[NSNull null],events]);
}
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

說明:第一個參數代表從JavaScript傳過來的數據,第二個參數是回調方法; 
JS層代碼:

import {
  NativeModules,
  NativeAppEventEmitter
} from 'react-native'; var CalendarManager = NativeModules.wjyTestManager; class ReactNativeProject extends Component { render() { return (
          <TouchableHighlight onPress={()=>{CalendarManager.testCallbackEvent(
             {'name':'good','description':'http://www.lcode.org'},
             (error,events)=>{ if(error){
                   console.error(error);
                 }else{
                   this.setState({events:events});
                 }
           })}}
         >
          <Text style={styles.text}
      >點擊 </Text>
          </TouchableHighlight>

        );
      }
}
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

參數類型說明

RCT_EXPORT_METHOD 支持所有標準JSON類型,包括:

  • string (NSString)
  • number (NSInteger, float, double, CGFloat, NSNumber)
  • boolean (BOOL, NSNumber)
  • array (NSArray) 包含本列表中任意類型
  • object (NSDictionary) 包含string類型的鍵和本列表中任意類型的值
  • function (RCTResponseSenderBlock)

除此以外,任何RCTConvert類支持的的類型也都可以使用(參見RCTConvert了解更多信息)。RCTConvert還提供了一系列輔助函數,用來接收一個JSON值并轉換到原生Objective-C類型或類。例如:

#import "RCTConvert.h" #import "RCTBridge.h" #import "RCTEventDispatcher.h" //  對外提供調用方法,為了演示事件傳入屬性字段 RCT_EXPORT_METHOD(testDictionaryEvent:(NSString *)name details:(NSDictionary *) dictionary)
{ NSString *location = [RCTConvert NSString:dictionary[@"thing"]]; NSDate *time = [RCTConvert NSDate:dictionary[@"time"]]; NSString *description=[RCTConvert NSString:dictionary[@"description"]]; NSString *info = [NSString stringWithFormat:@"Test: %@\nFor: %@\nTestTime: %@\nDescription: %@",name,location,time,description]; NSLog(@"%@", info);
}
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

iOS原生訪問React Native

如果需要從iOS原生方法發送數據到JavaScript中,那么使用eventDispatcher。例如:

#import "RCTBridge.h" #import "RCTEventDispatcher.h" @implementation CalendarManager @synthesize bridge = _bridge; //  進行設置發送事件通知給JavaScript端 - (void)calendarEventReminderReceived:(NSNotification *)notification
{ NSString *name = [notification userInfo][@"name"];
    [self.bridge.eventDispatcher sendAppEventWithName:@"EventReminder" body:@{@"name": name}];
} @end
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在JavaScript中可以這樣訂閱事件,通常需要在componentWillUnmount函數中取消事件的訂閱。

import { NativeAppEventEmitter } from 'react-native';

var subscription = NativeAppEventEmitter.addListener( 'EventReminder',
  (reminder) => console.log(reminder.name)
); ... // 千萬不要忘記忘記取消訂閱, 通常在componentWillUnmount函數中實現。
subscription.remove();
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

用NativeAppEventEmitter.addListener中注冊一個通知,之后再OC中通過bridge.eventDispatcher sendAppEventWithName發送一個通知,這樣就形成了調用關系。

藍藍設計m.skdbbs.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務

前端工程師必備實用網站

高勁

素材類網站


千庫網,一個免費下載圖片素材的網站:http://588ku.com/ 
千庫網.jpg.png


Unsplash是一個分享免費高質量照片的網站,照片分辨率都挺大,而且都是真實的攝影師作品,圖片多是風景和靜物:https://unsplash.com/ 

Unsplash.jpg.pngUnsplash2.jpg.png

插件類網站

jq22,分享jQuery插件和提供各種jQuery的詳細使用方法,在線預覽,jQuery插件下載及教程http://www.jq22.com/

jq22.jpg.png


http://www.htmleaf.com/ 這個網站與上一個網站類似,也提供了大量的jQuery插件。

                htmleaf.jpg.png

layui,這是一個強大的模塊化前端框架http://www.layui.com/

             layui1.jpg.png

layui2.jpg.png

H-ui,端框架,一個輕量級前端框架,簡單免費,兼容性好,服務中國網站:http://www.h-ui.net/index.shtml

H-ui.jpg.png 

字體類網站

有字庫,一個免下載字體,直接在線引用字體的網站http://www.youziku.com/onlinefont/index

有字庫.jpg.png



PS字體庫,包含了幾乎所有類型的字體,下載好安裝,PS中就可以使用了:http://www.psjia.com/pssc/fontxz/list_18_3.html


               PS字體庫.png

圖標類網站

iconfont,這是阿里巴巴旗下的圖標庫網站,直接搜索關鍵詞就可以找到大批的圖標。下載圖標的時候我們還可以選擇顏色、大小、格式,根據自己的需要下載就好了:http://www.iconfont.cn/plus

                   iconfont.jpg.png

easyicon,這也是一個非常有名的圖標庫,與上面那個不同的是,這里的圖標不是單一顏色的,而是設計好的顏色。下載圖標也很簡單,直接點擊對應圖標上面的格式就可以下載:http://www.easyicon.net/iconsearch/ios/

                  easyicon.jpg.png

奧森圖標(Font Awesome),提供豐富的矢量字體圖標—通過CSS可以任意控制所有圖標的大小 ,顏色,陰影:http://www.thinkcmf.com/font/search.html

                奧森圖標.jpg.png

                 奧森圖標1.jpg.png

配色類網站

http://colorhunt.co,這個網站給我們提供了很多的配色方案,我們直接使用就OK了。

使用方法也很簡單,鼠標移動到對應的顏色上,我們就可以看到顏色的十六進制碼,復制這個顏色到工具里就可以使用了。

                colorhunt.jpg.png

https://webgradients.com/180種漸變方案供你選擇,還可以直接復制CSS樣式應用到網頁中。

              webgradients.jpg.png

adobe,這個是Adobe公司出的,他提供了多種配色方案。我們點擊圓盤中間的點,就可以調整出我們想要的配色方案:https://color.adobe.com/zh/create/color-wheel

                Adobe.jpg.png

http://www.colorhunter.com/這是一個提取現有圖片配色方案的工具。我們上傳一張圖片,它就會幫我們把圖片的配色提取出來供我們使用。

                colorhunt.jpg.png

bootcss,這個網站是為WEB設計,開發中經常用到的安全色。網站內列出了顏色的十六進制碼和RGB碼,復制粘貼就可以了:http://www.bootcss.com/p/websafecolors/

               bootcss..jpg.png

sioe,這是一個在線RGB和十六進制顏色碼轉換工具。在對應的位置填入十六進制代碼,點擊轉換,我們就可以獲取到RGB顏色的代碼了http://www.sioe.cn/yingyong/yanse-rgb-16/

              sioe.jpg.png




js學習中的總結——幾種繼承模式

seo達人

如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

     js中構造函數的幾種繼承模式淺析

一、原型鏈模式繼承

    利用原型讓一個引用類型繼承另一個引用類型的屬性和方法 。

    用的最多。

    缺點:不可傳參,不可多繼承。


        
  1. function People(name, age) {//添加公有屬性
  2. name = name || 'xiaolan';
  3. age = age || 18;
  4. this.name = name;
  5. this.age = age;
  6. }//創建一個名為People的類
  7. People.prototype.eat = function() {//添加私有屬性
  8. console.log(this.name + '賊能吃');
  9. }
  10. function Cat(color) {//創建一個名為Cat的類
  11. this.color = color;
  12. }
  13. Cat.prototype = new People('小叮當', 200);//實例化一個People類,并賦值給Cat類的原型鏈
  14. var cat = new Cat('藍白色')
  15. console.log(cat.name)//'小叮當'
  16. cat.eat();//'小叮當賊能吃'

二、混合模式繼承

    用call的方法只能繼承私有屬性,所以再加一遍一遍原型鏈模式繼承,原型鏈模式繼承又把私有屬性和公有屬性都繼承了一遍。


        
  1. function People(name, age) { //創建一個父級People類
  2. name = name || 'xiaolan';
  3. age = age || 18;
  4. this.name = name;
  5. this.age = age;
  6. }
  7. People.prototype.eat = function() {
  8. console.log(this.name + '賊能吃');
  9. }
  10. function Cat(color, name, age) {
  11. this.color = color;
  12. People.call(this, name, age); //通過call的形式繼承
  13. //通過call(this),將People的指向改為Cat的實例
  14. }
  15. var cat = new Cat('藍白色', '小叮當', 1);
  16. console.log(cat.name);//'小叮當'
  17. cat.eat();//報錯,
  18. //繼承不了公有屬性,所以cat.eat()會報錯;

為了繼承公有屬性,用原型鏈模式在把公有屬性和方法繼承過來,


        
  1. function People(name, age) { //創建一個父級People類
  2. name = name || 'xiaolan';
  3. age = age || 18;
  4. this.name = name;
  5. this.age = age;
  6. }
  7. People.prototype.eat = function() {
  8. console.log(this.name + '賊能吃');
  9. }
  10. function Cat(color, name, age) {
  11. this.color = color;
  12. People.call(this, name, age); //通過call的形式繼承
  13. //通過call(this),將People的指向改為Cat的實例
  14. }
  15. Cat.prototype = new People()
  16. var cat = new Cat('藍白色', '小叮當', 200)
  17. console.log(cat)
  18. console.log(cat.name); //'小叮當',在原型鏈繼承的時候,就近原則,cat.name 先找到'小叮當',就不往下找了
  19. cat.eat(); //'小叮當賊能吃'

三、拷貝繼承

    優點:可以多繼承,可傳參;

    缺點:浪費資源,不能判斷父級;


        
  1. function People(name, age) { //創建一個父級People類
  2. name = name || 'xiaolan';
  3. age = age || 18;
  4. this.name = name;
  5. this.age = age;
  6. }
  7. People.prototype.eat = function() {
  8. console.log(this.name + '賊能吃');
  9. }
  10. function Cat(color, name, age) {
  11. this.color = color;
  12. var people = new People(name, age) //實例化一個People類
  13. for (let i in people) {
  14. this[i] = people[i]; //將people中的可枚舉屬性和方法遍歷并附給Cat類,公有屬性和私有屬性都是可枚舉屬性;
  15. }
  16. }
  17. var cat = new Cat('藍白色', '小叮當', 2);
  18. console.log(cat.name); //小叮當
  19. cat.eat(); //小叮當賊能吃

四、寄生組合方式繼承

    優點:私有屬性和公有屬性都單獨繼承,可以傳參;

    私有屬性可以多繼承,公有屬性不可多繼承;


        
  1. function People(name, age) {
  2. name = name || 'xiaolan';
  3. age = age || 18;
  4. this.name = name;
  5. this.age = age;
  6. }
  7. People.prototype.eat = function() {
  8. console.log(this.name + '賊能吃');
  9. }
  10. function Cat(color, name, age) {
  11. this.color = color;
  12. People.call(this, name, age) //用call的形式把私有屬性繼承過來
  13. }
  14. function Fn() {} //創建一個中間構造函數,用來接收People的公有屬性,為了防止創建實例Cat實例是影響原來的people構造函數
  15. Fn.prototype = People.prototype;
  16. Cat.prototype = new Fn(); //將中間構造函數Fn繼承people的公有屬性傳給Cat的原型鏈
  17. Cat.prototype.constructor = Cat; //由于上一步重置了Cat原型鏈的constructor屬性,所以要重新給賦回來;
  18. var cat = new Cat('藍白色', '小叮當', 3);
  19. console.log(cat.name); //'小叮當'
  20. cat.eat() //'小叮當賊能吃


注:若有不嚴謹與錯誤的地方,請多指教!






  1. 這里寫圖片描述



藍藍設計m.skdbbs.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務


vue在ie9中的兼容問題

seo達人

如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

問題總結  https://github.com/vuejs-templates/webpack/issues/260

  1. 首先npm install --save babel-polyfill

  2. 然后在main.js中的最前面引入babel-polyfill

    import 'babel-polyfill'

  3. 在index.html 加入以下代碼(非必須)

    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">

  4. 在config中的webpack.base.conf.js中,修改編譯配置


    
  1. entry:{
  2. app:['babel-polyfill','./src/main.js']
  3. }

當然,如果你只用到了 axios 對 promise進行兼容,可以只用 es6-promise

npm install es6-promise --save

在 main.js 中的最前面 引入

import 'es6-promise/auto' 
  • 以上配置,ie9兼容就完成了

那么,就有一個問題了,build之后的dist文件只有放在服務器上才能查看,但本地如何查看呢,參考一下配置

  1. 修改config文件夾中的index.js文件,將build對象中的打包路徑,'/‘改為'./',由絕對路徑改為相對路徑,建議將sourceMap改為false,編譯的時候會快一點

    build: { assetsPublicPath: './', productionSourceMap: false, },

  2. 修改完之后,重新 npm run build ,得到新的dist文件夾

  3. 然后進入dist文件夾

    cd dist

  4. 全局安裝簡易node服務器

    npm install http-server -g

  5. 啟動簡易node服務器

    http-server

  6. 出現如下圖所示,就代表你的服務器啟動成功了,那你也能在5000端口查看編譯打包后的項目了,可以在ie瀏覽器中直接測試了

    這里寫圖片描述

  7. IE在處理日期的時候,不支持-支持/的日期方式 如 2017-01-01應該 


藍藍設計m.skdbbs.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務


ES6新特性Promise異步調用

seo達人

如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

Promise 的含義

Promise 是異步編程的一種解決方案,比傳統的解決方案–回調函數和事件--更合理和更強大。它由社區最早提出和實現,ES6將其寫進了語言標準,統一了語法,原生提供了Promise

所謂Promise ,簡單說就是一個容器,里面保存著某個未來才回結束的事件(通常是一個異步操作)的結果。從語法上說,Promise是一個對象,從它可以獲取異步操作的消息。 
Promise 對象的狀態不受外界影響

三種狀態:

  • pending:進行中
  • fulfilled :已經成功
  • rejected 已經失敗

狀態改變: 
Promise對象的狀態改變,只有兩種可能:

  • 從pending變為fulfilled
  • 從pending變為rejected。

這兩種情況只要發生,狀態就凝固了,不會再變了,這時就稱為resolved(已定型

基本用法

ES6規定,Promise對象是一個構造函數,用來生成Promise實例


    
  1. const promist = new Promise(function(resolve,reject){
  2. if(/*異步操作成功*/){
  3. resolve(value);
  4. }else{
  5. reject(error);
  6. }
  7. })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

resolve函數的作用是,將Promise對象的狀態從“未完成”變為“成功”(即從 pending 變為 resolved),在異步操作成功時調用,并將異步操作的結果,作為參數傳遞出去; 
reject函數的作用是,將Promise對象的狀態從“未完成”變為“失敗”(即從 pending 變為 rejected),在異步操作失敗時調用,并將異步操作報出的錯誤,作為參數傳遞出去。

Promise的源碼分析:

1.回調地獄

曾幾何時,我們的代碼是這樣的,為了拿到回調的結果,不得不callback hell,這種環環相扣的代碼可以說是相當惡心了


            
  1. let fs = require('fs')
  2. fs.readFile('./a.txt','utf8',function(err,data){
  3. fs.readFile(data,'utf8',function(err,data){
  4. fs.readFile(data,'utf8',function(err,data){
  5. console.log(data)
  6. })
  7. })
  8. })

終于,我們的蓋世英雄出現了,他身披金甲圣衣、駕著七彩祥云。好吧打岔兒了,沒錯他就是我們的Promise,那讓我們來看看用了Promise之后,上面的代碼會變成什么樣吧


            
  1. let fs = require('fs')
  2. function read(url){
  3. return new Promise((resolve,reject)=>{
  4. fs.readFile(url,'utf8',function(error,data){
  5. error && reject(error)
  6. resolve(data)
  7. })
  8. })
  9. }
  10. read('./a.txt').then(data=>{
  11. return read(data)
  12. }).then(data=>{
  13. return read(data)
  14. }).then(data=>{
  15. console.log(data)
  16. })

2.重點開始,小眼睛都看過來

2.1 Promise/A+

首先我們要知道自己手寫一個Promise,應該怎么去寫,誰來告訴我們怎么寫,需要遵循什么樣的規則。當然這些你都不用擔心,其實業界都是通過一個規則指標來生產Promise的。讓我們來看看是什么東西。傳送門?Promise/A+

2.2 constructor

我們先聲明一個類,叫做Promise,里面是構造函數。如果es6還有問題的可以去阮大大的博客上學習一下(傳送門?es6


            
  1. class Promise{
  2. constructor(executor){
  3. //控制狀態,使用了一次之后,接下來的都不被使用
  4. this.status = 'pendding'
  5. this.value = undefined
  6. this.reason = undefined
  7. //定義resolve函數
  8. let resolve = (data)=>{
  9. //這里pendding,主要是為了防止executor中調用了兩次resovle或reject方法,而我們只調用一次
  10. if(this.status==='pendding'){
  11. this.status = 'resolve'
  12. this.value = data
  13. }
  14. }
  15. //定義reject函數
  16. let reject = (data)=>{
  17. if(this.status==='pendding'){
  18. this.status = 'reject'
  19. this.reason = data
  20. }
  21. }
  22. //executor方法可能會拋出異常,需要捕獲
  23. try{
  24. //將resolve和reject函數給使用者
  25. executor(resolve,reject)
  26. }catch(e){
  27. //如果在函數中拋出異常則將它注入reject中
  28. reject(e)
  29. }
  30. }
  31. }

那么接下來我會分析上面代碼的作用,原理

  • executor:這是實例Promise對象時在構造器中傳入的參數,一般是一個function(resolve,reject){}
  • status:``Promise的狀態,一開始是默認的pendding狀態,每當調用道resolve和reject方法時,就會改變其值,在后面的then方法中會用到
  • value:resolve回調成功后,調用resolve方法里面的參數值
  • reason:reject回調成功后,調用reject方法里面的參數值
  • resolve:聲明resolve方法在構造器內,通過傳入的executor方法傳入其中,用以給使用者回調
  • reject:聲明reject方法在構造器內,通過傳入的executor方法傳入其中,用以給使用者回調

2.3 then

then方法是Promise中最為重要的方法,他的用法大家都應該已經知道,就是將Promise中的resolve或者reject的結果拿到,那么我們就能知道這里的then方法需要兩個參數,成功回調和失敗回調,上代碼!


            
  1. then(onFufilled,onRejected){
  2. if(this.status === 'resolve'){
  3. onFufilled(this.value)
  4. }
  5. if(this.status === 'reject'){
  6. onRejected(this.reason)
  7. }
  8. }

這里主要做了將構造器中resolve和reject的結果傳入onFufilledonRejected中,注意這兩個是使用者傳入的參數,是個方法。所以你以為這么簡單就完了?要想更Swag的應對各種場景,我們必須得再完善。繼續往下走!

3.異步的Promise

之前我們只是處理了同步情況下的Promise,簡而言之所有操作都沒有異步的成分在內。那么如果是異步該怎么辦?

3.1 callback!?。?!

最早處理異步的方法就是callback,就相當于我讓你幫我掃地,我會在給你發起任務時給你一個手機,之后我做自己的事情去,不用等你,等你掃完地就會打手機給我,誒,我就知道了地掃完了。這個手機就是callback,回調函數。

首先我們需要改一下構造器里的代碼,分別添加兩個回調函數的數組,分別對應成功回調和失敗回調。他們的作用是當成功執行resolve或reject時,執行callback。


            
  1. //存放成功回調的函數
  2. this.onResolvedCallbacks = []
  3. //存放失敗回調的函數
  4. this.onRejectedCallbacks = []
  5. let resolve = (data)=>{
  6. if(this.status==='pendding'){
  7. this.status = 'resolve'
  8. this.value = data
  9. //監聽回調函數
  10. this.onResolvedCallbacks.forEach(fn=>fn())
  11. }
  12. }
  13. let reject = (data)=>{
  14. if(this.status==='pendding'){
  15. this.status = 'reject'
  16. this.reason = data
  17. this.onRejectedCallbacks.forEach(fn=>fn())
  18. }
  19. }

然后是then需要多加一個狀態判斷,當Promise中是異步操作時,需要在我們之前定義的回調函數數組中添加一個回調函數。


            
  1. if(this.status === 'pendding'){
  2. this.onResolvedCallbacks.push(()=>{
  3. // to do....
  4. let x = onFufilled(this.value)
  5. resolvePromise(promise2,x,resolve,reject)
  6. })
  7. this.onRejectedCallbacks.push(()=>{
  8. let x = onRejected(this.reason)
  9. resolvePromise(promise2,x,resolve,reject)
  10. })
  11. }

ok!大功告成,異步已經解決了

3.2 resolvePromise

這也是Promise中的重頭戲,我來介紹一下,我們在用Promise的時候可能會發現,當then函數中return了一個值,我們可以繼續then下去,不過是什么值,都能在下一個then中獲取,還有,當我們不在then中放入參數,例:promise.then().then(),那么其后面的then依舊可以得到之前then返回的值,可能你現在想很迷惑。讓我來解開你心中的憂愁,follow me


            
  1. then(onFufilled,onRejected){
  2. //解決onFufilled,onRejected沒有傳值的問題
  3. onFufilled = typeof onFufilled === 'function'?onFufilled:y=>y
  4. //因為錯誤的值要讓后面訪問到,所以這里也要跑出個錯誤,不然會在之后then的resolve中捕獲
  5. onRejected = typeof onRejected === 'function'?onRejected:err=>{ throw err ;}
  6. //聲明一個promise對象
  7. let promise2
  8. if(this.status === 'resolve'){
  9. //因為在.then之后又是一個promise對象,所以這里肯定要返回一個promise對象
  10. promise2 = new Promise((resolve,reject)=>{
  11. setTimeout(()=>{
  12. //因為穿透值的緣故,在默認的跑出一個error后,不能再用下一個的reject來接受,只能通過try,catch
  13. try{
  14. //因為有的時候需要判斷then中的方法是否返回一個promise對象,所以需要判斷
  15. //如果返回值為promise對象,則需要取出結果當作promise2的resolve結果
  16. //如果不是,直接作為promise2的resolve結果
  17. let x = onFufilled(this.value)
  18. //抽離出一個公共方法來判斷他們是否為promise對象
  19. resolvePromise(promise2,x,resolve,reject)
  20. }catch(e){
  21. reject(e)
  22. }
  23. },0)
  24. })
  25. }
  26. if(this.status === 'reject'){
  27. promise2 = new Promise((resolve,reject)=>{
  28. setTimeout(()=>{
  29. try{
  30. let x = onRejected(this.reason)
  31. resolvePromise(promise2,x,resolve,reject)
  32. }catch(e){
  33. reject(e)
  34. }
  35. },0)
  36. })
  37. }
  38. if(this.status === 'pendding'){
  39. promise2 = new Promise((resolve,reject)=>{
  40. this.onResolvedCallbacks.push(()=>{
  41. // to do....
  42. setTimeout(()=>{
  43. try{
  44. let x = onFufilled(this.value)
  45. resolvePromise(promise2,x,resolve,reject)
  46. }catch(e){
  47. reject(e)
  48. }
  49. },0)
  50. })
  51. this.onRejectedCallbacks.push(()=>{
  52. setTimeout(()=>{
  53. try{
  54. let x = onRejected(this.reason)
  55. resolvePromise(promise2,x,resolve,reject)
  56. }catch(e){
  57. reject(e)
  58. }
  59. })
  60. })
  61. })
  62. }
  63. return promise2
  64. }

一下子多了很多方法,不用怕,我會一一解釋

  1. 返回Promise?:首先我們要注意的一點是,then有返回值,then了之后還能在then,那就說明之前的then返回的必然是個Promise。
  2. 為什么外面要包一層setTimeout?:因為Promise本身是一個異步方法,屬于微任務一列,必須得在執行棧執行完了在去取他的值,所以所有的返回值都得包一層異步setTimeout。
  3. 為什么開頭有兩個判斷?:這就是之前想要解決的如果then函數中的參數不是函數,那么我們需要做處理。如果onFufilled不是函數,就需要自定義個函數用來返回之前resolve的值,如果onRejected不是函數,自定義個函數拋出異常。這里會有個小坑,如果這里不拋出異常,會在下一個then的onFufilled中拿到值。又因為這里拋出了異常所以所有的onFufilled或者onRejected都需要try/catch,這也是Promise/A+的規范。當然本人覺得成功的回調不需要拋出異常也可以,大家可以仔細想想。
  4. resolvePromise是什么?:這其實是官方Promise/A+的需求。因為你的then可以返回任何職,當然包括Promise對象,而如果是Promise對象,我們就需要將他拆解,直到它不是一個Promise對象,取其中的值。

那就讓我們來看看這個resolvePromise到底長啥樣。


            
  1. function resolvePromise(promise2,x,resolve,reject){
  2. //判斷x和promise2之間的關系
  3. //因為promise2是上一個promise.then后的返回結果,所以如果相同,會導致下面的.then會是同一個promise2,一直都是,沒有盡頭
  4. if(x === promise2){//相當于promise.then之后return了自己,因為then會等待return后的promise,導致自己等待自己,一直處于等待
  5. return reject(new TypeError('循環引用'))
  6. }
  7. //如果x不是null,是對象或者方法
  8. if(x !== null && (typeof x === 'object' || typeof x === 'function')){
  9. //為了判斷resolve過的就不用再reject了,(比如有reject和resolve的時候)
  10. let called
  11. try{//防止then出現異常,Object.defineProperty
  12. let then = x.then//取x的then方法可能會取到{then:{}},并沒有執行
  13. if(typeof then === 'function'){
  14. //我們就認為他是promise,call他,因為then方法中的this來自自己的promise對象
  15. then.call(x,y=>{//第一個參數是將x這個promise方法作為this指向,后兩個參數分別為成功失敗回調
  16. if(called) return;
  17. called = true
  18. //因為可能promise中還有promise,所以需要遞歸
  19. resolvePromise(promise2,y,resolve,reject)
  20. },err=>{
  21. if(called) return;
  22. called = true
  23. //一次錯誤就直接返回
  24. reject(err)
  25. })
  26. }else{
  27. //如果是個普通對象就直接返回resolve作為結果
  28. resolve(x)
  29. }
  30. }catch(e){
  31. if(called) return;
  32. called = true
  33. reject(e)
  34. }
  35. }else{
  36. //這里返回的是非函數,非對象的值,就直接放在promise2的resolve中作為結果
  37. resolve(x)
  38. }
  39. }

它的作用是用來將onFufilled的返回值進行判斷取值處理,把最后獲得的值放入最外面那層的Promise的resolve函數中。

  1. 參數promise2(then函數返回的Promise對象),x(onFufilled函數的返回值),resolve、reject(最外層的Promise上的resolve和reject)。
  2. 為什么要在一開始判斷promise2x?:首先在Promise/A+中寫了需要判斷這兩者如果相等,需要拋出異常,我就來解釋一下為什么,如果這兩者相等,我們可以看下下面的例子,第一次p2是p1.then出來的結果是個Promise對象,這個Promise對象在被創建的時候調用了resolvePromise(promise2,x,resolve,reject)函數,又因為x等于其本身,是個Promise,就需要then方法遞歸它,直到他不是Promise對象,但是x(p2)的結果還在等待,他卻想執行自己的then方法,就會導致等待。

            
  1. let p1 = new Promise((resolve,reject)=>{
  2. resolve()
  3. })
  4. let p2 = p1.then(d=>{
  5. return p2
  6. })
  1. called是用來干嘛的?:called變量主要是用來判斷如果resolvePromise函數已經resolve或者reject了,那就不需要在執行下面的resolce或者reject。
  2. 為什么取then這個屬性?:因為我們需要去判斷x是否為Promise,then屬性如果為普通值,就直接resolve掉,如果是個function,就是Promise對象,之后我們就需要將這個x的then方法進行執行,用call的原因是因為then方法里面this指向的問題。
  3. 為什么要遞歸去調用resolvePromise函數?:相信細心的人已經發現了,我這里使用了遞歸調用法,首先這是Promise/A+中要求的,其次是業務場景的需求,當我們碰到那種Promise的resolve里的Promise的resolve里又包了一個Promise的話,就需要遞歸取值,直到x不是Promise對象。

4.完善Promise

我們現在已經基本完成了Promise的then方法,那么現在我們需要看看他的其他方法。

4.1 catch

相信大家都知道catch這個方法是用來捕獲Promise中的reject的值,也就是相當于then方法中的onRejected回調函數,那么問題就解決了。我們來看代碼。


            
  1. //catch方法
  2. catch(onRejected){
  3. return this.then(null,onRejected)
  4. }

該方法是掛在Promise原型上的方法。當我們調用catch傳callback的時候,就相當于是調用了then方法。

4.2 resolve/reject

大家一定都看到過Promise.resolve()、Promise.reject()這兩種用法,它們的作用其實就是返回一個Promise對象,我們來實現一下。


            
  1. //resolve方法
  2. Promise.resolve = function(val){
  3. return new Promise((resolve,reject)=>{
  4. resolve(val)
  5. })
  6. }
  7. //reject方法
  8. Promise.reject = function(val){
  9. return new Promise((resolve,reject)=>{
  10. reject(val)
  11. })
  12. }

這兩個方法是直接可以通過class調用的,原理就是返回一個內部是resolve或reject的Promise對象。

4.3 all

all方法可以說是Promise中很常用的方法了,它的作用就是將一個數組的Promise對象放在其中,當全部resolve的時候就會執行then方法,當有一個reject的時候就會執行catch,并且他們的結果也是按著數組中的順序來排放的,那么我們來實現一下。


            
  1. //all方法(獲取所有的promise,都執行then,把結果放到數組,一起返回)
  2. Promise.all = function(promises){
  3. let arr = []
  4. let i = 0
  5. function processData(index,data){
  6. arr[index] = data
  7. i++
  8. if(i == promises.length){
  9. resolve(arr)
  10. }
  11. }
  12. return new Promise((resolve,reject)=>{
  13. for(let i=0;i<promises.length;i++){
  14. promises[i].then(data=>{
  15. processData(i,data)
  16. },reject)
  17. }
  18. })
  19. }

其原理就是將參數中的數組取出遍歷,每當執行成功都會執行processData方法,processData方法就是用來記錄每個Promise的值和它對應的下標,當執行的次數等于數組長度時就會執行resolve,把arr的值給then。這里會有一個坑,如果你是通過arr數組的長度來判斷他是否應該resolve的話就會出錯,為什么呢?因為js數組的特性,導致如果先出來的是1位置上的值進arr,那么0位置上也會多一個空的值,所以不合理。

4.4 race

race方法雖然不常用,但是在Promise方法中也是一個能用得上的方法,它的作用是將一個Promise數組放入race中,哪個先執行完,race就直接執行完,并從then中取值。我們來實現一下吧。


            
  1. //race方法
  2. Promise.race = function(promises){
  3. return new Promise((resolve,reject)=>{
  4. for(let i=0;i<promises.length;i++){
  5. promises[i].then(resolve,reject)
  6. }
  7. })
  8. }

原理大家應該看懂了,很簡單,就是遍歷數組執行Promise,如果有一個Promise執行成功就resolve。

Promise語法糖 deferred

語法糖這三個字大家一定很熟悉,作為一個很Swag的前端工程師,對async/await這對兄弟肯定很熟悉,沒錯他們就是generator的語法糖。而我們這里要講的語法糖是Promise的。


            
  1. //promise語法糖 也用來測試
  2. Promise.deferred = Promise.defer = function(){
  3. let dfd = {}
  4. dfd.promise = new Promise((resolve,reject)=>{
  5. dfd.resolve = resolve
  6. dfd.reject = reject
  7. })
  8. return dfd
  9. }

什么作用呢?看下面代碼你就知道了


            
  1. let fs = require('fs')
  2. let Promise = require('./promises')
  3. //Promise上的語法糖,為了防止嵌套,方便調用
  4. //壞處 錯誤處理不方便
  5. function read(){
  6. let defer = Promise.defer()
  7. fs.readFile('./1.txt','utf8',(err,data)=>{
  8. if(err)defer.reject(err)
  9. defer.resolve(data)
  10. })
  11. return defer.Promise
  12. }

沒錯,我們可以方便的去調用他語法糖defer中的Promise對象。那么它還有沒有另外的方法呢?答案是有的。我們需要在全局上安裝promises-aplus-tests插件npm i promises-aplus-tests -g,再輸入promises-aplus-tests [js文件名] 即可驗證你的Promise的規范。


藍藍設計m.skdbbs.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務


么去控制瀏覽器對資源文件的處理行為

seo達人

如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

通常當用戶打開一個資源的url,如果瀏覽器支持這個格式的文件的情況下,瀏覽器會嘗試去再頁面里展示它而不是直接下載。例如一張圖片(jpg, png, gif等),幾乎所有瀏覽器都會去將圖片在瀏覽器里面展示。


對于壓縮格式的文件(zip, tar, gzip等)瀏覽器總是會直接去下載它們,另外一些格式的文件,根據瀏覽器的不同也會有差異的處理方法,例如Microsoft Word文件(doc, docx)在ie瀏覽器下通常會在瀏覽器中展示,但是其他瀏覽器幾乎都會直接下載它,同樣的對于PDF文件chrome有自己的pdf 轉換器它會嘗試去在瀏覽器上展示該文件。

強制下載文件

對于瀏覽器這種行為,一般情況下是可以接受的,因為用戶可以在瀏覽器顯示文件后將文件保存到電腦中,但是一些情況下用戶可能希望文件直接被下載而不是在瀏覽器中被打開,比如有時候用戶想去下載一個歌曲,但是瀏覽器可能回去播放該音頻。那么怎么讓瀏覽器強制去下載文件要怎么做呢

a標簽的download屬性

html5中 a 標簽新增了 download 屬性,該屬性指示瀏覽器下載url的內容而不是導航到url,因此如果配置了此屬性用戶會直接下載url的內容。作為開發如果想直接觸發該事件我們可以直接用代碼模擬a標簽和點擊事件


    
  1. const link = document.createElement('a');
  2. link.addEventListener('click', function() {
  3. link.download = xxx;
  4. link.href = xxx;
  5. });
  6. const e = document.createEvent('MouseEvents');
  7. e.initEvent('click', false, false);
  8. link.dispatchEvent(e);
  • download屬性只在同域時候有效,當跨域請求時候該屬性將會被忽略。
  • 當前并非所以瀏覽器都支持該屬性,需要瀏覽器考慮兼容性。

改變資源格式

瀏覽器會根據資源類型去判斷是否支持,如果支持時會嘗試去在頁面上展示該資源。瀏覽器判斷資源類型是根據返回頭Content-Type的值,因此一方面我們在服務端可以設置返回頭字段為文件流'Content-Type': 'application/octet-stream',或者根據一些具體資源直接壓縮后傳輸,瀏覽器不能分析zip之類的壓縮文件所以會直接去下載它們。

配置Content-Disposition

在HTTP場景中,Content-Disposition 消息頭指示回復的內容該以何種形式展示,是以內聯的形式(即網頁或者頁面的一部分),還是以附件的形式下載并保存到本地。

  • inline 默認參數表示消息體會以頁面的一部分或者整個頁面的形式展示。
  • attachment 消息體應該被下載到本地,將參數filename的值預填為下載后的文件名

因此當我們希望該資源被直接下載時候,我們可以設置返回頭Content-Disposition的值為attachment。


    
  1. //example
  2. Content-Disposition: attachment; filename="fname.ext"

這里設置名稱時候,要注意下filename的編碼格式。

用戶自己在瀏覽器設置

瀏覽器既然定義了該行為,根據瀏覽器的不同用戶可能在設置頁面去配置某些格式的文件是否希望瀏覽器去展示該文件。一些有爭議的情況下,你也可以提示用戶自己根據需求去設置這些參數。


藍藍設計m.skdbbs.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 平面設計服務


日歷

鏈接

個人資料

藍藍設計的小編 http://m.skdbbs.com

存檔

92国产精品视频_亚洲a级在线观看_国产精品电影观看_国产精品免费观看在线_精品伊人久久97_亚洲人成在线观_尤物九九久久国产精品的特点_成人激情在线播放_成人黄色大片在线免费观看_亚洲成人精品久久久_久久免费视频在线观看_久久精品国产一区_国产一区二区三区18_亚洲欧美中文字幕在线一区_日韩美女中文字幕_日韩视频免费在线
精品一区二区在线视频| 日韩欧乱色一区二区三区在线| 久久九九久久九九| av在线一区二区三区| 色欧美乱欧美15图片| 久久国产精品免费一区二区三区| 激情综合色播五月| 欧美日韩亚洲视频| 成人av影视在线| 日韩精品免费专区| 欧美在线一二三区| 天堂va蜜桃一区二区三区漫画版| 国产精品一区二区在线播放| 91理论片午午论夜理片久久| 成人免费看片39| 国产精品视频免费| 97久久超碰| 91综合网人人| 毛片在线网站| 精品欧美一区二区在线观看视频| 久久精品国产一区| 日本欧美一二三区| 国产精品一区二区免费看| av色综合久久天堂av色综合在| 久久伦理中文字幕| 一二三区精品福利视频| 在线高清欧美| av在线电影观看| 欧美孕妇与黑人孕交| 免费观看成人www动漫视频| 狠狠做六月爱婷婷综合aⅴ| 偷拍一区二区三区| 成人丝袜高跟foot| 国产美女精品视频免费播放软件| 日韩子在线观看| 亚洲自拍另类欧美丝袜| 国语自产精品视频在线看| 超碰一区二区三区| 97在线看免费观看视频在线观看| 夫妻av一区二区| 欧美日韩一区二区精品| 天天综合色天天综合色hd| 欧美bbbbb| 99久久综合| 日韩在线观看中文字幕| 亚洲综合一区二区| 激情视频极品美女日韩| 成人黄色在线播放| 欧美精品激情| 精品一卡二卡三卡四卡日本乱码| 在线精品亚洲欧美日韩国产| 在线播放国产一区二区三区| 免费的国产精品| 青草青在线视频| 高清av在线| 99re6热只有精品免费观看| 快she精品国产999| 欧美黑人视频一区| 久久人人97超碰人人澡爱香蕉| 婷婷久久综合| 黄网站app在线观看| 91丨porny丨蝌蚪视频| 欧美中文一区二区三区| 免费97视频在线精品国自产拍| 欧美午夜视频在线| 97久久精品人人做人人爽50路| 欧美三电影在线| 91精品国产成人www| 一区二区av在线| 亚洲大胆人体在线| 亚洲超丰满肉感bbw| 日韩亚洲一区二区| 免费欧美激情| 国产高清精品在线| 亚洲一区二区毛片| 夜夜嗨av一区二区三区网页| 亚洲精品合集| 极品美女一区| 欧美肥老妇视频| 第一社区sis001原创亚洲| 国产成人精品免费在线| 欧美成人精品高清在线播放| 色婷婷亚洲婷婷| 老司机免费视频一区二区三区| 91久久奴性调教| 欧美黄色三级网站| 久久久久久久久国产一区| 亚洲+小说+欧美+激情+另类| 99精品久久| 99精品视频免费| 中文字幕一区二区精品区| 亚洲色图清纯唯美| 国产精品婷婷午夜在线观看| 久久久国际精品| 亚洲国产天堂久久综合网| 欧美一区二区不卡视频| 亚洲999一在线观看www| 亚洲五码中文字幕| 影音先锋中文在线视频| 久久久久国产精品免费网站| 久久99伊人| 7777免费精品视频| 国产日韩1区| 偷偷要91色婷婷| 午夜伦理大片视频在线观看| 色777狠狠综合秋免鲁丝| 蜜臀av免费一区二区三区| 成人免费xxxxx在线观看| 亚洲国内高清视频| 精品国产青草久久久久福利| 亚洲精品一区二区三区福利| 欧美亚洲国产日韩| 国产伦精品一区二区三区四区免费| 日韩欧美中文字幕公布| 四虎国产精品免费久久| 欧美日韩国产综合视频在线| 亚洲欧美国产一区二区三区| 久久久久久久久久久黄色| 国产亚洲精品美女久久久久久久久久| 高清欧美性猛交xxxx黑人猛交| 国产欧美日韩影院| www.午夜精品| 性开放的欧美大片| 久久精品中文字幕| 一本大道久久a久久精品综合| 国产夫妻在线播放| 一区二区三区四区不卡在线| 中文字幕乱码久久午夜不卡| 日韩图片一区| 在线亚洲人成电影网站色www| 136国产福利精品导航网址| 亚洲综合色婷婷| 欧美日韩视频一区二区三区| 久久久久久久97| 午夜国产一区| 97精品久久久中文字幕免费| 欧美中文字幕| 国产极品精品在线观看| 国产精品4hu.www| 国产九九精品视频| 91麻豆精品| 免费h精品视频在线播放| 国产精品传媒| 色一区av在线| 黄色免费在线网站| 黄av在线播放| 亚洲欧美日韩国产综合精品二区| 精精国产xxxx视频在线| 成人免费在线观看| 蜜臀av国内免费精品久久久夜夜| 婷婷成人激情| 日韩亚洲国产欧美| 制服.丝袜.亚洲.另类.中文| 成人免费一区| 亚洲国产精品国自产拍av秋霞| 北条麻妃一区二区三区| 国产香蕉97碰碰久久人人| 成人动漫一区二区在线| 亚洲护士老师的毛茸茸最新章节| 久久久久亚洲精品中文字幕| 亚洲视频在线观看免费| 国产精品99一区二区三区| 亚洲免费观看在线视频| 午夜影院在线观看欧美|