活動抽獎元件設計

Sherlock09發表於2019-07-17

一 專案背景

    略 公司內部資料以及安全紅線 只討論技術細節 不透漏相關互動和設計

二 互動以及視覺

    整體視覺:

    略

    抽獎模組:大概是以一個花朵的花瓣為抽獎背景,旋轉的時候不同的花瓣點亮,省略視覺稿,只討論技術實現細節

   

    互動:略

三 分析需要解決的問題

    當做一個沒有做過的東西的時候,這時候應該分析下完成這個效果需要考慮的問題,然後分解分析,然後逐步實施,分析總結遇到過的問題,是否有沒考慮到的。

    其實這種抽獎模組在現在的活動頁中十分的常見,尤其是在活動頁中。

    首先,整理了TODO List

  1.  需要寫成元件的形式,方便複用,需要考慮元件需要的傳遞的引數等等。
  2. 後端是介面的形式,也就是說,使用者點選抽獎的時候,已經獲得了中獎資訊,前端需要執行一下抽獎輪轉的動畫,這個動畫的時間、轉動速率、轉動期間禁止需要重複點選、初始的指標位置都需要前端來控制。
  3. 狀態管理,針對不同抽獎次數、區分是否登陸、是否在APP內等相應的狀態進行處理,彈窗或者跳轉相應的URL
  4. 前端埋點相關和資料上報相關。
  5. 樣式問題,設計互動的思路實際上是一個九宮格抽獎,但是視覺樣式卻是偏向指標類的輪盤抽獎,邏輯層面暫定的是按照九宮格的思路去實現,但是需要樣式方面進行調整
  6. 抽獎的結果也需要寫成一個彈窗元件,並且需要定義傳入的引數
  7. 異常展示,當介面呼叫失敗、後端資料庫庫存不足等等需要相應的warning彈窗元件

    大致互動流程如下

 四 具體設計

        4.1 封裝成公共元件,主要是對元件傳遞的引數進行定義,首先在首頁需要呼叫抽獎元件,必傳的有三個引數

            showLuckDraw // 是否展示抽獎模組,如果使用者已經抽過獎,預設不展示此模組,直接展示抽獎結果

            userStatus        // 使用者狀態:首頁介面中會返回此資訊,需要傳入到元件中

            drawStatus       // 抽獎狀態:

            此外還需要給抽獎元件的子元件–抽獎結果元件傳遞引數

            showSpecial&&type

 

        props: {
            // 是否展示抽獎模組,如果使用者已經抽過獎,預設不展示此模組,直接展示抽獎結果
            showLuckDraw: {
                type: Boolean
            },
            // 使用者狀態
            userStatus: {
                type: Number,
                required: true
            },
            // 抽獎狀態 0: 跳轉活動頁 1: 需要通過活動增加抽獎次數 3: 不可抽獎
            drawStatus: {
                type: Number,
                required: true
            },
            // 是否已登陸 未登陸吊起登陸元件
            hasLogin: {
                type: Boolean,
                required: true
            },
            // 特殊彈窗 展示抽獎的結果
            showSpecial: {
                type: Boolean,
                default: false
            },
            // 向抽獎結果彈窗 傳的值 顯示對應的抽獎結果
            type: {
                type: Number,
                required: true,
            }
        },

    4.2 抽獎動畫(核心邏輯)

        核心的思路是,當點選抽獎的時候,呼叫後端介面,並且設定轉盤所需要的初始引數,包括如下

  • diff               速度累加變數,控制逐漸加快/逐漸減慢
  • star              開始按鈕點選態,如果使用者已經無法抽獎,直接禁用
  • speed          抽獎初始速度
  • isDisable     是否禁用開始抽獎按鈕,防止重複抽獎,保證在在抽獎動畫結束後才能再次抽獎,避免重複呼叫後端介面        

  • drawStatus  設定抽獎狀態初始值

  • startTime     記錄轉動開始時間,用來控制動畫時長

      同時,設定一個定時器,輪盤的背景圖片依次切換來實現動畫的效果,利用定期器的milliseconds 時間間隔進行速度控制,當達到預設的轉動時間時,開始做減速運動,且如果後端返回的獎品id和前端設定的獎品id能對應上時,清除定時器,同時return中止函式,且重新設定轉盤的狀態值,完成抽獎動畫。

    html 部分使用的簡潔的jade,雖然剛開始上手有些不適應,但是用慣了之後,感覺十分簡潔乾淨,不需要在大段的html程式碼裡尋找calss等

<template lang="jade">
    .award-box(v-if="showLuckDraw")
        .award-bg
            .award(:class="'active' + (current)")
        button.start-btn(
            @click="start",
            :disabled="isDisable",
            :class="star ? 'star': '' "
            )
        .award-num 當前抽獎次數  
            i.award-n {{ currentNum = +this.drawStatus === 2 ? 1 : 0 }}   
            i 次
        special-dialog(:show-special="showSpecial", :type="id")
</template>

 

        
        move() {
                let timeout = setTimeout( () => {
                    this.current++; // 切換背景圖,初始值可以隨意設定
                    if ( this.current > 4) { // 因為只有5個獎品,所以當current 從0開始大於4的時候,重新載入第一張圖片
                        this.current = 0;
                    }
                    // 若抽中的獎品id存在,且轉動時間大於2秒,則開始減速轉動
                    if ( this.award.id && ( Date.now() - this.startTime ) / 1000 > 2 ) {
                        this.speed += this.diff; // 轉動減速
                        //若轉動超過4秒,並且獎品id等於格子的獎品id,則停下來
                        // this.awards 是從後端獲取的中獎結果,如果和前端對應的獎品id對應上的話則為中獎
                        if ( ( Date.now() - this.startTime ) / 1000 > 4 && this.award.id == this.awards[this.current].id ) {
                            clearTimeout( timeout );
                            this.star        = false;
                            this.isDisable   = false;
                            this.showSpecial = true;    // 呼叫抽獎結果元件
                            this.type        = this.id; // 將中獎結果賦值給type,顯示對應的抽獎結果元件
                            setTimeout( () => {
                                console.log(this.award.id);
                            },0);
                            return; // 抽中獎後停止定時器
                        }
                    //若抽中的獎品不存在,則加速轉動    
                    } else { 
                        // todo:如果後端介面200且返回的中獎結果是錯的,這裡可以處理下異常
                        this.speed -= this.diff;
                    }
                    this.move();
                }, this.speed );
            },

    4.3 狀態管理,在呼叫move() 抽獎動畫的之前,就對相應的使用者狀態做處理,未登陸的吊起登陸,沒有次數的去獲取次數,不可抽獎呼叫彈窗等等

    4.4 埋點這裡在工具函式裡封裝了一個公共的函式,直接呼叫傳參記錄埋點資訊,關於埋點的話有空再展開

    4.5 樣式方面,遇到了一些問題

  • 最開始的想法是隻改變花瓣的背景圖,但是最後發現,圖片是不規則的,是有角度的,難以定位準確。而且定位位置的計算在不同機型上有差異,所以採用整體圖片的替換
  • 整體圖片的替換又遇到一個閃爍問題:
    成因:因為當圖片花瓣旋轉時視覺上只是每個花瓣的變化,實際上是整張圖片的變化,通過動態的切換calss來完成背景圖片的替換。正因為這樣,新的問題就產生了,當程式碼構建部署打包發不到線上時,靜態資源一般會有單獨的伺服器,也就是說圖片的資源請求會有一定延遲,這就導致了第一次載入點選抽獎的時候,頁面花瓣轉動會有閃爍,而第二次圖片會走快取,所以這個問題只出現一次,但是卻是致命的
    解決方法:把url改為base64的Data URL,實際上就是利用base64編碼把圖片資料翻譯成標準ASCII字元,Data URL是在本地直接繪製圖片,不是從伺服器載入,所以節省了HTTP連線,起到加速網頁的作用,但是弊端就是IE8以下瀏覽器不支援這種方法(當然app內肯定是支援的,絕大部分手機也是支援的)。用這種方法會加重客戶端的CPU和記憶體負擔,總之有利有弊,而且不適合大圖片,針對這個圖片找UI替換了體積更小的圖片,以減輕客戶端的記憶體負擔。

    4.6 針對中獎結果的彈窗,封裝另一個元件,只需要傳遞type的引數就顯示不同的中獎結果,類似的還有掛在到全域性的彈窗元件,異常的時候及時丟擲錯誤彈窗

五 總結和反思

    雖然說現在活動頁比較多且互動複雜,但是可以儘可能的封裝一些公共的元件,提供基本的骨架,只需要修改一些css就能快速完成一個功能。

    還有對於沒有做過的東西要具體分析,拆解成步驟,一步一步的完成,同時預留好一定的buffer時間,最重要的,經常總結與反思,查詢自身的不足,在繁忙的工作中提升自己。

相關文章