首页

原生JS实现ajax详解

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

原生js写ajax可以类比打电话

打电话分下面4步:
1.拿出手机
2.拨号
3.说话
4.听对方说话

ajax也分下面4步:
1.创建ajax对象
2.连接到服务器
3.发送请求(告诉服务器我要什么文件)
4.接收返回值

下面是原生js写ajax的具体写法 :


    
  1. <script>
  2. window.onload=function()
  3. {
  4. var oBtn = document.getElementById("btn1");
  5. oBtn.onclick = function()
  6. {
  7. //1.创建ajax对象
  8. //只兼容非ie6的浏览器,在ie6浏览器上运行会提示没有被定义
  9. //var oAjax = new XMLHttpRequest();//这才是ajax实际的请求
  10. //alert(oAjax);
  11. //ie6浏览器下按照下面方法写,但是在别的浏览器中不能用,会报错。
  12. //var oAjax = new ActiveXObject("Microsoft.XMLHTTP");
  13. //alert(oAjax);
  14. //鉴于上面出现的问题,可以采取下面的方法解决,用if判断是否为IE6浏览器
  15. if(window.XMLHttpRequest)//如果有XMLHttpRequest,那就是非IE6浏览器。()里面加window的原因下面会有描述。
  16. {
  17. var oAjax = new XMLHttpRequest();//创建ajax对象
  18. }
  19. else//如果没有XMLHttpRequest,那就是IE6浏览器
  20. {
  21. var oAjax = new ActiveXObject("Microsoft.XMLHTTP");//IE6浏览器创建ajax对象
  22. }
  23. //2.连接服务器
  24. //open(方法、文件名、异步传输)
  25. //方法:
  26. //传输方式是get方式还是post方式。
  27. //文件名
  28. //告诉服务器要读哪个文件
  29. //异步传输
  30. //异步:多件事一件一件的做
  31. //同步:多件事情一起进行
  32. //但是js里面的同步和异步和现实的同步异步相反。
  33. //同步:多件事一件一件的做
  34. //异步:多件事情一起进行
  35. //ajax天生是用来做异步的
  36. oAjax.open("GET","a.txt?t='+new Date().getTime()",true);//加上t='+new Date().getTime()"的目的是为了消除缓存,每次的t的值不一样。
  37. //3.发送请求
  38. oAjax.send();
  39. //4.接收返回
  40. //客户端和服务器端有交互的时候会调用onreadystatechange
  41. oAjax.onreadystatechange=function()
  42. {
  43. //oAjax.readyState //浏览器和服务器,进行到哪一步了。
  44. //0->(未初始化):还没有调用 open() 方法。
  45. //1->(载入):已调用 send() 方法,正在发送请求。
  46. //2->载入完成):send() 方法完成,已收到全部响应内容。
  47. //3->(解析):正在解析响应内容。
  48. //4->(完成):响应内容解析完成,可以在客户端调用。
  49. if(oAjax.readyState==4)
  50. {
  51. if(oAjax.status==200)//判断是否成功,如果是200,就代表成功
  52. {
  53. alert("成功"+oAjax.responseText);//读取a.txt文件成功就弹出成功。后面加上oAjax.responseText会输出a.txt文本的内容
  54. }
  55. else
  56. {
  57. alert("失败");
  58. }
  59. }
  60. };
  61. }
  62. };
  63. /*//上面if里面需要些window的原因
  64. //js里面的变量和属性
  65. var a = 12;
  66. alert(a);//页面上弹出12很正常,而实际上输出的是下面的写法,是属于window的,只是window能省就省了。
  67. alert(window.a);//输出结果是一样的
  68. window.alert(window.a);
  69. //想a这种全局变量实际上是winow的一个属性。
  70. //如果不定义一个变量a直接像下面那样输出a
  71. alert(a)//系统会报错,而不是undefind,因为没有定义变量a。
  72. alert(window.a);//如果是这样写,系统就不会报错了,会显示undefind。
  73. //出现上面的原因是因为直接写a从根上就找不到a,而前面加上window只是找不到window的属性a了。*/
  74. </script>

但是,不能每次用ajax的时候都写那么多代码,要把这段ajax代码封装起来,方便使用。

封装ajax代码如下:


    
  1. //最后把代码封装起来,封装起来以后,要给这个函数加上一个参数url.参数是为了替换要读取的文件名
  2. function ajax(url,fnSucc)
  3. {
  4. if(window.XMLHttpRequest)
  5. {
  6. var oAjax = new XMLHttpRequest();
  7. }
  8. else
  9. {
  10. var oAjax = new ActiveXObject("Microsoft.XMLHTTP");//IE6浏览器创建ajax对象
  11. }
  12. oAjax.open("GET",url,true);//把要读取的参数的传过来。
  13. oAjax.send();
  14. oAjax.onreadystatechange=function()
  15. {
  16. if(oAjax.readyState==4)
  17. {
  18. if(oAjax.status==200)
  19. {
  20. fnSucc(oAjax.responseText);//成功的时候调用这个方法
  21. }
  22. else
  23. {
  24. if(fnfiled)
  25. {
  26. fnField(oAjax.status);
  27. }
  28. }
  29. }
  30. };
  31. }

将封装的ajax调用:


    
  1. <script src="new_ajax.js"></script>//引用封装的ajax文件
  2. <script>
  3. window.onload=function()
  4. {
  5. var oBtn = document.getElementById("btn1");
  6. oBtn.onclick = function()
  7. {
  8. ajax('a.txt',function(str){//读取a.txt文件里面的内容
  9. alert(str);//将读取的内容输出
  10. })
  11. }
  12. };
  13. </script>
蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

遮罩层上滚动,使下方的列表随之滚动

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

效果

这里写图片描述

遮罩层为一张边框样式图(如下图):

这里写图片描述

边框样式遮罩层显示在最上方,然后是中间的列表,最下层是一个透明黑色遮罩层,滚动鼠标滚轮,能控制列表滚动

实现原理

注册最上面遮罩层的滚动事件,拿到滚动滚动方向,然后控制列表滚动的方向和距离

上代码

注册事件 /**
 * 增加滚轮滚动事件(暂时只实现了chrome的滚动效果)
 * @param modalDomId 遮罩层domId
 * @param domId 需要滚动下层列表domId
 */ addMousewheelListener(modalDomId:string,domId:string){ //添加页面监听 let modalAwardPanel = document.getElementById(modalDomId);
  modalAwardPanel.addEventListener('mousewheel',function(e){
    let scrollContentDom = document.getElementById(domId); //向上滚 if (e.wheelDelta > 0){ if (scrollContentDom.scrollTop -20 >= 0){
        scrollContentDom.scrollTop = scrollContentDom.scrollTop - 20;
      } else{
        scrollContentDom.scrollTop = 0 ;
      }
    } //向下滚 else{ if(scrollContentDom.scrollTop + scrollContentDom.clientHeight < scrollContentDom.scrollHeight){
        scrollContentDom.scrollTop = scrollContentDom.scrollTop + 20;
      }
    }
  });
}

组件调用: this.addMousewheelListener("你的最上方遮罩层id","你想要滚动的列表id");
蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

前端算法之弹幕设计

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

大家都说前端写页面较多,几乎用不到算法。本文愿从弹幕设计这个场景来描述算法在前端中的应用,我们先来看下实现效果:

图1.1 弹幕效果

 

开场之前我们先来描述弹幕开发的难度,再集中精力描述算法设计的思路。

* 如何保证不同字号的弹幕不碰撞
* 弹幕的位置计算
* 弹幕的速度控制及动画实现
* 弹幕与视频的同步

***如何保证不同字号的弹幕不碰撞***

如果弹幕采用相同的字号,碰撞的问题处理起来比较简单,只要考虑相邻弹幕的播放速度和偏移的位置就可以计算出来。然而使用不同字号的弹幕处理起来就麻烦了许多,弹幕的起始位置不可以线性的增加,比如第一行放了字幕,接下来的字幕可以按顺序从上至下依次放置即可。

***弹幕的位置计算***

只有设计好弹幕的初始位置,才可以动态、的管理不同字号弹幕的碰撞问题。打个比方,我们通过接口获取了2秒之内的弹幕数据1000条,每个字幕的长度、速度、字号都不同,怎么管理这些弹幕,示意图如下:

图2.1 弹幕管理示意图

 

这是第一种情况,按照从上到啊的顺序依次摆放以后会有几个问题:
1. 弹幕五、六、七该怎么计算位置,按top值循环取模+累加吗?
2. 当弹幕一或者弹幕三足够长的时候,如何准时的跳过当前位置计算?
3. 当前屏幕的弹幕播放结束,如何再计算的时候利用空出来的位置
4. 空出的位置是否满足当前弹幕的高度
5. ……

一系列问题就不统统列举出来了,基于这个背景我们结合数学建模的思维方式,找到了弹幕场景相似度非常高的机场运营。我们可以把弹幕当做飞机,每个时间段播放多少弹幕和机场每个时间段放飞多少飞机一个道理。

首都国际机场一共有3条跑道,两条4E级跑道、一条4F级跑道,2016年的吞吐量为9000万人次。它的运行机制就是所有飞机通过搭台有顺序的共用3条跑道来完成运输任务的。

同理,我们也设计了几个个角色:一个是轨道(跑道)、一个是调度(塔台)、一个是弹幕(飞机),我们为每个角色设计一个类分为为Track、Main、Bullet。

* 轨道
            
       轨道这个角色很重要,它可以解决弹幕位置计算、速度控制、碰撞检测问题。
       首先,我们要来初始化轨道。通俗的说我们要修建几个跑道呢,我们不是实物,可以动态调整轨道的                        数量,计算的原则:
        轨道数量 = 播放器有效高度 / 设备基准字号
    * 播放器有效高度:播放器的实际高度减去控制条的高度,因为弹幕不可以遮挡控制条。
    * 设备基准字号:移动端是10px,pc端是12px;
        为啥计算公式是这样的?因为我们要支持不同字号的弹幕。试想不同的字号对物理空间的占用是不同的,然而如果要求轨道的尺寸是动态的,那就带来很复杂的计算。本文提出“虚拟轨道”的概念,在交通管制中最常见的就是道路合并或者改向。我们也是采用将相邻的物理轨道临时合并为一条轨道。这样就可以轻松的解决不同字号的轨道占用问题。原理图如下:
        

图2.2 轨道计算示意图

其次我们来回忆下机场的工作流程:
1. 机长呼叫塔台,CZ6132请求起飞
    * 目前跑道均被占用,请等待
        * N时刻后再次执行步骤1
    * 目前跑道 A1 空闲,准许进入
        * 执行步骤3
2. 塔台查看跑道使用情况
3. 进入跑道,起飞完成
4. 机长通知塔台,本次起飞完成,释放跑道的占用
5. 其他飞机同样执行上述步骤

按照这个思路,我们的弹幕工作流程:
    
1. 弹幕进入播放器
2. 轨道根据弹幕的播放速度、尺寸计算是否有合适的轨道提供
    * 没有
        * 通知弹幕尚无合适轨道提供,请等待;同时,弹幕队列中的其他弹幕依次执行步骤1
    * 有
        * 执行步骤3
3. 播放器加载弹幕DOM,开始播放,待播放完成
4. 播放完成通知轨道更新轨道占用情况
5. 其他弹幕同样执行上述步骤

图2.3 轨道可用性计算示意图

 

关于轨道的基本原理我们整理清楚了,当然还有不少细节比如如何和调度通信、如何和弹幕通信以及虚拟轨道检测算法等。有兴趣的同学可以参考代码吧。https://github.com/bytedance/xgplayer/blob/master/packages/xgplayer/src/control/makeBullet.js

* 弹幕
       弹幕基本是实现“飞机”的角色,我们要求它具有自身的属性和方法。比如调度中心通过id能拿到它所有的基本信息,轨道控制也可以通过弹幕进行检查和更新。当然弹幕也必须具备状态自动更新、移动、播放结束通知、自动销毁等功能。
* 调度
        调度就是搭台的化身,承接着轨道、弹幕的控制,也保持着与播放器的步调一致。它的职责如下:
    1. 播放器交互控制
    2. 弹幕队列控制
    3. 自身状态更新
    4. 数据格式转换
    5. 动画执行
        还是直接用流程图来描述更直接些:
        
       

图2.4 弹幕运行机制流程图

在弹幕启动之后,首先要检查本地是否已有缓存数据,没有的话直接请求数据并缓存,然后执行数据读取,首次过滤数据进入弹幕队列,同时启动定时器。弹幕队列的数据会定期请求轨道,检测队列里的弹幕是否可以进入,一旦确认后轨道做好登记,弹幕就可以进入播放器开启动画播放了。定时器每隔2秒就会再次更新数据进入到弹幕队列(这块不同的业务可以定制不同的规则)。弹幕播放结束后会通知调度和轨道,调度会在弹幕队列中移除该弹幕实例,轨道也会移除该弹幕实例的轨道占用。

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


快速开发一个自己的微信小程序

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

一.写在前面

小程序学习资料

1.为什么要学小程序开发?

对于前端开发而言,微信小程序因为其简单快速、开发成本低、用户流量巨大等特点,也就成了前端开发工程师必会的一个技能。

2.开发准备:

(1)有人开玩笑说,会vue小程序根本都不用学:

微信小程序虽然是腾讯自己搞的,但是核心的思想跟vue等框架是一样一样的哦~

(2)善于搜集精美的小组件: “我们不生产代码,我们只是代码的搬运工”,善于找到想要的组件并把他们巧妙优雅的组装成一个大项目,也算是程序员一项基本技能了。

具体怎么找到想要的小程序demo,篇末会给大家推荐小程序的资源,有很多大神的项目哦

撸起袖子开干了

一.注册小程序账号,下载IDE

1.官网注册https://mp.weixin.qq.com/,并下载IDE。

2.官方文档一向都是最好的学习资料。

注意:

(1)注册账号之后会有一个appid,新建项目的时候需要填上,不然很多功能是用不了的,比如不能预览,不能上传代码等等。

(2)如果你注册过微信公众号的话,一定要注意,微信公众号和小程序是两个账号,二者的appid也是不同,小程序开发必须使用小程序的appid哦。

二.小程序框架介绍和运行机制

1.我们建立了“普通快速启动模板”,然后整个项目目录如下:

2.app.js

整个项目的启动文件,如注释写的onlaunch方法有三大功能,浏览器缓存进行存和取数据;用登陆成功的回调;获取用户信息。

globalData是定义整个项目的全局变量或者常量哦。

3.app.json

整个项目的配置文件,比如注册页面,配置tab页,设置整个项目的样式,页面标题等等;

!注意:小程序启动默认的第一个页面,就是app.json的pages中的第一个页面哦。

4.pages

小程序的页面组件,有几个页面就会有几个子文件夹。比如快速启动模板,就有两个页面,index和logs

5.打开index目录

可以看到有三个文件,其实和我们web开发的文件是一一对应的。

index.wxml对应index.html;

index.wxss对应index.css;

index.js就是js文件哦。

一般我们还会给每个页面组件添加一个.json文件,作为该页面组件的配置文件,设置页面标题等功能

6.双击index.js文件

(1)var app = getApp();

引入整个项目的app.js文件,用来取期中的公共变量等信息。

如果要使用util.js工具库中的某个方法,在util.js中module.exports导出,然后在需要的页面中require即可得到哦。

(2)比如,我们要获取豆瓣电影的时候,我们需要调用豆瓣的api;我们先在app.js中的gloabData中定义doubanBase

然后在index.js中使用app.globaData.doubanBase即可取到这个值。

当然这些常量你也可以在页面需要的时候,再用写死的值,但是为了整个项目的维护,还是建议把这种公用参数统一写在配置文件中哦。

(3)接下来在整个page({})中,第一个data,就是本页面组件的内部数据,会渲染到该页面的wxml文件中,类似于vue、react哦~

通过setData修改data数据,驱动页面渲染

(4)一些生命周期函数

比如onload(), onready(), onshow(), onhide()等等,监听页面加载、页面初次渲染、页面显示、页面隐藏等等

更多的可以查官网API哦。其中用的最多的就是onload()方法,和onShareAppMessage()方法(设置页面分享的信息)

7 .wxml模板的使用。

比如本项目电影页面,就是以最小的星级评价组件wxml当做模板,star到movie到movie-list,一级一级的嵌套使用。

star-template.wxml页面写好name属性;然后import引入的时候通过name获得即可

8.常用的wxml标签

view,text,icon,swiper,block,scroll-view等等,这些标签直接查官网文档即可

三.小程序框架、各个页面以及发布上线的注意点

1.整个框架中的一些注意点

(1)整个wxml页面,最底层的标签是哦。

(2) 每个页面顶部导航栏的颜色,title在本页面的json中配置,如果没有配置的话,取app.json中的总配置哦。

(3)json中不能写注释哦,不然会报错的。

(4)路由相关

1)使用wx.SwitchTab跳转tab页的话,在app.json中除了注册pages页面,还需要在tabBar中注册tab页,才能生效哦。

注意:tab最多5个,也就是我们说的头部或者底部最多5个菜单。其他的页面只能通过其他路由方法打开哦。

2)navigateTo是跳到某个非tab页,比如欢迎页,电影详情页,城市选择页;在app.json中注册后,不能在tabBar里注册哦,不然同样也是不能跳转的哦。

3)reLaunch跳转,新开的页面左上角是没有退回按钮的,本项目只用了一次,切换城市的时候哦。

(5)页面之间传递参数

参数写在跳转的url之中,然后另一个页面在onload方法中的传参option接收到。如下传递和获取id

(6)data-开头的自定义属性的使用

比如wxml中我们怎么写

点击的事件对象可以这么取,var postId = event.currentTarget.dataset.postid;

注意: 大写会转换成小写,带_符号会转成驼峰形式

(7)事件对象event,event.target和event.currentTarget的区别:

target指的是当前点击的组件 和currentTarget 指的是事件捕获的组件。

比如,轮播图组件,点击事件应该要绑定到swiper上,这样才能监控任意一张图片是否被点击,

这时target这里指的是image(因为点击的是图片),而currentTarget指的是swiper(因为绑定点击事件在swiper上)

(8)使用免费的网络接口:

本项目中用到了 和风天气api,腾讯地图api,百度地图api,豆瓣电影api,聚合头条新闻api等,具体用法可以看各自官网的接口文档哦,很详细的

注意:免费接口是有访问限制的,所以如果用别人的组件用了这种接口的话,最好还是自己注册一个新的key替换上哦

附上一个免费接口大全:

https://github.com/jokermonn/-Api

!!另外还要注意,要把这些接口的域名配置到小程序的合法域名中,不然也是访问不了的

(8)wxss有一个坑:无法读取本地资源,比如背景图片用本地就会报错哦。

把本地图片弄成网络图片的几种方式: 上传到个人网站;QQ空间相册等等也是可以的哦

2.切换城市页面:

(1)首页使用navigateTo跳转到切换城市页,由于首页并没有关闭,导致切换了城市返回来,天气信息还是旧的。

正确的处理逻辑如下:

1)使用reLaunch跳转到切换城市页面,实质是关闭所有页面打开新的页面哦。

2)切换城市页面,更新公共变量中城市信息为手动切换的城区,再switchTab回到首页,触发首页重新加载。

3)首页获取城市信息的时候加一个判断,全局没有才取定位的,全局有(比如刚才设置了)就用全局的哦。

(2)城市列表的滚动和回到顶部

基于scroll-view组件的scroll-top属性,初始就是0,滚动就会增加的;点击回到顶部给它置为0即可回到顶部

3.天气页

(1)初始化页面,天气显示的逻辑

首先调用小程序的wx.getLocation方法获得当前的经纬度,然后调用腾讯地图获得当前的城市名称和区县名称,并存到公共变量中,

再调用查询天气和空气质量的方法哦。

(2)容错处理

城市的名称长短不一,有点名字特别长,比如巴彦淖尔市这种,需要动态的获取完整的城市名称;

有些偏僻的城市暂时没有天气信息,我们需要对返回的结果进行判断,没有信息的需要给用户一个良好的提示信息。

4.周边-地图服务页面

(1)调用百度地图的各种服务,查询酒店,美食,生活服务三种信息,更多信息可以看百度地图的文档

(2)点击时给被点中的图标加个边框,数据驱动视图,所以使用一个长度为3的数组保存三个图标当前是否被点中的状态

然后wxml再根据数据来动态添加class,增加边框样式

5.豆瓣电影页

(1)电影详情页的预览图片,用小程序本身的previewImage实现。

(2)详情页使用onReachBottom()方法,监控用户上拉触底事件,然后发送请求继续获得数据,实现懒加载的效果

(3)用户体验方面的优化,js中将整数评分比如7分统一改为7.0分,然后wxml模板再判断分数是否为0显示“暂无评分”

(4)搜索之后清空搜索框

因为小程序中不能使用getelementbyId这种方式获得元素,只能用数据来控制了

在data中加一个属性searchText来保存搜索框的内容并和 input的value属性绑定,搜索完成或者点击X时,searchText变量清空即可实现清空输入框的效果哦。

6.新闻页面

(1)聚合头条新闻的免费接口,只返回了新闻的基本信息,新闻的主体内容是没有的哦。

我找了好多新闻类的接口,好像都是没有新闻主体内容的。如果谁知道更好的接口欢迎留言告诉我哈~

(2)当然,也可以自己去爬新闻网站的数据哦

7.更多页面

(1)小程序目前开放外链的功能只是给公司组织的小程序开放了,个人开发还是不能使用外链的哦。

(2)彩蛋页面,获得用户信息

通过 wx.setStorageSync('userInfos', userInfos); 可以获得登陆小程序的用户的个人信息,可以发送给后台存到数据库中,方便对用户进行分析

我这里只是存储到浏览器缓存中哦,最大应该是10M缓存;如果用户把这个小程序从小程序列表中删除掉,就会清空这个缓存。

8.发布注意

(1) 新版本小程序发布的限制为2M,一般都是图片最占空间,所以尽量使用网络图片

具体怎么把本地图片变成网络图片,上面有讲哦。

(2)在开发者工具上预览测试没问题,点击上传;网页版小程序个的人中心的左侧“开发管理”菜单,第三块--开发版本就有了内容。

(3)点击提交,填写小程序相关信息,就可以提交审核了哦。

注意:分类最好填写准确,这样才能更快的通过审核哦。我这个小程序一天半时间过审上线的

至此,我就把两天开发内碰到的坑和注意点都过了一遍,据说还有更多的坑,等之后更深入的开发再继续研究咯。

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

mongoose中save无法获取回调函数值的解决方法

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

mongoose保存数据:

const save = new Model(data).save()
    
  • 1

如果成功,则可以获取到保存在数据库的值,但是如果保存数据失败,则会抛出异常,好在save可以传入一个回调函数,用法如下:

const save = new Model(data).save((err, result)=>{ if(err){ // 保存失败执行的操作
    }else { // 保存成功执行的操作
    }

})
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

我们希望根据结果获取到不同的值,但是此时save返回的是undefined,因为save中的回调函数是一个异步操作

解决方法:

使用try catch:

try{
    const save = await new Model(data).save();
    // 保存成功执行的操作 return ... }catch(err){
    // 保存失败执行的操作 return ... }
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注意:在async函数中才可以这么使用,因为await只能用在async函数中

示例:(注册功能)

user.model.js

const mongoose  = require("mongoose"); const port      = process.env.PORT || "8899"; const UserSchema = mongoose.Schema({
    userName: {
        type: String,
        unique: true },
    passWord: String,
    createTime: {
        type: Date, default: Date.now()
    },
    updateTime: {
        type: Date, default: Date.now()
    }
}, {
    timestamps: {
        createAt: "createTime",
        updateTime: "updateTime" }
});

module.exports = mongoose.model("USER", UserSchema);
    
  • 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

service.js

const User = require("./user.model);
class User{
    async login(user){
            try{
                const result = await new User(user).save();
                // 其他操作,如发送注册邮件
                return { success: true }
            }catch(err){
                return { success: false, message: "用户名或密码错误" }
            }
   }
}
moduel.exports = new User();
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

controller.js

const server = require("./server); async login(){ // 首先获取请求中携带的用户信息 const result = await server.login(user);
    if(result.success){ // 注册成功执行的操作 }else { // 注册失败执行的操作 }
}
蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

HTML-图片标签img

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

图片标签

图片标签<img src=路径属性 alt:加载失败后显示的文本  width:指定图片宽度  height:指定图片高度>  单位: px

路径属性

绝对路径
        E:\ruanjian\软件\环境\images
相对路径:相对于主文件位置的路径
        引用文件方式:

        同级:直接写文件名.后缀名
        上级:../文件名.后缀名   ../返回上一级文件夹
        下级:文件夹/文件名.后缀名


    
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title></title>
  6. </head>
  7. <body>
  8. <h1>这是一个图片</h1>
  9. <!-- 图片标签<img src=路径属性 alt:加载失败后显示的文本 width:指定图片宽度 height:指定图片高度 单位:px>
  10. 路径属性:
  11. 绝对路径
  12. E:\ruanjian\软件\环境\images
  13. 相对路径:相对于主文件位置的路径
  14. 同级:直接写文件名.后缀名
  15. 上级:../文件名.后缀名 ../返回上一级文件夹
  16. 下级:文件夹/文件名.后缀名
  17. -->
  18. <img src="../img/ad.jpg" alt="加载中" width="1000px" height="500px">
  19. <img src="../img/1.jpg" alt="加载中"><br><br><br><br><br><br><br><br><br><br><br>
  20. <img src="../footer.jpg" ><br>
  21. </body>
  22. </html>

<br>标签:换行   <img>标签为内联标签所以不换行,所以添加<br>标签换行。

页面是这样的:

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


前端性能优化之Lazyload

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

前端性能优化之Lazyload

@(Mob前端-冬晨)[JavaScript|技术分享|懒加载]


Lazyload 简介

前端工作中,界面和效果正在变得越来越狂拽炫酷,与此同时性能也是不得不提的问题。有些项目,页面长,图片多,内容丰富。像商城页面。如果同步加载时一次性加载完毕,那肯定是要等到花都谢了,loading转的人都崩溃~。今天分享的是Lazyload技术 是一种延迟加载技术。让页面加载速度快到飞起、减轻服务器压力、节约流量、提升用户体验。

一、实现思路

页面较长,屏幕的可视区域有限。 
不设置页面中img标签src属性值或者将其指向同一个占位图。 
图片的实际地址存在img标签自定义的一个属性中,如:“data-url”。 
监听scroll,滚动到某个位置时,动态的将url替换成实际的“data-url”。

二、上代码

  • html部分(简单示意下结构)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Lazyload</title> <style type="text/css"> .mob-wrap li{list-style: none;width: 100%;height: 345px;} </style> </head> <body> <ul class="mob-wrap"> <li"> <img class="tamp-img" alt="loading" data-src="http://mob.com/public/images/index/sharesdk-logo.jpg"><p>ShareSDK轻松实现社会化功能</p> </li> <li"> <img class="tamp-img" alt="loading" data-src="http://mob.com/public/images/index/sms-logo.jpg"><p>短信验证码SDK</p> </li> <li"> <img class="tamp-img" alt="loading" data-src="http://mob.com/public/images/index/rec-logo.jpg"><p>MobLink实现Web与App的无缝链接</p> </li> </ul> </body> </html>
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

简要流程

Start监听滚动事件距顶部高度<scrollTop么?将url替换成data-urlEndyesno
  • js部分
var aImg = [
  {"src":"http://mob.com/public/images/index/sharesdk-logo.jpg","txt":"ShareSDK轻松实现社会化功能"},
  {"src":"http://mob.com/public/images/index/sms-logo.jpg","txt":"短信验证码SDK"},
  {"src":"http://mob.com/public/images/index/rec-logo.jpg","txt":"MobLink实现Web与App的无缝链接"}
]; var sLi = '';
document.getElementsByClassName("mob-wrap")[0].innerHTML=""; for(let i = 0;i<10;i++){
  sLi = document.createElement("li");
  sLi.innerHTML = `<img class="tamp-img" alt="loading" src="./zwt.gif" data-src="${aImg[i%3].src}"><p>${aImg[i%3].txt}</p>`;
  document.getElementsByClassName("mob-wrap")[0].appendChild(sLi);
};

window.onscroll = function () {
  var bodyScrollHeight =  document.documentElement.scrollTop;// body滚动高度
  var windowHeight = window.innerHeight;// 视窗高度
  var imgs = document.getElementsByClassName('tamp-img');
  for (var i =0; i < imgs.length; i++) { var imgHeight = imgs[i].offsetTop;// 图片距离顶部高度 if (imgHeight < windowHeight + bodyScrollHeight - 340) { imgs[i].src = imgs[i].getAttribute('data-src'); imgs[i].className = imgs[i].className.replace('tamp-img','');
    }
  }
};
    
  • 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




谢谢观看,搞定收工0.0~~~这样草草了事总是不好的

三、再优化

不做任何处理直接监听scroll必然导致在滚动鼠标滚轮的时候,过于频繁的触发处理函数。 
如果刚巧在处理函数中有大量的操作dom等消耗性能的行为,引发大量操作,导致页面变卡变慢, 
甚至浏览器崩溃无响应。 
处理这种问题的思路是节流和防抖。 
节流函数的概念有一个很形象的比喻:在接咖啡的时候,按了一次按钮会出咖啡, 
紧跟着再按几次按钮接到的还是那一杯咖啡,相当于后面几次按的没有起作用。


常规的节流在这里就不多说了,下面介绍的是一种每隔least时间内至少执行一次的节流函数。

//节流函数 _throttle = (fn, delay, least) => { var timeout = null,
  startTime = new Date();
    fn(); return function() { var curTime = new Date();
    clearTimeout(timeout); if(curTime - startTime >= least) {
        fn();
        startTime = curTime;
    }else {
        timeout = setTimeout(fn, delay);
    }
    }
}
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

使用节流函数

function compare () { var bodyScrollHeight =  document.documentElement.scrollTop;// body滚动高度 console.log(bodyScrollHeight+"替换src方法") var windowHeight = window.innerHeight;// 视窗高度 var imgs = document.getElementsByClassName('tamp-img'); for (var i =0; i < imgs.length; i++) { var imgHeight = imgs[i].offsetTop;// 图片距离顶部高度  if (imgHeight < windowHeight + bodyScrollHeight - 340) {
       imgs[i].src = imgs[i].getAttribute('data-src');
       imgs[i].className = imgs[i].className.replace('tamp-img','');
    }
  }
}
window.onscroll = _throttle(compare, 350,600);
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

滚动时间least长于600,调用compare,否则延迟350ms执行。 
这样相对于直接onscroll性能得到更进一步提升,在功能上也没有什么问题。 
不同的业务场景调整一下delay和least就可以。


结语:历史潮流浩浩荡荡,前端技术的发展也是日新月异。 
不断通过一个个小的技术点深入探究,以加深自己对js这门语言的理解。 
温故知新,回顾旧的内容,学习新的内容和特性,更好的适应工作中的需求。

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



跨浏览器问题

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

写在前面的话

关于跨浏览器问题一直是一个大问题, 所以我决定在此做一个记录, 当然不可能把跨浏览器问题一下子都搞定, 所以该文章将是一个长期的过程, 当coding时遇到了, 就会完善该文。

添加事件

var EventUtil = { /*
     *添加事件
    */ addHandler: function(element, type, handler) { if(element.addEventListener){ element.addEventListener(type, handler, false)
        }else if(element.attachEvent){ element.attachEvent('on'+type, handler)
        }else{ element['on'+type] = handler
        }
    }, /*
     *删除事件
    */ removeHandler: function(element, type, handler){ if(element.removeEventListener){ element.removeEventListener(type, handler, false)
        }else if(element.detachEvent){ element.detachEvent('on'+type, handler)
        }else { element['on'+type] = null }
    }, /*
     *获得事件对象
    */ getEvent: function(event){ return event ? event : window.event  //ie浏览器的事件对象是window对象的属性, 所以需要window.event来获取。 }, /*
     *获得事件对象的事件目标(触发事件的事件目标)
    */ getTarget: function(event){ return event.target || event.srcElement //这是||符号的另一种用法, 遇到true就返回。 }, /*
     *阻止默认事件
    */ preventDefault: function(event){ if(event.preventDefault){
            event.preventDefault
        }else{
            event.returnValue = false }
    }, /*
     *阻止事件冒泡
    */ stopPropagation: function(event){ if(event.stopPropagation){
            event.stopPropagation()
        }else {
            event.cancelBubble = true }
    }

}  // stopPropagation()方法既可以阻止事件冒泡,也可以阻止事件捕获,也可以阻止处于目标阶段。
    
  • 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
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

ajax事件

关于xhr对象, ie7需要之前的需要使用ActiveXObject对象来实现, 而且存在三个不同的版本。 虽然现在已经不用兼容ie7以前的浏览器了, 还是可以了解一下: 
//适用于IE7之前的版本

function createXHR(){ if(typeof arguments.callee.activeXString != 'string'){ var versions = ['MSXML2.XMLHttp.6.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp'],
        i,
        len; for(i = 0; len = version.length; i++){ try{ new ActiveXObject(veersions[i]); arguments.callee.activeXString = versions[i] break }catch(ex){ //跳过 }
        }
    } return new ActiveXObject(arguments.callee.activeXString)
}
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

//最终版本

function createXHR(){ if(typeof XMLHttpRequest != 'undefined'){ return new XMLHttpRequest()
    }else if(typeof ActiveXObject != 'undefined'){ if(typeof arguments.callee.activeXString != 'string'){ var versions = ['MSXML2.XMLHttp.6.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp'],
        i,
        len; for(i = 0; len = version.length; i++){ try{ new ActiveXObject(veersions[i]); arguments.callee.activeXString = versions[i] break }catch(ex){ //跳过 }
        }
    } return new ActiveXObject(arguments.callee.activeXString)
    }else { throw new Error("NO XHR object availabel")
    }
}
蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

伪类和伪元素

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

定义:

伪类和伪元素就是为文档中不一定存在的结构指定样式,或者为某些元素(甚至文档本身)的状态所指示的幻象类指定样式。css引入伪类和伪元素概念是为了格式化文档树以外的信息。

伪类的形式:选择符: 伪类{ 属性:属性值 }

伪元素的形式:选择符:: 伪元素{ 属性:属性值 }

CSS3规范中要求使用双冒号(::)表示伪元素,以此来区分伪元素和伪类。

 

链接伪类

a:link{…}  //指向未访问的链接

a:visited{…} //指向已访问的链接

 

动态伪类

E:hover{…}  //元素上有鼠标指针停留

E:active{…} //元素被用户输入激活

E:focus{…}  //元素拥有输入焦点

 

伪类的顺序很重要,一般为link-visited-focus-hover-active。动态伪类可以应用到任何元素,可以为用户提供一种“强调”的作用。


E:first-child{…}

为父元素(可以body,div,ul,ol等)中的第一个子元素E元素设置样式,注意,E必须是父元素中的第一个子元素。

 

E:lang(value)

为E元素中lang属性为value的元素设置属性。相当于E[lang |= “value”]。

 

结合伪类

a:link:hover{…}//鼠标停留在未访问的链接上

a:visited:hover{…}//鼠标停留在已访问的链接上

 

伪元素选择器

在文档中插入假想元素,导致用户代理对一个假想元素做出响应。

p:first-letter{…}  //设置首字母样式,为p块级元素第一个元素设置样式

p:first-line{…}   //设置第一行的样式,为p块级元素第一个元素设置样式

所有伪元素都必须放在出现该伪元素的选择器的最后面。

 

设置之前和之后元素的样式

E:before {content:”…”}

E:after {content:”…”}


注:关于伪类和伪元素,我的理解并不是很深,不过掌握上面的这些内容,我想也是够用了。以上内容大部分是《CSS权威指南》中内容,总结了一下方便记忆。关于伪类和伪元素的内容,这里有一个不错的文章,下面是这篇文章的链接:http://www.alloyteam.com/2016/05/summary-of-pseudo-classes-and-pseudo-elements/#prettyPhoto 下面的内容引自这篇文章,可以补充上面的内容,贴在这里方便自己日后查阅。

伪类与伪元素的具体用法


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

vue生命周期钩子函数(11个)

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

说一下vue的声明周期:

vue 的生命周期11个钩子函数是按照以下的顺序来的 :(不可逆转哦,第11个除外) 
一. 组件创建前后

1.beforeCreate
2.created
    
  • 1
  • 2

如,写一个子组件,然后挂在到父组件,在子组件中,console.log 子组件中的

data(){ return { a:1 },
    beforeCreate(){
        console.log(this.a)//undefined },
    created(){
        console.log(this.a)//1 }
}
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11


.


二. vue启动前后

3.beforeMount 4.mounted
    
  • 1
  • 2

这两个的意思就是, 
vue在beforeMount时,还不管事,也就是说,还没有渲染数据到<div id="app"><div/>里面,此时的这个组件还是空的

mounted时,才会往<div id="app"><div/> 添加东西,也就是vue正式 
接管<div id="app"><div/>

可以获取#app的innerHTML查看差异;

beforeMount(){ console.log(document.getElementById('app').innerHTML)//空的
},
mounted(){ console.log(document.getElementById('app').innerHTML)//#app里的内容 }
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6


.


三. 组件更新前后

5.beforeUpdate 6.updated
    
  • 1
  • 2

这个就不用我多说了吧?当子组件里面的 视图改变 的时候触发。 
如,做一个按钮,让data里面的a++,假如 一开始a是1 
beforeUpdate返回1 
updated返回2

beforeUpdate(){
    console.log(document.getElementById('a').innerHTML)//1 },
updated(){
    console.log(document.getElementById('a').innerHTML)//2 }
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

再点一次 
beforeUpdate返回2 
updated返回3。。。 

.


四. 组件销毁前后(一般配合v-if使用)

7.beforeDestroy
8.destroyed
    
  • 1
  • 2

给这个子组件用v-if来控制它的销毁和创建,注意以下:v-show不行。 
子组件销毁前触发beforeDestroy 
子组件销毁后触发destroyed 
第一次会触发7.8. 
创建子组件后会触发以上的第1.2.3.4.钩子函数。

有一个问题,如果我们在子组件里写一个定时器,然后,子组件被销毁了,定时器还会执行吗? 
答案是会的 
所以这时候就会用到了destroyed,在组件被销毁后,我们把定时器给清除就好了。

所以这两个钩子函数一般用于做性能的优化。 

.


五. 组件激活时,未激活时

9.activated
10.deactivated
    
  • 1
  • 2

这两个钩子函数呢一般配合<keep-alive><keep-alive/>来使用。 
通过看 四。这个例子,你肯定知道了一个组件怎么被销毁和创建。 
但是我们知道通常一个组件是很大的,如果我们总是一直创建、销毁、创建、销毁。。。这样很不合理,而且很浪费性能。。。

这时候我们就可以用<keep-alive><keep-alive/>配合着两个钩子函数来控制组件的激活和不激活。

说一下<keep-alive><keep-alive/>,它就相当于把你的组件给缓存下来了,目的呢就是不让组件重复的渲染,然后我们通过v-if触发,子组件就不会再触发7 和 8 了,而是只会频繁的触发9 和 10 
这样性能会比7 和 8 好的多。 

.


六. 当捕获一个来自子孙组件的错误时被调用

11.errorCaptured
    
  • 1

当子孙组件报错的时候,父组件会触发这个钩子函数,并且会返回三个参数, 
第一个参数是 错误对象 
第二个参数是 报错的子孙组件 
第三个参数是 报错的子孙组件的具体哪个地方报错。(如,假如我没有定义b这个变量,但是我去console.log(b) 这一句肯定会报错,假如我把这句错误代码写在了created这个钩子函数里,那第三个参数会返回就是:created hook

具体第11个没深入研究,喜欢的可以去看下官网的 errorCaptured

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


日历

链接

个人资料

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

存档