方的风太大,吹得窗户咚咚作响,小白自从上午用了jQuery事件后,一直沉浸在鼠标控制容器内容的练习里面,周围无论多大的噪音也干扰不了他。中午太阳很好,低头族们又来到小白旁边向阳的窗口扎堆晒太阳。其中一人无意间看到了小白真正摆弄的页面,感到很好奇,说道:“哇!小白,这是你做的么?”
小白得意的说道:“必须的!”
“小白你真了不起,几天不见居然都会高科技了!”,“哇!小白,真佩服你,你居然会写程序!”。。。。。。
正当小白沉浸在赞美声中无法自拔的时候,小白的身旁响起了老朱的声音:“小白!醒醒!今天哥再告你个好玩的知识!”
“好玩的知识?”,小白眼里放出了惊喜的目光。
“对,通过jQuery可以改变元素的css样式,这个好玩吧!你用jQuery实现鼠标移入移出的功能了吧?让我看看”
“矮油!不错哦~!现在咱把鼠标以上以后的处理改一下,不要更改它的html内容了,变成更改CSS样式。更改CSS样式通过css(样式属性名,样式属性值进行更改,比如更改main里面文本的颜色,我们可以这样写:$("#main").css("color","#F00");”
“现在执行我们看一下效果吧”
“这个效果太棒了,可是鼠标移出以后怎么恢复呢?”
“你在移出的代码里面增加一个更改文本颜色就可以了!试试看!”
“成功了,是不是所有的样式都可以更改?”
“那当然,不过有个知识点你得了解一下,在css里面很多样式属性的默认值是none,比如容器main的border属性设置为none的效果跟没给容器设置border的效果是一样的。具体哪些css样式的属性默认值是none,你可以在一个空网页中写一个div标签,不要给它设置任何css样式,然后通过console.log($('div').css('属性名'))在控制台看看它的默认值。这个工作你有时间了自己测试一下,我就不多说了,现在你做这样一个功能,鼠标移到main容器上时改变容器的高度、背景色、行高、文字大小,移出后恢复原来的状态。”
“好的,我试试!”
二十分钟后小白找到老朱,“做好了!”
“很好,小白。不过这个方法虽好,可有时需要改变的样式太多,以至于我们会写很多行代码。还有一个方法可以通过添加、删除class或者直接更改容器的class属性值进行设置。添加class使用addClass("类名"),删除class使用removeClass("类名")。我们可以这样来做!”
“你也可以直接更改div标签上的class属性值,更改属性我近期会跟你说怎么做,你现在会这两种更改样式的方法就可以了。添加和删除class会精简js代码的行数,直接更改css样式的属性值呢又很方便,在真正使用的时候你要学会灵活运用。好了你可以自己练习了~~”
想学H5的朋友可以关注老炉,您的关注是我持续更新《小白H5成长之路》的动力!
奖和开盲盒性质一样的都是通过ajax读取后台的随机数据。
图1 转轮盘抽奖
图2 转轮盘抽奖结果
1、转轮盘
本来是想直接绘图实现轮盘,但是没有找到怎么填充文字,只好把轮盘弄成了背景图,通常用于游戏抽道具,商城积分抽奖,公司年末员工抽奖
html代码
<style>
.box{
width:500px;height:500px;border:0px solid #DDD;margin:100px;position:relative;
}
.beij{
background:url(cjbg.jpg) no-repeat center center;width:100%;height:100%;
}
.pointer{
cursor:pointer;position:absolute;top:50%;left:50%;margin-left:-40px;margin-top:-48px;background:url(c1.png) no-repeat center center;width:80px;height:96px;z-index:21;
}
</style>
<div class='box' >
<div class='beij'></div>
<div class='pointer'></div>
</div>
js代码
<script>
$(document).ready(function() {
var time=0.4;//转一圈所需时间 s
var count=10;//默认多转几圈
/*
var angle=new Array();
angle[0]=23;
angle[1]=53;
angle[2]=83;
angle[3]=110;
angle[4]=133;
angle[5]=163;
angle[6]=223;
*/
var i=1;
$(".pointer").click(function(){
$.ajax({
url: "/public/man/index.php/api/choujiang",
data:'',
type: "post",
dataType: "json",
success: function(result) {
//console.log(result.msg);
$('.beij').css({'transform':"rotate("+(i*count*360+result.angle)+"deg)","transition":" All "+(time*(5+result.angle/360))+"s ease-in-out"});
//弹窗提示
//setTimeout("alert('"+result.msg+"');",time*1000*(5+result.angle/360));
setTimeout("console.log('"+result.msg+"');",time*1000*(5+result.angle/360));
}
})
i++;
});
});
</script>
说明:
后台接口程序
public function choujiang(){
/*
id 奖品编号
title 中奖提示
prec 中奖概率
angle 旋转角度
*/
$arr[0]=array('id'=>1,'title'=>'恭喜抽中一等奖:苹果手机一部!','prec'=>1,'angle'=>23);
$arr[1]=array('id'=>2,'title'=>'恭喜抽中二等奖:Ipad','prec'=>2,'angle'=>68);
$arr[2]=array('id'=>3,'title'=>'恭喜抽中三等奖:','prec'=>25,'angle'=>113);
$arr[3]=array('id'=>4,'title'=>'恭喜抽中四等奖','prec'=>50,'angle'=>155);
$arr[4]=array('id'=>5,'title'=>'恭喜抽中五等奖','prec'=>80,'angle'=>202);
$arr[5]=array('id'=>6,'title'=>'恭喜抽中六等奖','prec'=>150,'angle'=>245);
$arr[6]=array('id'=>7,'title'=>'恭喜抽中七等奖','prec'=>240,'angle'=>290);
$arr[7]=array('id'=>8,'title'=>'获得50元优惠券,还需加油哦!','prec'=>380,'angle'=>337);
//中奖几率求和
$cmun=0;
for($i=0;$i<=count($arr)-1;$i++){
$cmun+=$arr[$i]['prec'];
}
//中奖随机数
$smrand=mt_rand(1,$cmun);
$this->getRand(1,0,$arr,count($arr),$smrand);
}
public function getrand($m,$im,$arr,$count,$smrand){
/*
$m 起始数
$im 第几个数组元素
$count 数组总得元素个数
$arr 原始数组
$smrand 中奖随机数
*/
//已经中奖
if($smrand>=$m&&$smrand<=$arr[$im]['prec']+$m-1){
//中奖返回
$msg=array('msg'=>$arr[$im]['title'],'angle'=>$arr[$im]['angle'],'smrand'=>$smrand);
exit(json_encode($msg,JSON_UNESCAPED_UNICODE));
}else{
//最后一个不需要判断 直接返回
if($im+1==$count-1){
$msg=array('msg'=>$arr[$count-1]['title'],'angle'=>$arr[$count-1]['angle'],'smrand'=>$smrand);
exit(json_encode($msg,JSON_UNESCAPED_UNICODE));
}else{
//起始数字
$start=$arr[$im]['prec']+$m;
//递归 再次调用数组 读取下一个数组元素
$this->getrand($start,$im+1,$arr,$count,$smrand);
}
}
}
说明:
2、随机抽取一个幸运员工
点击开始抽奖,单行文本框循环显示员工,抽奖按钮文字变为停止,点击停止的时候,抽中的员工显示在获奖名单。
图3 随机抽取幸运员工
html代码
<style>
body{
background:#DDD;
}
.title{
height:40px;line-height:40px;font-size:14px;font-weight:bold;margin:100px 0 0 100px;
}
.box{
width:700px;height:200px;border:1px solid #EEE;border-radius:8px;background:#FFF;margin-left:100px;
}
.box li{height:30px;line-height:30px;}
.cjbtn{
margin:10px 0 0 100px;
}
#ygname{
padding:3px 5px;;
}
</style>
<div class='title'>获奖名单</div>
<div class='box' >
<ul>
</ul>
</div>
<div class='cjbtn'><input type='text' id='ygname' /> <button id='choujiang'>开始抽奖</button></div>
js代码
<script>
var t;
var yuangong=new Array();
$.ajax({
url: "/public/man/index.php/api/yuangong",
data:'',
type: "post",
dataType: "json",
success: function(result) {
yuangong=result.msg
}
})
$(document).ready(function() {
$("#choujiang").click(function(){
if($(this).html()=='开始抽奖'){
if(yuangong.length>=3){
$(this).html("停止");
start();
}
}else{
$(this).html("开始抽奖");
stop();
}
});
});
function start() {
num=Math.floor(Math.random() * (yuangong.length-1));
$('#ygname').val(yuangong[num]['title']);
t=setTimeout(start, 0);
}
function stop() {
clearInterval(t);
//数组中删除中奖员工信息防止重复中奖
yuangong.splice($.inArray(yuangong[num], yuangong), 1);
$(".box ul").append("<li>"+$('#ygname').val()+"</li>");
}
</script>
说明:
num=Math.floor(Math.random() * (yuangong.length));
综上:num得到的是0到数组下标的随机数。
clearInterval(t):用于停止t=setTimeout(start, 0);
后台php接口程序
public function yuangong(){
$yuangong[0]=array('id'=>1,'title'=>'业务部【张三】');
$yuangong[1]=array('id'=>2,'title'=>'技术部【李四】');
$yuangong[2]=array('id'=>3,'title'=>'技术部【逍遥】');
$yuangong[3]=array('id'=>4,'title'=>'会计部【薛嫣】');
$yuangong[4]=array('id'=>5,'title'=>'行政部【王五】');
$yuangong[5]=array('id'=>6,'title'=>'行政部【王天林】');
$yuangong[6]=array('id'=>7,'title'=>'行政部【李笑和】');
$msg=array('msg'=>$yuangong);
exit(json_encode($msg,JSON_UNESCAPED_UNICODE));
}
3、随机抽取多个幸运员工
没有想到什么效果,只是单纯地获取了随机数
html代码
<style>
body{
background:#DDD;
}
.title{
height:40px;line-height:40px;font-size:14px;font-weight:bold;margin:100px 0 0 100px;
}
.box{
width:700px;height:200px;border:1px solid #EEE;border-radius:8px;background:#FFF;margin-left:100px;
}
.box li{height:30px;line-height:30px;}
.cjbtn{
margin:10px 0 0 100px;
}
#ygname{
padding:3px 5px;;
}
</style>
<div class='title'>获奖名单</div>
<div class='box' >
<ul>
</ul>
</div>
<div class='cjbtn'> <button id='choujiang'>开始抽奖</button></div>
js代码
<script>
var yuangong=new Array();
var ygstr='';//存取获奖员工
var ygrs=5;//一次抽几个
var t;
$.ajax({
url: "/public/man/index.php/api/yuangong",
data:'',
type: "post",
dataType: "json",
success: function(result) {
yuangong=result.msg
}
})
$(document).ready(function() {
$("#choujiang").click(function(){
if(yuangong.length>=ygrs){
start(1);
}
});
});
function start(ms) {
//ms 第几次获取员工信息
num=Math.floor(Math.random() * (yuangong.length));
console.log(num);
ygstr+="<li>"+yuangong[num]['title']+"</li>";
if(ms>=ygrs){
$(".box ul").html(ygstr);
ygstr="";
}else{
yuangong.splice($.inArray(yuangong[num], yuangong), 1);
start(ms+1);
}
}
</script>
4、在线开盲盒
需要我们点击抽奖的时候通过ajax读取后台获得的盲盒信息,直接显示到前台,前台显示同上边的,都是一样,说一下后台程序。
使用array_rand().随机获取几个数组元素
array_rand($arr,$count).用法
返回值是原数组的下标。
public function manghe(){
$goods[0]=array('id'=>1,'title'=>'手机');
$goods[1]=array('id'=>2,'title'=>'毛绒玩具');
$goods[2]=array('id'=>3,'title'=>'化妆品');
$goods[3]=array('id'=>4,'title'=>'啫喱水');
$goods[4]=array('id'=>5,'title'=>'面膜');
$goods[5]=array('id'=>6,'title'=>'学习用品');
$goods[6]=array('id'=>7,'title'=>'电脑');
$getarr=array_rand($goods,3);
$i=0;
foreach($getarr as $k){
$rearr[$i]=$goods[$k];
$i++;
}
$msg=array('msg'=>$rearr);
exit(json_encode($msg,JSON_UNESCAPED_UNICODE));
}
如果包含特殊奖项,需要满足抽奖多少次,一定抽中,可以达到抽奖次数以后在array_rand内随机数减一,然后把大奖塞进该次抽奖的返回信息。
array_push($rearr,$a)用法:
$tebie[999]=array('id'=>999,'title'=>'特别大奖');
$goods[0]=array('id'=>1,'title'=>'手机');
$goods[1]=array('id'=>2,'title'=>'毛绒玩具');
$goods[2]=array('id'=>3,'title'=>'化妆品');
$goods[3]=array('id'=>4,'title'=>'啫喱水');
$goods[4]=array('id'=>5,'title'=>'面膜');
$goods[5]=array('id'=>6,'title'=>'学习用品');
$goods[6]=array('id'=>7,'title'=>'电脑');
$getarr=array_rand($goods,3);
$i=0;
foreach($getarr as $k){
$rearr[$i]=$goods[$k];
$i++;
}
array_push($rearr,$tebie[999]);
dump($rearr);
exit;
输出结果:
前面一篇文章:「高频面试题」浏览器从输入url到页面展示中间发生了什么 中,我们有对浏览器的渲染流程做了一个概括性的介绍,今天这篇文章我们将深入学习这部分内容。
对于很多前端开发来说,平常做工主要专注于业务开发,对浏览器的渲染阶段可能不是很了解。实际上这个阶段很重要,了解浏览器的渲染过程,能让我们知道我们写的HTML、CSS、JS代码是如何被解析,并最终渲染成一个页面的,在页面性能优化的时候有相应的解决思路。
我们先来看一个问题:
HTML、CSS、JS文件在浏览器中是如何转化成页面的?
如果你回答不上来,那就往下看吧。
按照渲染的时间顺序,渲染过程可以分为下面几个子阶段:构建DOM树、样式计算、布局阶段、分层、栅格化和合成显示。
下面详细看下每个阶段都做了哪些事情。
HTML文档描述一个页面的结构,但是浏览器无法直接理解和使用HTML,所以需要通过HTML解析器将HTML转换成浏览器能够理解的结构——DOM树。
HTML文档中所有内容皆为节点,各节点之间有层级关系,彼此相连,构成DOM树。
构建过程:读取HTML文档的字节(Bytes),将字节转换成字符(Chars),依据字符确定标签(Tokens),将标签转换成节点(Nodes),以节点为基准构建DOM树。参考下图:
打开Chrome的开发者工具,在控制台输入 document 后回车,就能看到一个完整的DOM树结构,如下图所示:
在控制台打印出来的DOM结构和HTML内容几乎一样,但和HTML不同的是,DOM是保存在内存中的树状结构,可以通过JavaScript来查询或修改其内容。
样式计算这个阶段,是为了计算出DOM节点中每个元素的表现样式。
CSS样式可以通过下面三种方式引入:
和HTML一样,浏览器无法直接理解纯文本的CSS样式,需要通过CSS解析器将CSS解析成 styleSheets 结构,也就是我们常说的 CSSOM树。
styleSheets结构同样具备查询和修改功能:
document.styleSheets
属性值标准化看字面意思有点不好理解,我们通过下面一个例子来看看什么是属性值标准化:
在写CSS样式的时候,我们在设置color属性值的时候,经常会用white、red等,但是这种值浏览器的渲染引擎不容易理解,所以需要将所有值转换成渲染引擎容易理解的、标准化的计算值,这个过程就是属性值标准化。
white标准化后的值为 rgb(255, 255, 255)
完成样式的属性值标准化后,就需要计算每个节点的样式属性,这个阶段CSS有两个规则我们需要清楚:
样式计算阶段是为了计算出DOM节点中每个元素的具体样式,在计算过程中需要遵守CSS的继承和层叠两个规则。
该阶段最终输出的内容是每个DOM节点的样式,并被保存在 ComputedStyle 的结构中。
经过上面的两个步骤,我们已经拿到了DOM树和DOM树中元素的样式,接下来需要计算DOM树中可见元素的几何位置,这个计算过程就是布局。
在DOM树中包含了一些不可见的元素,例如 head 标签,设置了 display:none 属性的元素,所以我们需要额外构建一棵只包含可见元素的布局树。
构建过程:从DOM树的根节点开始遍历,将所有可见的节点加到布局树中,忽略不可见的节点。
到这里我们就有了一棵构建好的布局树,就可以开始计算布局树节点的坐标位置了。从根节点开始遍历,结合上面计算得到的样式,确定每个节点对象在页面上的具体大小和位置,将这些信息保存在布局树中。
布局阶段的输出是一个盒子模型,它会精确地捕获每个元素在屏幕内的确切位置与大小。
现在我们已经有了布局树,也知道了每个元素的具体位置信息,但是还不能开始绘制页面,因为页面中会有像3D变换、页面滚动、或者用 z-index 进行z轴排序等复杂效果,为了更方便实现这些效果,渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)。
在Chrome浏览器中,我们可以打开开发者工具,选择 Elements-Layers 标签,就可以看到页面的分层情况,如下图所示:
浏览器的页面实际上被分成了很多图层,这些图层叠加后合成了最终的页面。
到这里,我们构建了两棵树:布局树和图层树。下面我们来看下这两棵树之间的关系:
正常情况下,并不是布局树的每个节点都包含一个图层,如果一个节点没有对应的图层,那么这个节点就从属于父节点的图层。
那节点要满足什么条件才会被提升为一个单独的图层?只要满足下面其中一个条件即可:
构建好图层树之后,渲染引擎就会对图层树中的每个图层进行绘制。
渲染引擎实现图层绘制,会把一个图层的绘制拆分成很多小的绘制指令,然后将这些指令按照顺序组成一个绘制列表。
绘制一个图层时会生成一个绘制列表,这只是用来记录绘制顺序和绘制指令的列表,实际上绘制操作是由渲染引擎中的合成线程来完成的。
通过下图来看下渲染主线程和合成线程之间的关系:
当图层的绘制列表准备好后,主线程会把该绘制列表提交给合成线程,合成线程开始工作。
首先合成线程会将图层划分为图块(tile),图块大小通常是 256256 或者 512512。
然后合成线程会按照视口附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的。所谓栅格化,是指将图块转换为位图。而图块是栅格化执行的最小单位。渲染进程维护了一个栅格化的线程池,所有的图块栅格化都是在线程池内执行的,运行方式如下图所示:
一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。
浏览器进程里面有一个名字叫做 viz 的组件,用来接收合成线程发过来的 DrawQuad 命令,然后根据命令执行。 DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。
多年开发老码农福利赠送:网页制作,网站开发,web前端开发,从最零基础开始的的HTML+CSS+JavaScript。jQuery,Vue、React、Ajax,node,angular框架等到移动端小程序项目实战【视频+工具+电子书+系统路线图】都有整理,需要的伙伴可以私信我,发送“前端”等3秒后就可以获取领取地址,送给每一位对编程感兴趣的小伙伴
一个完整的渲染流程可以总结如下:
渲染过程中还有两个我们经常听到的概念:重排和重绘。在这篇文章中就不细说了,下一篇文章再详细介绍。
*请认真填写需求信息,我们会在24小时内与您取得联系。