前端技術分享之3/8女神節抽獎活動

一、活動背景

作爲一家團隊文化氛圍濃厚的公司,每年的3/8女神節活動那是必不可少的。

一般來說,這樣的活動想要收到足夠的效果,那高密度的人員聚集是必不可少的(比如去年就組織了大型送玫瑰花活動加現場抽獎)。奈何今年正是疫情期間,這種形式實在是無法開展。那怎麼辦呢?

於是人力想到了線上抽獎(還有另外兩個活動,因爲沒有參與,所以就不列出來啦),很榮幸的,人力讓我來負責前端,與另一個部門一位優秀的後端同事來配合完成整個線上抽獎活動,當然啦,還有一位認真負責,非常優秀的UI同事。

本次的抽獎活動定於3/6號週五中午進行,發佈形式爲向集團APP內註冊h5應用,開發時間大約兩天。

二、前期準備

在正式着手開發之前,人力已經爲我們準備了一份完整的女神資料表(絕密資料,概不外傳!)。由於無法保證集團用戶數據的準確,所以系統內用到的所有個人資料數據(員工編碼除外)都將來自該表格。

鑑於我和後端同事都是第一次往集團APP內嵌入應用,那麼第一步自然是要閱讀集團的第三方開發文檔。

通過閱讀文檔我們得知,往APP內嵌入h5頁面的大致流程就是:

  1. 搭建一個可在公網訪問的網站
  2. 去APP內註冊一個應用,填寫應用參數,並填寫上述網站首頁的鏈接地址
  3. 通過與集團APP後臺服務進行一系列交互,獲取當前用戶數據

第一步基本上與搭建常規網站無異。

第二步則是登錄集團APP,新建一個應用。由於一般用戶缺少發佈給其他人的權限,因此這一步主要由人力的相關人員完成。

第三步則是獲取用戶數據。既然是抽獎,那麼必然要知道抽獎人是誰。而作爲內嵌到集團APP的h5應用,我們需要從集團的後臺服務器獲取這些數據。這個過程大致爲:當用戶點擊APP中註冊的應用時,APP會向我們的服務器發送請求獲取首頁,同時,在發送首頁請求時,會在url後面添加一個臨時的code參數,一分鐘有效。服務端可通過配置攔截器來攔截該請求,提取code參數。然後通過幾個特定格式的請求與APP的後端服務器進行交互,獲取該用戶的參數,並將獲取到的員工編碼存儲到後端的session中。

接下來就很簡單了,集團的APP會在內置瀏覽器(webView)中顯示我們的首頁,之後用戶的操作和流程控制等均由我們自己的代碼負責。

三、技術選型

這裏指的是前端技術選型。

由於目前公司在前端方面基本已經採用了vue技術棧,所以這裏我就毫不猶豫選擇了vue進行前端開發。在vue的基礎上,我選擇了基於Promise的http庫:axios;vue官方支持的路由組件:vue-router;另外引入了mockjs,在開發階段模擬後端請求,以提高並行開發能力。這些基本上都是一個最簡單的vue項目的標配。

除了基本的技術框架外,還有一個不得不正視的問題,那就是字體問題。作爲一個UI,在設計活動頁面的時候必然是以美觀爲第一要務的,所以基本上不太可能選擇基本的web字體格式。一般來說,UI會爲前端提供其所用的字體文件:xxx.ttf,而這個字體文件基本上會在10MB以上。

有一部分瀏覽器會在字體文件下載完成之前先用瀏覽器內置的字體格式顯示頁面內的文字,還有一部分則會一直等待字體文件下載完畢纔會渲染頁面上的文字。無論哪種情況,讓用戶因爲下載一個10多兆的字體文件而等待七八秒以上才能看到最終頁面都不在一個前端開發者可接受的範圍內。

即使換個字體,還是會面臨同樣的問題。如果想把所有的文字段落都使用圖片代替也不現實,畢竟文字模板中還穿插着少量的動態數據。

那怎麼辦呢?

在這裏我要向大家隆重介紹一個基於nodejs的字體文件壓縮工具:font-spider。它的壓縮原理是,通過font-spider xxx.html命令,自動識別該文件內用到的第三方字體,然後檢查文件內的哪些文字用到了該字體(我們暫稱爲目標文字),最後從完整的字體文件中剔除目標文字以外的所有文字。

一個完整的中文字體庫大約有五萬多個字符,而本項目中只用到了其中大約兩百多個。使用font-spider剔除了五萬多個未用到的字符之後,字體文件大小直接從13M壓縮到了200KB,而且從一個ttf格式的文件生成了兼容各大瀏覽器的四種文件格式,簡直是夢幻般的效果!

四、主要的技術實現

完成了前期的技術鋪墊,我收到了來自UI的設計圖 – 一個160多兆,psd格式的美圖(爲了保護UI的知識產權,這裏就不上高清大圖了)!
在這裏插入圖片描述
這裏切圖工作就不再囉嗦了。切圖完成後總共得到了十多個圖片,存入項目assets/img文件夾備用。

然後是字體文件壓縮。首先運行一下命令安裝font-spider:

npm install font-spider -g

爲了簡單,我把人力給出的完整文案放到一個單獨的HTML文件中進行壓縮,格式大致如下:

<!DOCTYPE html>
<html>
  <head>
    <style type="text/css">
      @font-face { 
        font-family: '華康方圓';
        src: url('./HuaKangGuJiMuLan-Regular-2.eot');
        src: url('./HuaKangGuJiMuLan-Regular-2.eot?#font-spider') format('embedded-opentype'),
          url('./HuaKangGuJiMuLan-Regular-2.woff') format('woff'),
          url('./HuaKangGuJiMuLan-Regular-2.ttf') format('truetype'),
          url('./HuaKangGuJiMuLan-Regular-2.svg') format('svg');
        font-weight: normal;
        font-style: normal; 
      }
      body{
        font-family: '華康方圓';
      }
    </style>
  </head>
  <body>
    <p>
		xxx(文案數據)
    </p>
  </body>
</html>

由於設定body內的文字全部使用華康方圓體,因此這裏出現的文字都會被保存到最終生成的字體文件中。將完整的字體文件放在該HTML同級目錄下
在這裏插入圖片描述
打開cmd命令行,進入當前文件夾路徑下,輸入:

font-spider spider.html

壓縮結果如下:
在這裏插入圖片描述
原文件被自動備份到了.font-spider文件夾內。生成的四個字體文件放到項目的assets/font文件夾備用(雖然這裏有四個字體文件,但是最終瀏覽器只會下載其支持的第一個字體文件,準備多個格式的文件可以兼容各大瀏覽器)。

下面就是真正的前端代碼編寫了。

活動主要包括四個頁面:抽獎頁面、在京女神獲獎頁面,非在京女神活動頁、男職員廣告頁。由於是單頁應用,實際上這裏的四個頁面指的是四個組件,由APP.vue組件通過路由來決定當前用戶應該跳轉到哪個組件顯示。

要決定顯示哪個組件,當然必須先知道當前用戶的參數,比如性別、是否在京、是否已開獎、開獎結果等,這些參數通過後臺接口getUser提供。因此在顯示頁面之前,前端會向後端發起一次請求,獲取當前用戶的數據對象。路由邏輯如下:

  1. 性別爲男,直接加載男職員廣告頁
  2. 性別爲女,未開獎,跳轉到開獎頁
  3. 性別爲女,已開獎,跳轉到獲獎頁,顯示獲獎結果

跳轉到開獎頁之後,如果用戶點擊開獎,則向後端發起請求。如果是非在京的,則不返回任何數據,只是記錄已開獎,前端根據用戶參數,顯示一個活動頁。如果是在京的,則後端根據當前各個獎品的剩餘數量,按照概率計算出所中獎品(據人力反饋,最終大家所中獎品都很符合自己的心意,不知道是不是後端進行了大數據分析,作爲前端,咱就不關心這個了哈哈),前端獲取到中獎類型後,顯示對應的文案和獎品圖片。

如果是實際參與到抽獎的女神,應該可以看到,在點擊抽獎信封的時候,獲獎頁有一個短暫的淡入效果,並且信紙有一個向上抽動的小動畫。關於淡入效果的實現比較簡單,只需要把路由組件放在一個transition組件中,配置淡入的css動畫即可。不過信紙的向上抽動效果代價就略大一些。
在這裏插入圖片描述
這裏我說的是代價,而不是難度。因爲實現抽動效果的難度並不大,下面的代碼就可以實現:

<script>
  export default{
    methods: {
      flowPaper(){
        setTimeout(function(){
          let paper = document.getElementById("paper");
          let content = document.getElementById("content");
          let award = document.getElementById("award");
          paper.style.top = "20%";
          content.style.top = "27%";
          award.style.bottom = "10%";
        }, 100)
      }
    },
    mounted(){
      this.flowPaper();
    }
  }
</script>

<style>
.paper, .content, .award{
    transition: top .6s;
    -moz-transition: top .6s; /* Firefox 4 */
    -webkit-transition: top .6s; /* Safari and Chrome */
    -o-transition: top .6s; /* Opera */
	...
  }
</style>

短短几行js,加一個css過渡動畫定義就可以了。但是由該動畫引出的,是對前端構圖的變更。

如果沒有抽取動畫,前端完全可以把背景、信紙以及信紙上的裝飾物切成一張圖,只留出打印文字以及顯示獲獎圖片的位置即可。但是要實現抽取動畫,這三個圖層必須隔離開,因爲只有信紙位於背景圖和裝飾物的中間圖層,纔可能實現抽動效果。於是我把上面的圖片切成了四張圖片:背景圖、信紙、獎品和信紙上的裝飾物。背景圖、信紙和裝飾物可以在五種獎品的獲獎頁使用,而獎品則需要根據中獎結果動態設置。再配合上文案的三個段落,就完成了獲獎頁面的構圖。接下來只需要設置一個100毫秒的延遲,用js修改信紙、段落和獎品圖片的位置,配合css所定義的過渡效果,就可以產生柔和的信紙抽出效果。

另外,由於信紙採用的百分比高度,因此它的長度在各個分辨率的手機上並不是固定的,但是文字的行高卻很難保證與所有的屏幕高度恰好匹配,這帶來的結果就是要麼在小屏手機上獎品被遮擋,要麼在大屏手機上文字擠在一堆,影響美觀度。

爲了解決這個問題,我對頁面構圖進行了簡單的分析(由於時間有限,行高的自適應問題做的稍微有點粗糙)。我發現幾乎在所有的手機上,文字加獎品圖片的高度都大約是屏幕高度的一半,而獎品圖片又可以採用固定大小,因此整個段落的高度大約是屏幕高度的一半減去獎品高度。再用這個結果除以大致的行數,就可以得到一個粗略的行高值。用js動態設置這個行高值,就可以大大提高頁面對不同分辨率手機的適應能力(說是這麼說,但真正動起手來,大約調了一個多小時才調整到基本滿意)。

另外還有一個問題,就是頁面返回。集團的APP內提供了一個返回鍵,在最初的版本中,我發現當抽完獎之後去點擊這個返回鍵,就會出現白頁,而且在相當長一段時間內都沒搞清楚什麼原因。經過反覆的測試,我發現實際上點擊這個返回鍵的行爲與點擊瀏覽器的返回鍵是一致的,於是我轉移到瀏覽器去分析如何解決。下面是某個頁面的路由參數:

http://xxx/indexhtml#/WomanPage

我發現點擊了返回鍵之後,路由變成了下面的樣子:

http://xxx/indexhtml#/

現在就白頁了。那麼問題就很明顯了,因爲我的路由表裏沒有配/對應的組件,所以沒有東西可以渲染。我當時想到的解決方案是,在路由表裏配一個/對應的組件,然後找UI臨時做一個返回頁,寫點祝福語什麼的(沒錯,我又理直氣壯地跟UI要了一張好看的圖片)。

UI的圖片給我了,放上去,發現效果還不錯。但是咱作爲前端,總感覺這問題它不簡單。後來去查vue-router相關的資料,突然想到,如果用this.$router.replace代替this.$router.push,那不就解決了嗎?

果不其然,現在一點返回,就可以成功退出頁面了。但是人力小姐姐偏偏就看上了剛纔做好的返回頁,咱能咋辦呢,那就加回去唄(一個bug轉需求的感人故事)!

五、完工上線

這就沒啥可說的啦,技術人員負責導入數據,啓動服務;人力那邊配置APP應用地址和圖標,選擇可見範圍爲公司所有人。11:38,女神紛紛拿起手機,點擊抽獎,下午送禮到工位,活動圓滿成功,拍手慶賀!

在所有的功能裏,我最喜歡的就是那個信紙向上抽出的動畫效果了。雖然實現起來並不難,但是我想讓每位女神感覺到,你所中的獎品並不是事先準備好的,它的確是你剛從信封裏拆出來的。我把這個0.6秒的動畫稱爲“0.6秒的驚喜”,作爲我送給公司三百多位女神的禮物!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章