觀視訊《月薪4萬的程式員有多強?半小時原生JS開發打氣球遊戲,征服現場數萬人!》
清晨,日常打開B站,被首頁此視訊的标題所吸引,雖一看就是标題黨,但還是沒能抑制住好奇心。
視訊共計60*3分鐘,學習到了很多東西。其中後半部分有許多正三觀的見解也非常認同。
視訊位址:https://www.bilibili.com/video/av15152538/
線上試玩:http://sandbox.runjs.cn/show/luderhbq
參考視訊寫的demo:https://coding.net/u/yimocoding/p/WeDemo/git/tree/氣球大戰
看了視訊,自己來實作試試
花了半天的時間,人生中的第二個遊戲終于完成了,想起第一次做拼圖遊戲也已經是3年前了~
來吧,試玩一下,看能消滅多少個氣球【笑哭】:http://sandbox.runjs.cn/show/luderhbq
然後,一起來一步步建構自己的【氣球大戰】(文中代碼為核心代碼,後續有優化,故非完整代碼),可以在runjs中去檢視
1.用css3畫一個氣球
看視訊的時候覺得自己這個會那個也會,寫代碼的時候才發現沒有智能提示啥都不會,打錯單詞的次數不是一次兩次~
- transform:http://www.runoob.com/cssref/css3-pr-transform.html
- 圓角邊框:http://www.runoob.com/cssref/css3-pr-border-radius.html
氣球效果預覽
css代碼
//html→→_→→
<div class="balloon"></div>
body{margin:0;padding:0}
.balloon{width:150px;height:150px;position:absolute;left:0;top:0;background-color:pink;border-radius:50% 50% 10% 50%;transform:rotate(45deg);box-shadow:1px 1px 20px 20px red inset}
.balloon:after{width:20px;height:20px;content:"";display:block;background:0 0;position:absolute;right:-15px;bottom:-15px;border-left:5px solid red;border-top:5px solid red}
.balloon:before{width:2px;height:50px;content:"";display:block;background:pink;position:absolute;right:-10px;top:100%;margin-top:-16px;transform:rotate(-45deg)}
2.随機建立氣球
首先定義了一些變量
var bnElements=[];//存放所有氣球
var random=Math.random;//随機函數
var wW=window.innerWidth;//視窗寬度
var wH=window.innerHeight;//視窗高度
var ballW=160;//氣球的寬度
var ballH=300;//氣球的寬度
var minSpeed=3;//最小速度,每次向上移動至少3px
var speedNum=8;//速度的定量
var defBnNumber=10;//初始化氣球
首先編寫并調用初始化方法生成氣球
生成氣球代碼
init(defBnNumber);
//初始化氣球
function init(num){
//建立一個虛拟文檔節點
var docFragment=document.createDocumentFragment();
for(var i=0;i<num;i++){
var bnElement=document.createElement('div');
bnElement.className='balloon';
//速度随機,限定最小值
var speed=Math.max(minSpeed,~~(random()*speedNum));
bnElement.setAttribute('speed',speed);//~~取整 移動速度
bnElement.setAttribute('id','ball-'+(bnElements.length+i+1));
//分散排列
var x=(~~(random()*wW))-ballW;
x=Math.max(0,x);
bnElement.style.left=x+'px';
bnElement.style.top=wH+'px';//露一點出來
//1.先将建立的氣球放入建立的虛拟文檔節點
docFragment.appendChild(bnElement);
bnElements.push(bnElement);
}
//2.将虛拟文檔節點添加到body中
document.body.appendChild(docFragment);
}
效果預覽
3.氣球向上移動
建立一個move方法并在初始化後調用
氣球移動代碼
move();//移動氣球 隻需要調用一次即可
function move(){
var bl=bnElements.length
for(var i=0;i<bl;i++){
var currentElement=bnElements[i]
if(currentElement==null){
continue;
}
var offsetTop=currentElement.offsetTop;
if(offsetTop>-ballH){//視窗中
var speed=currentElement.getAttribute('speed');
currentElement.style.top=offsetTop-speed+'px'
}
else{
//移除dom節點
document.body.removeChild(currentElement);
//移除數組中
bnElements.splice(i,1);
init(1);
}
}
setTimeout(move,1000/30);
}
4.點選氣球,氣球消失
發現顔色有點醜~~遂改。
氣球消失代碼
bindClick();
//綁定點選氣球事件
function bindClick(){
document.body.addEventListener('click',function(e){
if(e.target.className=='balloon'){
boom.call(e.target,function(){
e.target.parentNode.removeChild(e.target);
bnElements.splice(bnElements.lastIndexOf(e.target),1);
init(1);
});
}
});
}
function boom(callback){
//var that=this; //替換了上下文,但是沒有使用this的意義.
var speed=this.getAttribute('speed');
this.timer=setInterval(function(){
this.style.opacity=0.1*(speed--)
console.log(this.offsetWidth);
if(speed<1){
callback&&callback();
clearInterval(this.timer);
}
}.bind(this),1000/30);
}
核心代碼終于寫完,在我的純靜态工具站點生成二維碼掃一掃,在我的小米手機上玩了玩,ok正常,然後再新入手的ipad中試了試。。。擦。坑爹呢,點了咋沒反應啊。
好吧,為了ipad能玩,強忍着淚水(餓的)解決了iOS的safari相容問題~
5.解決遇到的safari浏覽器相容問題
-
問題一:Safari中單擊事件不能綁定到document.body上~~,因為無效~
解決方法:給元素加了個父級,若click事件有問題則還需要将click換成touchend
-
問題二:transform變換z-index層級渲染異常
解決方法:未變換的元素上添加樣式:
參考文章:http://www.zhangxinxu.com/wordpress/2016/08/safari-3d-transform-z-index/transform: translateZ(120px);
總結
get了幾個以前不知道沒用過的新技能
-
文檔片段
當需要将一堆節點添加到dom中可以使用
建立虛拟文檔節點,讓後将節點先添加到此虛拟節點中,再将此節點追加到指定元素,能夠降低dom渲染次數document.createDocumentFragment();
-
使用位運算符取整
取0-9的随機數
//~~(Math.random()*10)
大于等于 0.0 且小于 1.0Math.random()
-
Math.max()
可以用來限定邊界值Math.min()
- setInterval問題:
- 可能會丢幀(浏覽器的重新整理頻率為60FPS,一秒最大可以重繪60次),故理論上setinterval()間隔時間大于1000/60就不會參數丢幀的情況
- 時間線偏移(甚至重疊沒執行完就執行下一次任務了),若需要每次都執行完才執行下次任務則使用
setTimeout+遞歸
-
this的傳遞(可以使用bind()去綁定this,不能使用call,會提示沒有權限)
傳遞this到
中:setInterval
setInterval(function(){}.bind(this),1000/30)
- 值的相等判斷使用
會比===
性能好一點,大部分情況應當使用==
===
-
判斷回調函數并執行回調函數
以前我是這樣寫的:if(typeof(callback)==='function')callback();
視訊中有用短路運算符實作即:
callback&&callback()
- 踩了踩safari的坑
- 最可怕的事情,不是别人比你強,而是比你強的人比你還努力!!!
作者:易墨
個人小站:http://www.yimo.link
純靜态工具站點:http://tools.yimo.link/
說明:歡迎拍磚,不足之處還望園友們指出;
迷茫大概是因為想的太多做的太少。