標籤:多次 rect function github 置中 再計算 city 沒有 滑鼠
又是一年科技節,鑒於去年參加一個比較沒意思的比賽,拿了一個不該拿的獎。今年我想著去參加一個稍微有點意思的比賽,憑自己的努力拿個獎。(題外話,血虧的是同學參加ctf比賽,我一開始以為我個人能力不行沒敢和他組隊(主要是怕我太坑),結果我幫他們解決了兩道前端的題目,他們得了個二等獎……)
說正事,接觸html和css是很早以前的事情了,但是js方面還是剛剛入門,之前有用bootstrap搭過一個blog(還沒有完成)。隊友想的是所有的都自己來寫,也當是給自己一個練手的機會。這正如一個學長說的,用模板就是前期簡單,後面自己要修改起來就很難了 ,而自己寫的,後面再修改起來就會省去很多的功夫。抱著嘗試總是沒有錯的心態,我們開始寫這個網頁了。大賽的題目是幫學校的某個社團做一個首頁,我們當時選的是一個新成立不久的社團——天文社。隊友剛剛提出這個想法,我的腦海裡就有了一個感覺上很不錯的思路了,畢竟天文能讓人聯想到星星,而星星的背景應該是能夠抓住人的眼球的絕好的東西。canvas是html5新的標籤,我想著用canvas做出這個效果可能是再合適不過的了。
這個是第一個版本
第一個版本遇到的第一個問題,同樣也是寫js通常情況下遇到的問題,那就是相容性問題。滑鼠移動事件再不同的瀏覽器上是有不同的方法來表示的。由於是剛開始學,我先是模仿的是網上的寫法,但是我的瀏覽器中並不能相容他的代碼,於是我有baidu,google了好久,最後又去找了官方的api還是沒有找到;其實問題出在監控的對象上,我們設定的背景的z-index應該是最下的,而如果監控的對象選為canvas,滑鼠移動並不能發生在canvas上,後來我隨便改了一下,改為window終於得到了效果了。這個效果其實和我當初的設想差不多,我把我寫的發給同學,讓他評價一下,誰知道他當頭一棒,就說這個動態很礙眼。我一下就不服氣了,我辛辛苦苦弄了這麼久,卻被說成這樣,一時實在是沒法接受。不過後來我也越看越不怎麼協調,就去掉了。
第二版,我的想法是既然移動的那麼不好看,不如寫個不動的,讓星星自己閃。把這個想法和隊友說,隊友也沒太大的意見,於是我又開始去折騰了。實現的方法就是先給每一個點設定一個初相位st,然後讓他們不透明度從st->1然後再從[0,1]往返,然後就是我們能夠看到的一閃一閃的效果。
這個是第二版的背景(圖中紅圈圈出的地方有明顯的明暗變化)
如此一來,沒了移動的效果,但是閃爍的效果也並沒有想象中的好看。之前寫js完全沒去想效能上可能會有問題,這次,我突然發現一開啟這個背景的頁面,就cpu的佔用就非常的高。我開始嘗試分析My Code,看看有沒有什麼能夠最佳化的地方,由於是採用的是之前滑鼠移動事件相似的方法,我使用了每次都刪除整個畫布的全部內容,然後再計算每個點的不透明度,然後再重新畫這個點。
function twinkle() { run = function() { context_stars.clearRect(0, 0, canvas_stars.width, canvas_stars.height);//每次清除整個畫布 for (var i = 0; i < starsnum; i++) { start[i] ++; starArr[i].opacity = Tween.Quart.easeInOut(start[i], flag[i], 1-2*flag[i], 100);//這裡用到了一個緩動的庫 drawCirle(context_stars, starArr[i].centerX, starArr[i].centerY, starArr[i].radius, starArr[i].opacity); if(start[i] == 100){ //當start == 100的時候完成兩件事情,一個是start置零 另一個是flag方向交換,簡單來講就是從0->1變成1->0或者反之 start[i] = 0; flag[i] = 1-flag[i]; } } requestAnimationFrame(run); }; run();}
整個思路是非常的清晰的,但是事實上每次清除並重新計算的cpu代價是非常的大的。研究了半天最佳化的方法,最後總結下來有兩種:
(1)每次不清除,一層一層的覆蓋,通過改變整體的不透明度來改變星星閃爍的效果
(2)每次清除一個點周圍的一小塊地區,而不是清除整個畫布
第一種我倒是有嘗試過,cpu的佔用瞬間降下來了,可能是參數調節的時候的問題,最後的效果同樣不能讓我滿意。至於第二種,由於畫布給的api種只有清除某個矩形地區的內容,而星星採用的圓形的表示方法,一旦清除可能會給周圍的點造成缺少一個角的問題,所有後來也就沒有去實現。
在製作背景的過程當中,我交給我的隊友去想,他給出我下面這個版本:
這個其實是改的人家的demo
不過星星數量太多,運動效果同樣鬼畜,和文字顯得實在不搭,最後我還是否決了這個想法。
最後,因為這個網頁的設計我們想走的風格還是一種簡約的路線,最後改成了一個不動的效果:
這個是最終版本,星星沒有移動也沒有閃爍
最後的版本我還加入了視窗resize的事件的處理,又對星星之間連線的判斷做了最佳化,為了讓星星之間的連線橫向,縱向上分布的盡量均勻。這樣的星星背景的效果,達到了理想效果的80%,但不失美觀和簡潔,也是評委看到感覺很滿意的一項。導覽列上的表徵圖去掉有兩個原因,一個是為了美觀,另一個是因為布局容易出問題。
說到導覽列,我做的第二部分就是導覽列,導覽列是有個變化的過程,從頂部往下,導覽列收縮,背景色從無色變為有顏色;從下面到頂部,導覽列從有顏色變為沒有顏色。與之同時的還有個返回頂部的小火箭的變化,從頂部往下,小火箭有個從display none到dispaly block不透明度從0到1的變化;從下面到頂部反之。
當時糾結最久的並不在變化上面,因為只要寫個css的animation效果就行了,雖然時間鎖死最少一秒,不過效果已經很不錯了;而在於滾輪事件的判定上面。眾所周知,瀏覽器對於滑鼠滾輪事件的判定有各種各樣的辦法,不知道是我的寫的問題,還是隊友寫的問題,我試著console.log一下,發現我的chrome在返回頂部的過程中出現了兩個scrollTop=0的點,這就非常神奇了。如果一個向上的過程中出現了兩個scrollTop=0就意味著瀏覽器給了兩個頂部(現在想想很有可能是css的問題),導覽列變化的過程會執行兩次,而真正到達頂部的時候,它卻並不能處在它應有的狀態。單單這個事情就困擾了我好久,想了好久,既要能夠精確的反應滾輪位置的變化,又要能夠找不到不同瀏覽器的相容性問題。最後我想到了一種比較能夠兩者兼顧的解決方案,分別訂一個pre_wheel和cur_wheel分別記錄上一個滾輪的位置和當前滾輪的位置,放入body的onscroll事件中。
var wheel = { pre_wheel: 0, //前一個滾輪位置 cur_wheel: 0, //當前滾輪位置 wheelup: false, //滾輪是否向上 wheeldown: false, //滾輪是否向下 on_top: false, //滾輪是否到頂 on_bottom: false //滾輪是否到底}function scroll() { //滾動的時候判斷滾輪的狀態 wheel.cur_wheel = $(window).scrollTop(); if (wheel.cur_wheel < wheel.pre_wheel) { wheel.wheelup = true; wheel.wheeldown = false; } else if (wheel.cur_wheel > wheel.pre_wheel) { wheel.wheelup = false; wheel.wheeldown = true; } else if(wheel.cur_wheel == wheel.pre_wheel) { wheel.wheelup = wheel.wheeldown = false; } if ($(window).scrollTop() == 0) { wheel.on_top = true; } else { wheel.on_top = false; } if ($(window).scrollTop() + $(window).height() >= $(document).height()) { wheel.on_bottom = true; } else { wheel.on_bottom = false; } /*滑鼠滾動函數介面*/ /*此處可以放入一些需要滾輪監控的事件*/ wheel.pre_wheel = wheel.cur_wheel;}
這樣處理過後,用console調試後的效果果然非常好,甚至精確到了小數點後,感覺這個正是我想要的結果。細心的你一定能看出,如果滾動結束了以後,滾輪的wheelup和wheeldown應該都重設為false,但是用這種方法卻沒法做的;實際運用的過程中,兩個變化的效果都完美實現了,各種地方測試都沒有問題,於是我就選擇性的無視了這個問題。
滾輪的事件處理總算“解決“了,接下來我們想到寫個頁面跳轉的方法,這個同樣並不難,加了一個緩動的庫,我又對滾動的時間用距離差距做了一個簡單的運算,使得每個頁面跳轉的時間大體相同,緩入還是緩出又還是緩入緩出,我們測試了好幾種,最後敲定了四次方緩入緩出的方式。
代碼如下:
var block_top = false;var block_jump = false;function to_top() { //跳回頂部 if(block_top == false) { x = document.body.scrollTop; rocket = document.getElementById(‘rocket‘); if (x == 0) { return; } block_jump = true; block_top = true; start = 0, during = Math.floor(40 * x / document.documentElement.clientHeight); tween_to_top = function() { start++; document.body.scrollTop = Tween.Quart.easeInOut(start, x, -x, during); if (start < during) requestAnimationFrame(tween_to_top); if (start == during) { rocket.style.cssText = "display: none"; block_jump = false; block_top = false; } }; tween_to_top(); }}function jump(obj) { if(block_jump == false){ object = document.getElementById(obj); x = document.body.scrollTop; to = object.offsetTop; if(Math.abs(x - to) < 1) return; start = 0, during = Math.floor(40 * Math.abs(to - x) / document.documentElement.clientHeight); block_top = true; block_jump = true; cur_page = getindex(pages, obj); jump_to = function() { start++; document.body.scrollTop = Tween.Quart.easeInOut(start, x, to - x, during); if (start <= during) { requestAnimationFrame(jump_to); }else{ block_top = false; block_jump = false; } }; jump_to(); }}
這裡分成了兩個函數,一個是返回頂部的,一個是頁面之間直接跳轉的,這個是一開始為了避免一些不必要的衝突,(其實是沒有必要的),另外這裡有個處理的小技巧。js的本身特性使得同一個函數能在同一時間執行多次,這樣會出現很多奇奇怪怪的bug,為此我加了兩道block,保證同一時間,只能有一個jump函數或者to_top函數在運行,避免bug。
接下來我做的部分就是公告部分了。公告我們最一開始就想寫一個簡單的,大家都很常見的那種公告的方式,後來,因為社團那裡發了很多的照片(雖然大多拍攝的不大好...),我就想到了可以弄一個時間軸的方式來做。假設有個時間軸,過去舉行的活動就放在前面的點上,點擊就會出現過去的活動的介紹和圖片展示;通知相當於未來要發生的事情,所以就放在最後一個時間點上。這裡在處理點和時間對其的上面,我們用到了table標籤,table的td和tr標籤以及內建的自動置中效果正好能夠協助我們構建這個時間軸。而我所需要控制的就是節點的數目以及內容,這個用了jquery來實現就是十分容易的一件事了。
$(function(){ let num = Events.length; for(var i = 0; i < num; i++){ $(‘.time‘).append("<td class=‘time_text‘>" + Events[i].date + "</td>"); $(‘.timepoint‘).append("<td class=‘time_point‘><img src=‘img/circle.svg‘></td>"); } $(‘.time‘).append("<td class=‘time_text‘>接下來會發生什麼呢...</td>"); $(‘.timepoint‘).append("<td class=‘time_point‘><img src=‘img/circle_cur.svg‘></td>"); $(‘.time_line_notice‘).html("<div class=‘time_line_img‘></div>"+ "<div class=‘time_line_intro‘></div>"+ "<h3 style = ‘text-align:center;‘>" + "通告" + "</h3>"+ "<p style = ‘font-weight: normal;‘>" + notice + "</p>"); $(‘.time_line_intro‘).css("display", "none"); $(‘.time_line_img‘).css("display", "none"); $(‘.time_point img‘).click(function(){ var i = $(‘.time_point img‘).index(this); $(‘.time_point img‘).attr("src", "img/circle.svg"); $(‘.time_point img‘).eq(i).attr("src", "img/circle_cur.svg"); if (i == num) { $(‘.time_line_intro‘).css("display", "none"); $(‘.time_line_center‘).text(‘未來計劃‘); $(‘.time_line_img‘).removeAttr("style"); $(‘.time_line_notice‘).html("<div class=‘time_line_img‘></div>"+ "<div class=‘time_line_intro‘></div>"+ "<h3 style = ‘text-align:center;‘>" + "通告" + "</h3>"+ "<p style = ‘font-weight: normal;‘>" + notice + "</p>"); $(‘.time_line_intro‘).css("display", "none"); $(‘.time_line_img‘).css("display", "none"); }else{ $(‘.time_line_intro‘).css("display", "block"); $(‘.time_line_img‘).css("display", "block"); $(‘.time_line_center‘).text(‘過往記憶‘); $(‘.time_line_intro‘).html("<b>" + Events[i].title + "</b>" + "<p>" + Events[i].date +" "+ Events[i].place + "</p>" + "<p>" + Events[i].context + "</p>"); $(‘.time_line_img‘).css("background-image", "url(" + Events[i].pic +")"); } });});
下面是效果展示:
這其中目前時間點的變化是通過兩個顏色不同的svg圖片互相替換實現的,因為圖片下面寫文字的效果不一定好看,所以我們底下的介紹是用一個線性漸層做底,然後把文字放在上面實現的,也算是我們整潔美觀的一種體現吧。這裡還有很多的細節可以完善,不過由於時間的倉促,我們也沒有餘力去弄接下來的最佳化了。
整個網頁設計的最後一個我做的部分其實是最後趕工階段臨時增加出來的一個需求。鑒於我們頁面的配色不是很好,我們想做一個向下滾動,自動跳轉到下一頁的效果。由於之前寫的滾動監測我感覺非常的完美,於是我首先就接下了這個鍋,然而我當時並不知道,這個卻成了我們最後最大的一個問題,最後都沒有能夠解決成功的問題。之前有提到,我寫的滾動監測的bug,但是可能按照那個bug我的向下滾動應該是一直滾動到底部,或者滾動到頂部,停不下來的那種。事實卻出乎我的意料,向上的滾動完全沒有問題,向下的滾動出了很大的問題,他會先向下,然後在向上回彈,導致根本沒法往下滾動,更可怕的是我之前寫的認為非常好的點擊跳轉,在加上了這個效果以後都出現了類似的bug。這個在我們看來只是要注釋這一個點的問題,但是對於使用者來說這個簡直是個災難。這個bug的情況也是令人捉摸不透,我的windows下的chrome運行毫無問題,但是換到隊友同樣是windows下的chrome瀏覽器就出了問題;更更令人匪夷所思的是,我早晨寫的沒有問題,中午開啟就出了問題。調試發現,我的瀏覽器顯示的距離能夠精確到小數點,然而他們的都不能精確到小數點,至此總算bug的原因是搞清楚了,然而卻沒有任何的解決思路,試著換成jquery,問題依舊在。眼看還有一兩天就要交了,我的電腦依然是處在一會兒可以,一會兒不可以的狀態,實在沒有頭緒,我嘗試像是和跳轉一樣處理滾動加了鎖之後,依舊還是有問題。最後我們無能為力,只能將有問題的部分注釋掉了,交了上去,真是遺憾。
總結起來,網頁設計比賽最後能夠獲得二等獎實屬不易。網頁設計比賽,其實重點突出一個設計,我們三個人沒一個有設計的基礎,單純憑藉著“嗯,這個厲害”,“這個好看”來做,確實有很多的問題,甚至最後臨近提交5個小時,我還改了好多的圖片和布局,最後的結果早已經和最先設想的南轅北轍了。其次,一個原因在於我們的基礎太差,底子太薄,經驗不足,一開始的架構搭的不夠好,導致後面修修補補都能動相當大的部分,浪費了太多的時間,最後響應式也出了很多的問題,最後無奈刪掉了。還有沒能好好利用git,本想利用git提高工作的效率,結果卻耽誤了好多的時間,學長指導之後稍微好點,然而最後還是崩了...總之,還是一個在學習的過程,解決這一個個問題後,收穫的也還是有很多的。
最後放一下github上的地址:
https://github.com/MZIchenjl/NUPT_Astronomy_Association
雜談-網頁設計大賽的一些感想