蹭一波日食流量古沥,手擼h5日環(huán)食效果

這兩天大家的朋友圈應該都被日環(huán)食刷屏了吧,有幸親眼目睹了日環(huán)食的小伙伴一定被這十年才能一見的天文奇觀給震撼了一番娇跟,我作為一個業(yè)余天文愛好者岩齿,業(yè)余到連一個望遠鏡都沒有,只能在日環(huán)食這天仰望天空苞俘,卻被強烈的陽光刺痛了雙眼盹沈,毛也看不到。

作為一個有追求的前端碼農(nóng),怎么能在這么有意義的日子里什么也不做呢乞封,于是我靈機一動做裙,干脆手擼一個日環(huán)食效果吧。

擼頁面之前肃晚,我們先腦補一下頁面要實現(xiàn)的效果锚贱,碧藍的天空里懸掛著一輪孤獨的烈日,突然关串,她渾圓的身體開始出現(xiàn)黑色的殘缺拧廊,隨著時間的推移,她的身體逐漸被黑色吞噬晋修,蒼茫的天空也隨之籠罩下壓抑的陰霾吧碾,天地之間,在一片混沌的漆黑之中墓卦,一輪詭異的金色圓環(huán)出現(xiàn)了倦春,啊,打住落剪,跑題了睁本。


日食效果

如圖,頁面元素比較簡單:

  1. 藍天
  2. 太陽
  3. 月亮

因為要做動畫效果著榴,這三個元素都用絕對定位添履,其中藍天的寬高都設置為100%就好屁倔,太陽元素要設置一個投影濾鏡(作為發(fā)光效果)脑又。需要注意的是:月亮要對太陽進行遮擋,并且顯示為黑色锐借,但超出太陽的部分是不可見的问麸,因此在層次結(jié)構(gòu)上,月亮div屬于太陽div的子元素钞翔,然后太陽div要設置overflow為hidden严卖,這點需要注意。另外布轿,由于是日環(huán)食哮笆,月亮div的寬高要略小于太陽,具體數(shù)值根據(jù)效果微調(diào)即可汰扭。

以下css代碼僅供參考

.sky {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: #7ad8fb;
    }
.sun {
        position: absolute;
        top: 200px;
        right: 200px;
        width: 204px;
        height: 204px;
        border-radius: 200px;
        background: #fcf6dc;
        overflow: hidden;
        box-shadow: 0 0 60px rgba($color: #ffffff, $alpha: 0.6);
    }
.moon {
        position: absolute;
        top: 7px;
        left: 7px;
        width: 190px;
        height: 190px;
        border-radius: 190px;
        background: #000000;
    }

隨著日食的推進稠肘,天空會逐漸變暗直至黑色,因此還需要一個元素萝毛,用來控制天空的明暗程度项阴,這個元素我們就叫它mask吧,它也是絕對定位笆包,并且寬高跟天空一樣是鋪滿全屏的环揽,在層次上略荡,它應該處于天空上方,太陽下方歉胶。這個div我們設置它的背景色為黑色汛兜,但透明度默認是0,后續(xù)用腳本控制透明度來達到天空逐漸變暗的效果通今。
css代碼如下:

.mask {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba($color: #000000, $alpha: 0.9);
        opacity: 0;
    }

頁面的html結(jié)構(gòu)非常簡單序无,如下:

<div class="sky">
        <div class="mask"></div>
        <div class="sun">
            <div class="moon"></div>
        </div>
    </div>

通過上面的代碼,我們已經(jīng)實現(xiàn)了一個靜態(tài)的日環(huán)食效果衡创,接下來我們就來編寫js腳本帝嗡,控制月亮的移動以及天空的明暗變化。

我用的是vue璃氢,但這個不重要哟玷,我們只需要關(guān)注實現(xiàn)原理即可。實現(xiàn)原理其實也很簡單一也,我們只需要控制好月球的坐標走向即可巢寡,為了盡可能實現(xiàn)逼真的效果,我們讓月球從太陽的左下角逐漸走到太陽的右上角直至消失椰苟,當走到中間的一瞬間抑月,月球和太陽的圓心會重合,由于月球的半徑比太陽小舆蝴,因此正好會出現(xiàn)日環(huán)食的效果谦絮,注意,當月球圓心和太陽圓心重合的一瞬間洁仗,mask遮罩層的透明度應該正好是1层皱,也就是天空完全變黑的一個效果。

大致的原理就是這樣赠潦,以下是這個頁面需要用到的變量:

opacity_step: 0.001, // 透明度的增量(每一次渲染增加的透明度)
sun_width: 0, // 太陽寬度
sun_height: 0, // 太陽高度
moon_width: 0, // 月亮寬度
sun: null, // 太陽dom對象
moon: null, // 月亮dom對象
mask: null, // 遮罩層dom對象
distanceX: 0, // 月球到太陽中心重合點的橫向距離
distanceY: 0 // 月球到太陽中心重合點的縱向距離

在頁面加載完畢后叫胖,我們先對這些變量進行初始化,并且讓月球處于左下角的位置她奥,我用的是vue瓮增,所以將這部分代碼寫在mounted函數(shù)里:

this.sun = document.querySelector('.sun')
this.moon = document.querySelector('.moon')
this.mask = document.querySelector('.mask')
this.sun_width = this.sun.clientWidth
this.sun_height = this.sun.clientHeight
this.moon_width = this.moon.clientWidth
this.moon.style.left = (this.moon_width * -1) + 'px'
this.moon.style.top = this.sun_height + 'px'
const offsetSize = (this.sun_width - this.moon_width) * 0.5
this.distanceX = this.moon_width + offsetSize
this.distanceY = this.moon_width + offsetSize
this.render()

注意月球初始位置的計算規(guī)則,left應該是負的月球的寬度哩俭,top應該是太陽的高度绷跑。初始化的最后一行代碼,調(diào)用了render方法携茂,我們將在這個方法里不斷更新月球的位置和遮罩層的透明度你踩,為了實現(xiàn)這個不斷刷新,可以使用setInterval,但這里我用的是window.requestAnimationFrame带膜,也推薦大家用這個吩谦,此方法在MDN的說明如下:

window.requestAnimationFrame() 告訴瀏覽器——你希望執(zhí)行一個動畫,并且要求瀏覽器在下次重繪之前調(diào)用指定的回調(diào)函數(shù)更新動畫膝藕。該方法需要傳入一個回調(diào)函數(shù)作為參數(shù)式廷,該回調(diào)函數(shù)會在瀏覽器下一次重繪之前執(zhí)行

詳見:window.requestAnimationFrame

我們在render方法中引入這個requestAnimationFrame方法

render () {
  window.requestAnimationFrame(() => {
    // 更新dom元素 todo...
    this.render() // 再次調(diào)用自己
  }
)

通過requestAnimationFrame方法,我們就得到了一個屏幕不斷刷新的回調(diào)函數(shù)芭挽,接下來我們只需要告訴瀏覽器滑废,每次刷新,dom元素的位置或透明度如何變化即可袜爪。

首先我們來分析遮罩層mask蠕趁,根據(jù)上文描述,它的透明度需要從0變?yōu)?(月球和太陽的圓心重合)辛馆,然后再從1變?yōu)?(月球離開太陽)俺陋,因此我們只需要在每次渲染時讓它的透明度逐漸遞增就行,參考代碼如下:

let opacity = Number(this.mask.style.opacity) // 獲取當前透明度
if (opacity >= 1 || opacity < 0) { // 如果透明度已經(jīng)大于1 或者小于0
  this.opacity_step *= -1 // 就讓增量值反轉(zhuǎn)
}
opacity += this.opacity_step
this.mask.style.opacity = opacity // 更新遮罩層的透明度

緊接著我們來分析月球的位置昙篙,我們的目標是讓月球移動到左上角腊状,說明每次移動,月球的橫向偏移量和縱向偏移量都是一樣的苔可,因此月球就會沿著一個45°角的軌跡來移動缴挖。但這里要注意一個問題,就是月球每次移動多少偏移量焚辅,才能在遮罩層正好為1(天空完全變暗)的時候映屋,移動到太陽的正中間?我們在初始化的時候法焰,已經(jīng)計算好了月球距離太陽圓心的橫向距離distanceX和縱向距離distanceY秧荆,而遮罩層的透明度增量也是知道的倔毙,就是變量opacity_step(0.001)埃仪,因此可以得出:月球每次偏移量 = 月球到太陽圓心的距離 * opacity_step,然后陕赃,當月球已經(jīng)離開太陽時卵蛉,讓所有變量復原,日食重新開始么库。
月球的位移計算代碼如下:

let left = Number(this.moon.style.left.replace('px', ''))
let top = Number(this.moon.style.top.replace('px', '')) //先獲取月球當前的left和top
left += this.distanceX * Math.abs(this.opacity_step)
top -= this.distanceY * Math.abs(this.opacity_step) // 計算月球的位置
this.moon.style.left = left + 'px'
this.moon.style.top = top + 'px' // 更新月球dom元素的位移

if (left > this.sun_width) { // 如果月球已超出太陽的邊界傻丝,所有變量復原
  this.opacity_step = Math.abs(this.opacity_step)
  this.mask.style.opacity = 0
  this.moon.style.left = (this.moon_width * -1) + 'px'
  this.moon.style.top = this.sun_height + 'px'
}

好了,所有的代碼都寫完了诉儒,運行你的頁面葡缰,你就會看到一個還不錯的日環(huán)食效果。

完整效果請訪問:h5日環(huán)食效果

喜歡這篇文章的小伙伴,記得轉(zhuǎn)發(fā)泛释、點贊哦滤愕,原創(chuàng)不易,請大家多多支持怜校。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末间影,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子茄茁,更是在濱河造成了極大的恐慌魂贬,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件裙顽,死亡現(xiàn)場離奇詭異付燥,居然都是意外死亡,警方通過查閱死者的電腦和手機愈犹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門机蔗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人甘萧,你說我怎么就攤上這事萝嘁。” “怎么了扬卷?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵牙言,是天一觀的道長。 經(jīng)常有香客問我怪得,道長咱枉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任徒恋,我火速辦了婚禮蚕断,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘入挣。我一直安慰自己亿乳,他們只是感情好,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布径筏。 她就那樣靜靜地躺著葛假,像睡著了一般。 火紅的嫁衣襯著肌膚如雪滋恬。 梳的紋絲不亂的頭發(fā)上聊训,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機與錄音恢氯,去河邊找鬼带斑。 笑死鼓寺,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的勋磕。 我是一名探鬼主播侄刽,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼朋凉!你這毒婦竟也來了州丹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤杂彭,失蹤者是張志新(化名)和其女友劉穎墓毒,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亲怠,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡所计,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了团秽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片主胧。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖习勤,靈堂內(nèi)的尸體忽然破棺而出踪栋,到底是詐尸還是另有隱情,我是刑警寧澤图毕,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布夷都,位于F島的核電站,受9級特大地震影響予颤,放射性物質(zhì)發(fā)生泄漏囤官。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一蛤虐、第九天 我趴在偏房一處隱蔽的房頂上張望党饮。 院中可真熱鬧,春花似錦驳庭、人聲如沸刑顺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捏检。三九已至,卻和暖如春不皆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背熊楼。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工霹娄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留能犯,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓犬耻,卻偏偏與公主長得像踩晶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子枕磁,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345