天天看點

看了180分鐘的視訊,寫了半天的代碼

觀視訊《月薪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層級渲染異常

    解決方法:未變換的元素上添加樣式:

    transform: translateZ(120px);

    參考文章:http://www.zhangxinxu.com/wordpress/2016/08/safari-3d-transform-z-index/

總結

get了幾個以前不知道沒用過的新技能

  • 文檔片段

    當需要将一堆節點添加到dom中可以使用

    document.createDocumentFragment();

    建立虛拟文檔節點,讓後将節點先添加到此虛拟節點中,再将此節點追加到指定元素,能夠降低dom渲染次數
  • 使用位運算符取整

    取0-9的随機數

    ~~(Math.random()*10)

    //

    Math.random()

    大于等于 0.0 且小于 1.0
  • 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/

說明:歡迎拍磚,不足之處還望園友們指出;

迷茫大概是因為想的太多做的太少。

繼續閱讀