如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
写在前面:
如果让用简单的几句话说一下什么是原型,或者给原型下个定义,我觉得还是有点困难的,困难之处在于即使说了之后,对于听的人来说,估计也是一头雾水。不过,关于原型的一些基本的东西还是要说明的,这些基本的东西差不多就可以构成一个对原型的理解。首先,原型是函数才有的一个属性;其次,原型就是一个对象,我们可以给它添加属性或方法;最后,原型的作用是实现对象属性的继承。
每个对象都有一个隐藏的
每个函数都有一个
对象是没有
通过原型
什么是原型链?
typeof在判断引用数据类型时只能返回object和function,不能准确判断引用数据类型时数组还是对象。而instanceof可以很好用于判断引用数据类型。
用法:
instanceof是通过判断对象
1、什么是对象?
对象就是属性的集合;
2、对象与函数的关系?
对象都可以看做是由构造函数Object实例化生成的;
函数都可以看做是由构造函数Function实例化生成的;
构造函数Object也是由构造函数Function生成的;
1、原型prototype
__proto__
属性,__proto__
属性指向创建该对象的函数的原型prototype
;
prototype
属性,其prototype
属性值是一个对象;
prototype
属性的,函数是没有__proto__
属性的;
prototype
,可以实现对象属性的继承,即创建在构造函数原型上的方法和属性可以被所有由该构造函数生成的实例所共享;
2、原型链
原型链描述的是对象的继承图谱(类似于家谱图),当访问一个对象的属性的时候,会在该对象中进行查询,如果在该对象中没有查询到,则会沿着该对象的__proto__
线进行查询,直到查询到该属性或者到Object.prototype,这样层层向上查询的线路就是该对象的原型链。
3、instanceof
A instanceof B
A
的原型链上是否存在B
的原型来确定A的数据类型;
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
html, body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
}
.container {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div class="container">
<canvas id="cs"></canvas>
</div>
</body>
<script>
function MoveBalls(element, opts) {
var canvas = document.querySelector(element);
this.canvas = canvas;
this.ctx = canvas.getContext("2d");
var defaultOpts = {
total: 100,
color: "#00D0FF",
size: 1,
width: this.canvas.parentNode.clientWidth,
height: this.canvas.parentNode.clientHeight
};
var opts = opts || defaultOpts;
for (var key in opts) {
defaultOpts[key] = opts[key];
};
for (var key in defaultOpts) {
this[key] = defaultOpts[key];
};
opts = null;
defaultOpts = null;
// 鼠标坐标
this.coordinate = {
x: null,
y: null,
max: 100
};
// 粒子
this.dots = [];
// 含鼠标坐标的粒子数组
this.newDots = [];
// 总数
this.count = 0;
// requestAnimationFrame兼容处理
window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
window.setTimeout(callback, 1000 / 60);
};
this.colorReg = /[rgba()]/g;
this.init();
};
MoveBalls.prototype = {
constructor: MoveBalls,
init: function () {
var _this = this;
this.freshResize();
this.mouseEvent();
this.getDots();
var timer = setTimeout(function () {
clearTimeout(timer);
_this.draw(_this)
}, 300);
},
colorCheck: function () {
this.canvas.style.color = this.color;
var colorData = this.canvas.style.color;
return colorData = colorData.replace(this.colorReg, "").split(",");
},
resize: function (self) {
var _this = self || this;
_this.canvas.width = _this.width;
_this.canvas.height = _this.height;
},
freshResize: function () {
this.resize();
var _this = this;
window.addEventListener("resize", function () {
_this.resize(_this);
});
},
mouseEvent: function () {
var _this = this;
_this.canvas.addEventListener("mousemove", function (e) {
var e = e || winodw.event;
_this.coordinate.x = e.offsetX ? e.offsetX : e.layerX;
_this.coordinate.y = e.offsetY ? e.offsetY : e.layerY;
});
_this.canvas.addEventListener("mouseout", function () {
_this.coordinate.x = null;
_this.coordinate.y = null;
})
},
getDots: function () {
while(this.count < this.total) {
var x = Math.random() * this.canvas.width;
var y = Math.random() * this.canvas.height;
var xMove = Math.random() * 2 - 1;
var yMove = Math.random() * 2 - 1;
this.dots.push({
x: x,
y: y,
xMove: xMove,
yMove: yMove,
max: 100
});
this.count ++;
}
},
draw: function (self) {
var _this = self || this;
var ctx = _this.ctx;
ctx.clearRect(0, 0, _this.canvas.width, _this.canvas.height);
_this.newDots = [_this.coordinate].concat(_this.dots);
_this.dots.forEach(function (dot) {
dot.xMove *= (dot.x > _this.canvas.width || dot.x < 0) ? -1 : 1;
dot.yMove *= (dot.y > _this.canvas.height || dot.y < 0) ? -1 : 1;
dot.x += dot.xMove;
dot.y += dot.yMove;
// 绘制点
ctx.save();
ctx.beginPath();
ctx.arc(dot.x, dot.y, _this.size, 0, Math.PI * 5);
ctx.fillStyle = _this.color;
ctx.fill();
ctx.restore();
// 循环比对粒子间的距离
for (var i = 0; i < _this.newDots.length; i ++) {
var newDot = _this.newDots[i];
// 如果是第一个点,则跳过
if(newDot === dot || newDot.x === null || newDot.y === null) continue;
var xDistance = dot.x - newDot.x;
var yDistance = dot.y - newDot.y;
var distance = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
// 颜色深度
var deep = 0;
// 小于最小距离,则连线
if (distance <= newDot.max) {
// 附近的小球向鼠标位置移动
if(newDot === _this.coordinate && distance > (newDot.max / 2)) {
dot.x -= xDistance * 0.05;
dot.y -= yDistance * 0.05;
}
// 距离越近---值越大---颜色越深
deep = (newDot.max - distance) / newDot.max;
// 画线
ctx.save();
ctx.beginPath();
ctx.lineWidth = deep / 2;
var colorInfo = _this.colorCheck();
ctx.strokeStyle = "rgba(" + colorInfo[0] + ", " + colorInfo[1] + ", " + colorInfo[2] + "," + (deep + 0.4) + ")";
ctx.moveTo(dot.x, dot.y);
ctx.lineTo(newDot.x, newDot.y);
ctx.stroke();
ctx.restore();
}
}
// 将已经计算过的粒子删除,减少遍历的总数量
_this.newDots.splice(_this.newDots.indexOf(dot), 1);
});
window.requestAnimationFrame(function (obj) {
_this.draw(_this);
});
}
}
var moveBalls = new MoveBalls("#cs", {total: 66, color: "#00D0FF", size: 1});
</script>
</html>
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
字号
工作了有一段时间,基本上都在搞移动端的前端开发,工作的过程中遇到过很多问题,bug的解决方案,记录下来,以便后用!!!内容并不是很全,以后每遇到一个问题都会总结在这里,分享给大家!
一、meta标签相关知识
1、移动端页面设置视口宽度等于设备宽度,并禁止缩放。
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
2、移动端页面设置视口宽度等于定宽(如640px
),并禁止缩放,常用于微信浏览器页面。
<meta name="viewport" content="width=640,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
3、禁止将页面中的数字识别为电话号码
<meta name="format-detection" content="telephone=no" />
4、忽略Android平台中对邮箱地址的识别
<meta name="format-detection" content="email=no" />
5、当网站添加到主屏幕快速启动方式,可隐藏地址栏,仅针对ios的safari
-
<meta name="apple-mobile-web-app-capable" content="yes" />
-
<!-- ios7.0版本以后,safari上已看不到效果 -->
6、将网站添加到主屏幕快速启动方式,仅针对ios的safari顶端状态条的样式
-
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
-
<!-- 可选default、black、black-translucent -->
viewport模板
-
<!DOCTYPE html>
-
<html>
-
<head>
-
<meta charset="utf-8">
-
<meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
-
<meta content="yes" name="apple-mobile-web-app-capable">
-
<meta content="black" name="apple-mobile-web-app-status-bar-style">
-
<meta content="telephone=no" name="format-detection">
-
<meta content="email=no" name="format-detection">
-
<title>title</title>
-
<link rel="stylesheet" href="index.css">
-
</head>
-
-
<body>
-
content...
-
</body>
-
-
</html>
二、CSS样式技巧
1、禁止ios和android用户选中文字
.css{-webkit-user-select:none}
2、禁止ios长按时触发系统的菜单,禁止ios&android长按时下载图片
.css{-webkit-touch-callout: none}
3、webkit去除表单元素的默认样式
.css{-webkit-appearance:none;}
4、修改webkit表单输入框placeholder的样式
-
input::-webkit-input-placeholder{color:#AAAAAA;}
-
input:focus::-webkit-input-placeholder{color:#EEEEEE;}
5、去除android a/button/input
标签被点击时产生的边框 & 去除ios a
标签被点击时产生的半透明灰色背景
a,button,input{-webkit-tap-highlight-color:rgba(255,0,0,0);}
6、ios使用-webkit-text-size-adjust
禁止调整字体大小
body{-webkit-text-size-adjust: 100%!important;}
7、android 上去掉语音输入按钮
input::-webkit-input-speech-button {display: none}
8、移动端定义字体,移动端没有微软雅黑字体
-
/* 移动端定义字体的代码 */
-
body{font-family:Helvetica;}
三、其他技巧
1、手机拍照和上传图片
-
<!-- 选择照片 -->
-
<input type=file accept="image/*">
-
<!-- 选择视频 -->
-
<input type=file accept="video/*">
2、取消input在ios下,输入的时候英文首字母的默认大写
<input autocapitalize="off" autocorrect="off" />
3、打电话和发短信
-
<a href="tel:0755-10086">打电话给:0755-10086</a>
-
<a href="sms:10086">发短信给: 10086</a>
四、CSS reset
-
/* hcysun */
-
@charset "utf-8";
-
/* reset */
-
html{
-
-webkit-text-size-adjust:none;
-
-webkit-user-select:none;
-
-webkit-touch-callout: none
-
font-family: Helvetica;
-
}
-
body{font-size:12px;}
-
body,h1,h2,h3,h4,h5,h6,p,dl,dd,ul,ol,pre,form,input,textarea,th,td,select{margin:0; padding:0; font-weight: normal;text-indent: 0;}
-
a,button,input,textarea,select{ background: none; -webkit-tap-highlight-color:rgba(255,0,0,0); outline:none; -webkit-appearance:none;}
-
em{font-style:normal}
-
li{list-style:none}
-
a{text-decoration:none;}
-
img{border:none; vertical-align:top;}
-
table{border-collapse:collapse;}
-
textarea{ resize:none; overflow:auto;}
-
/* end reset */
五、常用公用CSS style
-
/* public */
-
-
/* 清除浮动 */
-
.clear { zoom:1; }
-
.clear:after { content:''; display:block; clear:both; }
-
-
/* 定义盒模型为怪异和模型(宽高不受边框影响) */
-
.boxSiz{
-
-webkit-box-sizing: border-box;
-
-moz-box-sizing: border-box;
-
-ms-box-sizing: border-box;
-
-o-box-sizing: border-box;
-
box-sizing: border-box;
-
}
-
-
/* 强制换行 */
-
.toWrap{
-
word-break: break-all; /* 只对英文起作用,以字母作为换行依据。 */
-
word-wrap: break-word; /* 只对英文起作用,以单词作为换行依据。*/
-
white-space: pre-wrap; /* 只对中文起作用,强制换行。*/
-
}
-
-
/* 禁止换行 */
-
.noWrap{
-
white-space:nowrap;
-
}
-
-
/* 禁止换行,超出省略号 */
-
.noWrapEllipsis{
-
white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
-
}
-
-
/* 文字两端对齐 */
-
.text-justify{
-
text-align:justify;
-
text-justify:inter-ideograph;
-
}
-
-
/* 定义盒模型为 flex布局兼容写法并让内容水平垂直居中 */
-
.flex-center{
-
display: -webkit-box;
-
display: -moz-box;
-
display: -ms-flexbox;
-
display: -o-box;
-
display: box;
-
-
-webkit-box-pack: center;
-
-moz-box-pack: center;
-
-ms-flex-pack: center;
-
-o-box-pack: center;
-
box-pack: center;
-
-
-webkit-box-align: center;
-
-moz-box-align: center;
-
-ms-flex-align: center;
-
-o-box-align: center;
-
box-align: center;
-
}
-
-
/* public end */
六、flex布局
1、定义弹性盒模型兼容写法
-
/*
-
box
-
inline-box
-
*/
-
display: -webkit-box;
-
display: -moz-box;
-
display: -ms-flexbox;
-
display: -o-box;
-
display: box;
2、box-orient 定义盒模型内伸缩项目的布局方向
-
/**
-
* vertical column 垂直
-
* horizontal row 水平 默认值
-
*/
-
-webkit-box-orient: horizontal;
-
-moz-box-orient: horizontal;
-
-ms-flex-direction: row;
-
-o-box-orient: horizontal;
-
box-orient: horizontal;
3、box-direction 定义盒模型内伸缩项目的正序(normal默认值)、倒叙(reverse)
-
/* Firefox */
-
display:-moz-box;
-
-moz-box-direction:reverse;
-
/* Safari、Opera 以及 Chrome */
-
display:-webkit-box;
-
-webkit-box-direction:reverse;
4、box-pack 对盒子水平富裕空间的管理
-
/*
-
start
-
end
-
center
-
justify
-
*/
-
-webkit-box-pack: center;
-
-moz-box-pack: center;
-
-ms-flex-pack: center;
-
-o-box-pack: center;
-
box-pack: center;
5、box-pack 对盒子垂直方向富裕空间的管理
-
/*
-
start
-
end
-
center
-
*/
-
/* box-align */
-
-webkit-box-align: center;
-
-moz-box-align: center;
-
-ms-flex-align: center;
-
-o-box-align: center;
-
box-align: center;
6、定义伸缩项目的具体位置
-
/*-moz-box-ordinal-group:1;*/ /* Firefox */
-
/*-webkit-box-ordinal-group:1;*/ /* Safari 和 Chrome */
-
.box div:nth-of-type(1){-webkit-box-ordinal-group:1;}
-
.box div:nth-of-type(2){-webkit-box-ordinal-group:2;}
-
.box div:nth-of-type(3){-webkit-box-ordinal-group:3;}
-
.box div:nth-of-type(4){-webkit-box-ordinal-group:4;}
-
.box div:nth-of-type(5){-webkit-box-ordinal-group:5;}
7、定义伸缩项目占空间的份数
-
-moz-box-flex:2.0; /* Firefox */
-
-webkit-box-flex:2.0; /* Safari 和 Chrome */
-
-
.box div:nth-of-type(1){-webkit-box-flex:1;}
-
.box div:nth-of-type(2){-webkit-box-flex:2;}
-
.box div:nth-of-type(3){-webkit-box-flex:3;}
-
.box div:nth-of-type(4){-webkit-box-flex:4;}
-
.box div:nth-of-type(5){-webkit-box-flex:5;}
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
打电话分下面4步:
ajax也分下面4步:
下面是原生js写ajax的具体写法 :
但是,不能每次用ajax的时候都写那么多代码,要把这段ajax代码封装起来,方便使用。
封装ajax代码如下:
将封装的ajax调用:
原生js写ajax可以类比打电话
1.拿出手机
2.拨号
3.说话
4.听对方说话
1.创建ajax对象
2.连接到服务器
3.发送请求(告诉服务器我要什么文件)
4.接收返回值
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
遮罩层为一张边框样式图(如下图):
边框样式遮罩层显示在最上方,然后是中间的列表,最下层是一个透明黑色遮罩层,滚动鼠标滚轮,能控制列表滚动
注册最上面遮罩层的滚动事件,拿到滚动滚动方向,然后控制列表滚动的方向和距离
效果
实现原理
上代码
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务注册事件 /**
* 增加滚轮滚动事件(暂时只实现了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");
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
大家都说前端写页面较多,几乎用不到算法。本文愿从弹幕设计这个场景来描述算法在前端中的应用,我们先来看下实现效果:
开场之前我们先来描述弹幕开发的难度,再集中精力描述算法设计的思路。
* 如何保证不同字号的弹幕不碰撞
***如何保证不同字号的弹幕不碰撞***
如果弹幕采用相同的字号,碰撞的问题处理起来比较简单,只要考虑相邻弹幕的播放速度和偏移的位置就可以计算出来。然而使用不同字号的弹幕处理起来就麻烦了许多,弹幕的起始位置不可以线性的增加,比如第一行放了字幕,接下来的字幕可以按顺序从上至下依次放置即可。
***弹幕的位置计算***
只有设计好弹幕的初始位置,才可以动态、的管理不同字号弹幕的碰撞问题。打个比方,我们通过接口获取了2秒之内的弹幕数据1000条,每个字幕的长度、速度、字号都不同,怎么管理这些弹幕,示意图如下:
这是第一种情况,按照从上到啊的顺序依次摆放以后会有几个问题:
一系列问题就不统统列举出来了,基于这个背景我们结合数学建模的思维方式,找到了弹幕场景相似度非常高的机场运营。我们可以把弹幕当做飞机,每个时间段播放多少弹幕和机场每个时间段放飞多少飞机一个道理。
首都国际机场一共有3条跑道,两条4E级跑道、一条4F级跑道,2016年的吞吐量为9000万人次。它的运行机制就是所有飞机通过搭台有顺序的共用3条跑道来完成运输任务的。
同理,我们也设计了几个个角色:一个是轨道(跑道)、一个是调度(塔台)、一个是弹幕(飞机),我们为每个角色设计一个类分为为Track、Main、Bullet。
* 轨道
其次我们来回忆下机场的工作流程:
按照这个思路,我们的弹幕工作流程:
关于轨道的基本原理我们整理清楚了,当然还有不少细节比如如何和调度通信、如何和弹幕通信以及虚拟轨道检测算法等。有兴趣的同学可以参考代码吧。https://github.com/bytedance/xgplayer/blob/master/packages/xgplayer/src/control/makeBullet.js
* 弹幕
在弹幕启动之后,首先要检查本地是否已有缓存数据,没有的话直接请求数据并缓存,然后执行数据读取,首次过滤数据进入弹幕队列,同时启动定时器。弹幕队列的数据会定期请求轨道,检测队列里的弹幕是否可以进入,一旦确认后轨道做好登记,弹幕就可以进入播放器开启动画播放了。定时器每隔2秒就会再次更新数据进入到弹幕队列(这块不同的业务可以定制不同的规则)。弹幕播放结束后会通知调度和轨道,调度会在弹幕队列中移除该弹幕实例,轨道也会移除该弹幕实例的轨道占用。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
图1.1 弹幕效果
* 弹幕的位置计算
* 弹幕的速度控制及动画实现
* 弹幕与视频的同步
图2.1 弹幕管理示意图
1. 弹幕五、六、七该怎么计算位置,按top值循环取模+累加吗?
2. 当弹幕一或者弹幕三足够长的时候,如何准时的跳过当前位置计算?
3. 当前屏幕的弹幕播放结束,如何再计算的时候利用空出来的位置
4. 空出的位置是否满足当前弹幕的高度
5. ……
轨道这个角色很重要,它可以解决弹幕位置计算、速度控制、碰撞检测问题。
首先,我们要来初始化轨道。通俗的说我们要修建几个跑道呢,我们不是实物,可以动态调整轨道的 数量,计算的原则:
轨道数量 = 播放器有效高度 / 设备基准字号
* 播放器有效高度:播放器的实际高度减去控制条的高度,因为弹幕不可以遮挡控制条。
* 设备基准字号:移动端是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 轨道可用性计算示意图
弹幕基本是实现“飞机”的角色,我们要求它具有自身的属性和方法。比如调度中心通过id能拿到它所有的基本信息,轨道控制也可以通过弹幕进行检查和更新。当然弹幕也必须具备状态自动更新、移动、播放结束通知、自动销毁等功能。
* 调度
调度就是搭台的化身,承接着轨道、弹幕的控制,也保持着与播放器的步调一致。它的职责如下:
1. 播放器交互控制
2. 弹幕队列控制
3. 自身状态更新
4. 数据格式转换
5. 动画执行
还是直接用流程图来描述更直接些:
图2.4 弹幕运行机制流程图
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
一.写在前面
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)点击提交,填写小程序相关信息,就可以提交审核了哦。
注意:分类最好填写准确,这样才能更快的通过审核哦。我这个小程序一天半时间过审上线的
至此,我就把两天开发内碰到的坑和注意点都过了一遍,据说还有更多的坑,等之后更深入的开发再继续研究咯。
小程序学习资料
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
mongoose保存数据:
如果成功,则可以获取到保存在数据库的值,但是如果保存数据失败,则会抛出异常,好在save可以传入一个回调函数,用法如下:
我们希望根据结果获取到不同的值,但是此时save返回的是undefined,因为save中的回调函数是一个异步操作
使用try catch:
注意:在async函数中才可以这么使用,因为await只能用在async函数中
示例:(注册功能)
user.model.js
service.js
controller.js
const save = new Model(data).save()
const save = new Model(data).save((err, result)=>{ if(err){ // 保存失败执行的操作
}else { // 保存成功执行的操作
}
})
解决方法:
try{
const save = await new Model(data).save();
// 保存成功执行的操作 return ... }catch(err){
// 保存失败执行的操作 return ... }
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);
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();
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务const server = require("./server); async login(){ // 首先获取请求中携带的用户信息 const result = await server.login(user);
if(result.success){ // 注册成功执行的操作 }else { // 注册失败执行的操作 }
}
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
图片标签<img src=路径属性 alt:加载失败后显示的文本 width:指定图片宽度 height:指定图片高度> 单位: px
绝对路径
同级:直接写文件名.后缀名
<br>标签:换行 <img>标签为内联标签所以不换行,所以添加<br>标签换行。
页面是这样的:
图片标签
路径属性
E:\ruanjian\软件\环境\images
相对路径:相对于主文件位置的路径
引用文件方式:
上级:../文件名.后缀名 ../返回上一级文件夹
下级:文件夹/文件名.后缀名
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
@(Mob前端-冬晨)[JavaScript|技术分享|懒加载]
前端工作中,界面和效果正在变得越来越狂拽炫酷,与此同时性能也是不得不提的问题。有些项目,页面长,图片多,内容丰富。像商城页面。如果同步加载时一次性加载完毕,那肯定是要等到花都谢了,loading转的人都崩溃~。今天分享的是Lazyload技术 是一种延迟加载技术。让页面加载速度快到飞起、减轻服务器压力、节约流量、提升用户体验。
页面较长,屏幕的可视区域有限。
简要流程
.
不做任何处理直接监听scroll必然导致在滚动鼠标滚轮的时候,过于频繁的触发处理函数。
使用节流函数
滚动时间
结语:历史潮流浩浩荡荡,前端技术的发展也是日新月异。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
前端性能优化之Lazyload
Lazyload 简介
一、实现思路
不设置页面中img标签
的src属性
值或者将其指向同一个占位图。
图片的实际地址存在img标签
自定义的一个属性中,如:“data-url”。
监听scroll
,滚动到某个位置时,动态的将url替换成实际的“data-url”。
二、上代码
<!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>
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','');
}
}
};
.
.
谢谢观看,搞定收工0.0~~~这样草草了事总是不好的
三、再优化
如果刚巧在处理函数中有大量的操作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);
}
}
}
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);
least
长于600,调用compare,否则延迟350ms执行。
这样相对于直接onscroll性能得到更进一步提升,在功能上也没有什么问题。
不同的业务场景调整一下delay和least就可以。
不断通过一个个小的技术点深入探究,以加深自己对js这门语言的理解。
温故知新,回顾旧的内容,学习新的内容和特性,更好的适应工作中的需求。
蓝蓝设计的小编 http://www.lanlanwork.com