首页

谈谈移动端布局

周周

移动端推广速度快,效果好,越来越多的企业,商家开始重视移动站的建设和移动页面(h5)的制作。随着移动页面的玩法越来越多,对前端技术的要求也会越来越高。

选择合适的布局,是写好移动页面的第一步。今天我们就来谈谈移动端的布局问题。
为什么移动端布局如此混乱?这是由多方的原因造成的。
1. css这套技术系统本身十分混乱,基本上可以说毫无规律可言,依赖于技术人员的熟练程度而不是逻辑更多一些;
2.css历经了多个时代的升级,每一次升级之后,新的技术标准和旧的基本上没有任何关联。比如:table布局,div+css布局,flex布局,grid布局等;
3. 手机终端市场的混乱。当前市场上手机的尺寸五花八门;加上由iphone的retina技术带来的dpr的混乱;

关于移动设备一些基本概念的理解。



一. 物理设备像素。
思考:为什么手电筒只能发出一种颜色的光,而我们的屏幕能发出这么多种颜色的光?
因为我们的屏幕是由无数个小的手电筒组成的,每个点可以发不同颜色的光,最后就组成了我们看到的彩色的效果。
每张图片都是由色点组成的,每个色点称为一个像素。一张图片由30万个色点组成,这个图片的像素就是30W。我们常说相机是多少像素,这个像素实际就是在说这款照相机的感器件有多少个,有100W个感光器件的相机就是100W像素的相机,有4000W个感光器件的相机就是4000W像素,以此类推。一台100W像素的相机拍摄的照片洗成5寸的照片会比洗成6寸清晰一点。
二. 屏幕分辨率
屏幕分辨率是屏幕每行的像素点数*每列的像素点数,每个屏幕有自己的分辨率。屏幕分辨率越高,所呈现的色彩越多,清晰度越高。
结论:
1. 像素的单位本质上是:个数,100像素你可以理解成你有100个手电筒;
2. 同样大小(比如1cm*1cm大小的矩形),里面的像素越多,画面越清晰;
三.css像素
在pc端1css像素相当于1物理设备像素。
思考:
我们的手机分辨率是640*1136(iphone 5和iphone 5s的物理设备分辨率),如果我们打开一个纯粹pc端的网站会出现什么情况?
(比如jumei.com,min-width是1090px,在pc端的我的电脑的设备宽度是1280,通过screen.width进行检测)
我们会发现网站会缩小到我们可以看到整个网站(www.jubi.com)
则会发现,有滚动条了,因为禁止缩放了
四. dpr
1个css像素占多少物理设备像素
思考:iphone 5或者iphone 5s一屏幕能看到的极限是多少宽度?
应该是320(这是默认的可视区的css宽度) * 2 = 640px
以上,我们学习完了所有关于移动端布局相关的概念,接下来,我们来聊一聊布局的思路。
假如我们有640px的设计稿,我们如何才能让用户全部看到呢?
思路一:百分比布局
把尺寸除以2,比如我们量出来的是640px ---> 实际上我们只写320px;
如果是iphone 6怎么办? iphone 6的宽度是375px;
由于320和375的宽度其实差别不大,我们可以不定宽度,也就是把整体宽度设定为100%,然后其他的全部量出来是多少。
布局方法
- 拿到设计师给我们的设计稿之后(推荐640px),把所有量出来的尺寸除以2即可
- 遇到等分就用百分比
- 左浮动 + 右浮动(导航部分实现、折扣推荐导航部分) --> 适合于所有的元素宽度固定的
- 左浮动 + padding挤(见超值折扣推荐内容部分) 本质上元素大小在任何尺寸下面都是一致,改变的其实是元素与元素之间的间距大小 --> 适合一个元素宽度固定,另一个宽度自适应;

网站示例

http://m.duba.com/

http://m.lagou.com/

百分比布局的缺点
在大屏幕的手机下显示效果会变成有些页面元素宽度被拉的很长,但是高度还是和原来一样,实际显示非常的不协调,这就是流式布局的最致命的缺点,往往只有几个尺寸的手机下看到的效果是令人满意的,其实很多视觉设计师应该无法接受这种效果,因为他们的设计图在大屏幕手机下看到的效果相当于是被横向拉长来一样。流式布局并不是最理想的实现方式,通过大量的百分比布局,会经常出现许多兼容性的问题,还有就是对设计有很多的限制,因为他们在设计之初就需要考虑流式布局对元素造成的影响,只能设计横向拉伸的元素布局,设计的时候存在很多局限性。
思路二:rem布局
如何理解rem布局?
思考一个问题,假如我们的设计稿是750px,我们量出来一个盒子的宽度是75px,那么在640px下面,它应该是多少合适呢? 答案是:64
问题,如果才能保证你写的css的尺寸只需要写一次,在不同的屏幕尺寸下面不用改?
假如我们在750px下面,我们让html的font-size为75,则这个盒子的宽度是1rem,在640px下面我们让html的font-size为64,则这个盒子的宽度也是1rem,问题就这样解决了。
那么实际开发中,该用什么样等布局思路?
我们打开m.jd.com,m.vip.com,会发现,实际上没有一个网站用了纯粹的百分比或者rem布局,经常会发现各种布局思路混在一起,因为没有一套布局思路能够通用保证不出问题
为什么rem不是万能的?
比如1px,如果我们在dpr是2的情况下就会变得很粗,我们知道那并不是真正的1像素。
推荐布局思路——使用由阿里出品的lib-flexible库。

网址:https://github.com/amfe/lib-flexible


该如何使用呢?
1. 引入布局用的flexible.js要注意的是不要再写meta:viewport标签了,因为flexible.js会自动帮你创建;
2. 引入base.css;
3. 把设计师的设计稿拿过来,标注稿基准字体大小 = 标注稿宽度 / 10,如标注稿宽为750,标注稿基准字体大小为75;标注稿宽为640,标注稿基准字体大小为64;
4. 除了字体大小以外,其他所有的均按rem来,比如你的设计稿是750px的,那么,假如你量出来的是75px,则是1rem;
字体除外,要根据不同的dpr设置不同的大小,比如如果是750的设计稿,那么字体假如是24px,则在dpr为1的情况下是16px,dpr2的情况下是24px,dpr3的情况下是32px(这块涉及到字体专业知识,总结一句话就是没有人会考虑用奇数字体,https://www.zhihu.com/question/20440679,所以不能让工具帮我们自动算,得写死。
以上是我个人关于移动端布局的一些总结。如有不妥的地方,还请指正。
最后附上关于移动端常见问题当网址:



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 href="http://www.imooc.com" target="_blank">第一张 路飞与艾斯</a>
</div>
<div>
<img src="img/2.jpg">
<a href="http://www.imooc.com" target="_blank">第二张 艾博</a>
</div>
<div>
<img src="img/3.jpg">
<a href="http://www.imooc.com" target="_blank">第三张 路飞</a>
</div>
<div>
<img src="img/4.jpg">
<a href="http://www.imooc.com" target="_blank">第四张 艾斯</a>
</div>
<div>
<img src="img/5.jpg">
<a href="http://www.imooc.com" target="_blank">第五张 女王</a>
</div>
<div>
<img src="img/6.jpg">
<a href="http://www.imooc.com" target="_blank">第六张 香吉士</a>
</div>
<div>
<img src="img/7.jpg">
<a href="http://www.imooc.com" target="_blank">第七张 艾斯</a>
</div>
<div>
<img src="img/8.jpg">
<a href="http://www.imooc.com" 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);
});

蓝蓝设计www.lanlanwork.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>



蓝蓝设计www.lanlanwork.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发送一个通知,这样就形成了调用关系。

蓝蓝设计www.lanlanwork.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. 这里写图片描述



蓝蓝设计www.lanlanwork.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应该 


蓝蓝设计www.lanlanwork.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的规范。


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档