隨機轉盤小程序的設計與實現


1 要求描述
1.1 程序需求描述
·制作一個轉盤小程序,內置多種場景供用戶選擇。用戶可以選擇系統內置的場景,也可以自行添加場景。選擇場景后,用戶可以點擊開始按鈕,轉盤轉動並隨機生成場景中的某一項。
1.2 其他要求描述
·明確要求:使用PSP記錄開發流程所需時間。
·自行要求:該作業為反向工程(https://www.cnblogs.com/ourshiningdays/p/14858512.html)作業的替代。反向工程作業的截止日期為9月15日23時59分59秒(以發博客的時間為准)。因此決定對本作業使用相同的截止日期。
2 分析
2.1 基本功能模塊分析
根據程序需求描述,程序可以分為如下基本功能模塊:
·轉盤模塊:能夠顯示各種選項,能夠正常進行操作、生成隨機結果等。
·場景模塊:該模塊應細分成系統內置場景模塊、用戶自定義場景模塊。
2.2 技術路線及技術可行性分析
技術路線:微信小程序提供官方API文檔,有一套專門的微信小程序API。需要掌握其使用方法。另外,還需使用CSS進行樣式控制、JavaScript進行事件處理、程序功能邏輯處理等。程序暫不需要后端及相關知識。
技術可行性:由於技術路線中涉及的技術棧接觸較少,此前未進行過相關實際開發,預計在實現過程中會遇到相關語法/用法的困難。該小程序的程序邏輯清晰,思路較易獲得。該小程序實現時存在一些需要處理的細節。結合以上分析,若要在6天內基本完成,開發策略是首先快速學習微信小程序最基礎的結構,在語法上“即用即查”、“即學即用”,必要時可能需要參考一些現有demo,優先完成主要核心功能,方可保證在規定時間內的進度。
3 系統實現
3.1 Tab實現
在微信小程序中,可以通過控制app.json中的tabBar項進行Tab的編輯。[1-2]
此處按照要求編寫代碼即可,故直接使用代碼說明:

"tabBar":{
    "borderStyle": "white",
    "selectedColor": "#4A6141",
    "color": "#333",
    "backgroundColor": "#FFF",
    "position": "bottom",
    "list": [
    {
      "pagePath": "pages/wheel/wheel",
      "text": "圓盤",
      "iconPath": "images/wheel_unclicked.png",
      "selectedIconPath": "images/wheel_clicked.png"
    },
    {
      "pagePath": "pages/scene/scene",
      "text": "場景",
      "iconPath": "images/scene_unclicked.png",
      "selectedIconPath": "images/scene_clicked.png"
    }
  ]
 }

3.2 圓盤
圓盤實現是在完成本作業中最困難的部分,該部分在實際開發中首先進行了具體技術棧的查詢,得知一種方式是按照本文第二部分的分析,使用CSS進行繪制,另外有使用canvas進行繪制的方法。
接下來進行該功能模塊總體思路的建構:
I.使用某種方法繪制圓盤、繪制分割線、繪制轉盤開始按鈕
II.通過某種方式進行數據的獲取,數據應該分為一個索引index和選項名,一個index對應一種選項。
III.隨機生成一個[0,length)的整數隨機數作為index。
IV.播放轉盤動畫,轉盤轉動角度是N*360°+(360°/選項個數*index),其中N為轉動圈數。
V.獲得該index對應的選項名,提示給用戶。
根據該思路嘗試編寫代碼,但多次嘗試均未得到正確結果,決定參考一些demo。
由於微信小程序支持模塊化編程[1],在網上無意間找到了與示例小程序極為相似的成熟轉盤組件[3],但直接引用或直接學習該組件使得該作業失去訓練意義,決定不參考該項目,但將該較為成熟的項目在本博客中收錄,供有相關需求的用戶參考使用,也方便自己在未來有需要時進行學習。本作業不考慮直接使用模塊。
經過一段時間的尋找,找到了如附[4]的demo,總體思路與前面自行分析時生成的思路有較高的相似度。
拿到demo首先就是對自己的思路進行對比,發現總體還是基本一致的,但在轉盤轉動角度上,demo作者設置的角度為

app.runDegs = app.runDegs || 0
app.runDegs = app.runDegs + (360 - app.runDegs % 360) + (360 * runNum - selectionIndex * (360 / app.selectionConfig.selection.length))


表達式第三項基本與上述分析IV相似,但作者采用的是減法,這是因為如果按照之前分析IV的方法,如果在繪制轉盤時選項按照順時針順序繪制,旋轉時應該逆時針旋轉才成立。


如圖所示,在填選項的時候按照綠色順時針方向進行,則index如圖所示,指針初始指在[0]處,如直接順時針旋轉360/8*1,停留的是[8]處,這是不對的。而微信默認的動畫旋轉為順時針,因此作者使用減法的方式是正確的,之前IV分析考慮不周全。
另外,由於轉盤轉動一次后,轉盤已經不是初始角度了,這樣在計算的時候必須對當前角度進行處理,或者是像要求中的示例小程序那樣重置轉盤。找到的demo采用了第一種方法。而在我之前分析的時候沒有考慮到這一點問題,是細節疏忽。
該demo中有兩種顏色,我期望的是如要求中的示例小程序一樣繪制多種顏色,繪制思路也比較簡單:
I.事先建立好一個color數組存儲顏色。數組容量=最多允許有幾種選項。
II.循環繪制扇形。將顏色填充為color[i]。
瀏覽作者的demo代碼,作者也是繪制了扇形,但只指定兩種顏色:根據index%2來確定使用哪種顏色。我按照自己的思路進行代碼修改,在模擬器上得到了正確的彩色轉盤。但是此時我並沒有嘗試使用真機測試,在我后續使用真機測試的時候,發現填充的扇形會將圓盤和文字全部蓋住,這是因為扇形采用canvas進行繪制,而canvas在微信小程序中屬於原生組件,無法單獨設置z-index,屬於最高層級,因此它會直接覆蓋住圓盤和文字,並且也沒辦法應用動畫。因此基本論證技術路線的失敗。作者另外給出了一種實現方法,但實際上圓盤只有一種顏色,如想得到多種顏色使用canvas進行繪制,就會復現問題。而此時時間已經來不及,只好暫時作罷。
可能實現轉盤着色的技術路線:CSS、Canvas2d等其他新組件[5]?
有了單色轉盤,便可以進行其他功能的編寫,此時已經在該組件中花費了較多的時間。
3.3 場景模塊
3.3.1 系統內置場景數據
系統內置場景可以使用如下數據結構表示:
selectionConfig:JSON格式數據數組。存儲場景全部信息。
selectionConfig每一項包括:
title:場景標題-String,
chance:是否可以抽獎-Boolean-默認=true,
selection:JSON格式數組。存儲所有選項。
selection包括:
index:int類型。該選項的索引。
name:String類型。該選項的名稱。
將該數據存儲至data/data.js目錄中。
3.3.2 用戶自定義場景數據
數據結構與內置場景數據應一致。但要存儲至微信小程序提供的本地緩存中,使用微信小程序提供的增刪改查接口對其進行訪問及操作[1-2]
3.3.3 內置場景數據的顯示
實現方法如下:
使用wx:for循環對3.3.1所述數據結構進行引用,將調用數據結構的title標題進行數據綁定,即可完成顯示。但需要注意的是,在wxss中寫代碼進行顯示的時候,要添加點擊事件。
點擊事件使用微信小程序的全局變量進行傳遞,使用一個全局變量存儲當前的index,默認為0。在點擊時將該全局變量置為當前index,並切換至轉盤頁,並刷新。切換並刷新的代碼如下[6]

wx.switchTab({
            url: '../wheel/wheel',
            success: function (e) {
                var page = getCurrentPages().pop();
                if (page == undefined || page == null) return;
                page.onLoad();
                page.onReady();
            }
        })


代碼獲取了當前頁面棧的實例,將當前頁彈出,由於程序打開是轉盤頁,切至場景頁時,當前頁的上一頁是轉盤頁,即目標頁。然后重新執行onLoad()和onReady方法,即可重新刷新數據。
3.3.4 用戶自定義場景頁面的實現
用戶自定義場景頁面首先應該做一個頂部tab,切換內置場景和自定義場景。[7]
在自定義場景頁面中要顯示出所有的信息,和上文所述系統內置的場景方法類似,只不過這里要從緩存里讀數據,在data.js中使用userSelection存儲,數據結構同上。使用一個固定的獲得所有數據的方法,如下:

getAllUserSelection() {
        var res = wx.getStorageSync(this.storageKeyName);
        if (!res) {
            res = require('../data/data.js').userSelection;
            this.execSetStorageSync(res);
        }
        return res;
    }

 

在頁面中直接調用該方法即可顯示。
然后應該顯示一個添加場景的按鈕,點擊之后應跳轉到添加場景的頁面中。這里通過頂部tab的index決定是否顯示,為0時是預置場景——不顯示添加按鈕,為1時是用戶場景——顯示添加按鈕,如下: 

 <view wx:if="{{currentIndex == 1}}" class="addBtn" bindtap="onAddBtn">添加場景</view>

點擊該按鈕的事件是跳轉到一個新的添加場景的頁面。
3.3.5 添加頁面的實現
該部分流程如下:
I.生成一個存儲標題的輸入框。
II.生成一個點擊添加選項的輸入框。添加前校驗選項數量。
III.選項輸入框中添加刪除功能。
IV.保存前校驗是否為空。
V.保存至本地緩存數據庫。
使用表單實現,保存按鈕為submit。
具體事件:
每當點擊添加時,如沒有超過最大選項數量,添加一個帶刪除按鈕的輸入框。
每當有輸入事件時,從輸入框中獲取輸入數據保存在數組中。
每當有刪除事件時,從數組中刪除。
點擊保存時,調用isValid函數進行判斷,部分isValid函數代碼如下。

 isValid: function (data) {
        if (data.detail.value.sceneName === ("")) {
            wx.showToast({
                title: '場景名是必填的!',
                icon: "none"
            })
            return false;
        }

        for (var i = 0; i < this.data.array.length; i++) {

            if (this.data.inputVal[i] == undefined || this.data.inputVal[i].length == 0) {
                wx.showToast({
                    title: '您有選項沒填寫!',
                    icon: "none"
                })
                return false;
            }
        }
        return true;
    },


如判斷通過,要進行保存,但這里獲得的輸入數據和上部分描述的數據結構相比有較大差異,這里獲得的只是一個保存輸入信息的數組。因此要進行轉為符合此前的數據結構的格式,然后再進行保存。具體代碼如下:

            var info = {"title":data.detail.value.sceneName,"chance":"true","selection":this.data.saveVal}
            var JSONInfo = JSON.parse(JSON.stringify(info))
            var userSelection = dbPost.getAllUserSelection();
            userSelection.push(JSONInfo)
            wx.setStorageSync('userSelection', userSelection)
            wx.showToast({
              title: '添加成功',
              icon:'success'
            })
            wx.navigateBack();

 

這里有一個功能沒實現好:返回后應該將3.3.4所述頁面數據進行刷新,目前沒有刷新,需要用戶手動切換才能看到剛剛添加的數據。
3.4 圓盤頁面其他相關功能
要求中的示例小程序還有幾個其他的功能。本次作業也對此進行了實現。
3.4.1 標題及副標題
圓盤上方應顯示標題,副標題轉轉盤之前是“???”,轉轉盤之后顯示結果。
實現方法:
直接從數據結構中取得標題進行顯示即可。
副標題固定寫為“???”,轉轉盤之后將轉到的index對應的selection設置為副標題即可。
3.4.2 生成三種建議場景
要求中的示例小程序這部分是簡單的使用內置場景的第1~第3個場景。
本作業中,將這部分進行隨機化。
首先要控制轉盤頁在數據結構中取得三項標題,在注[8]中作者提供了利用wx:if來控制wx:for循環列表數量的方法,但該文章中的index是直接寫進代碼里的,這里進行一下處理,在js中使用random隨機生成一個[0,場景數組長度-3]的整數,該整數存儲在變量randomIndex內,然后在wx-if數據綁定處進行對應的修改,代碼如下: (這里博客園自動把代碼吞掉,先用純文本代替-9.16 21:42)

    <view class="hint">
      <text class="hintRandom"> 我們為您隨機推薦了以下場景:</text>
      <block wx:for="{{selectionInfo}}" wx:for-item="item" wx:for-index="idx"
       wx:if="{{idx>=randomIndex&&idx<randomIndex+3}}">
        <view class="titleList">
          <view bindtap="clicked" id="{{idx}}">
            <text class="hintTitle"> {{item.title}}</text>
          </view>
        </view>
      </block>
    </view>
 

這樣便可以在用戶點擊小程序之后,隨機生成三個連續的場景。
3.5 轉盤背景音樂
在轉盤動畫進行時、提示用戶結果時分別進行音樂的播放,微信小程序中音樂的播放代碼可以按照如下實現:

const bgMusic = wx.getBackgroundAudioManager()
      bgMusic.title = '得到結果';
      bgMusic.src = '音樂網址';
      bgMusic.play();

 

其中需要注意的是.src不支持播放本地音樂,要設法獲取到一個支持外鏈的音樂網址。

3.6 程序截圖

 

4 PSP記錄
PSP表格如下

分類 開始時間 結束時間 中斷時間/min(s) Delta Δ/min(s) 任務內容/描述
Preparing 9.9 22:01 9.9 22:07 0 6 請求本部圖書館《微信小程序開發入門與實踐》
Preparing 9.10 15:13 9.10 15:17 0 4 取書
Reading 9.10 19:33 9.10 19:41 0 8 閱讀前面
Preparing 9.10 19:41 9.10 20:12 1 30 安裝環境、申請賬號、創建項目等
Reading 9.10 20:30 9.10 21:13 1 42 閱讀學習第三章(讀+實踐)
Reading 9.11 00:31 9.11 00:58 3 24 閱讀學習至p72
Reading 9.11 08:17 9.11 08:45 5 23 閱讀學習至p82
Reading 9.11 10:41 9.11 11:09 0 28 閱讀學習至p98
Summarizing 9.11 13:11 9.11 13:29 0 18 反思總結目前遇到的問題。
Searching 9.11 13:39 9.11 14:32 5 48 搜索轉盤繪制所需知識
Preparing 9.11 14:34 9.11 14:54 0 20 收集制作圖片素材
Trying 9.11 15:00 9.11 15:27 0 27 研究繪制轉盤的方法
Trying 9.11 15:43 9.11 17:08 9 76 研究繪制轉盤的方法
Trying 9.11 18:23 9.11 19:27 6 58 研究繪制轉盤的方法
Coding 9.11 22:00 9.11 22:31 1 30 學習、編寫、修改轉盤部分代碼
Coding 9.12 13:32 9.12 16:03 31 120 學習、編寫、修改轉盤部分代碼
Coding 9.12 21:29 9.12 21:48 0 19 學習並編寫Tab部分(完成)
Coding 9.12 22:33 9.12 23:19 6 40 把數據單獨拿出放到data.js
Coding 9.13 14:00 9.13 15:40 3 97 顯示場景列表(CSS未寫);完成點擊內置場景時數據的切換
Coding 9.13 15:53 9.13 16:25 1 31 擴充內置場景數據至10種
Coding 9.13 21:31 9.13 23:07 9 87 完成主頁隨機生成三個連續場景及其點擊后數據的切換功能;補充主頁及場景頁CSS樣式;
Coding 9.14 12:41 9.14 13:20 5 34 場景頁切換tab-CSS
Coding 9.14 14:00 9.14 14:11 1 10 場景頁切換tab-CSS
Coding 9.14 19:04 9.14 19:19 1 14 點擊切換事件代碼結構
Reading 9.14 19:12 9.14 19:30 0 18 讀書尋找關於緩存數據庫內容
Coding 9.14 19:31 9.14 20:43 3 69 僅在用戶自定義場景顯示添加場景按鈕的邏輯判斷,緩存相關代碼的編寫(未實現)
Coding 9.14 22:33 9.14 23:47 3 71 添加按鈕的點擊跳轉事件
Coding 9.15 10:10 9.15 11:38 2 86 添加場景頁面的編寫
Coding 9.15 11:51 9.15 12:29 2 36 添加場景頁面的編寫
Coding 9.15 16:13 9.15 19:04 4 167 添加場景頁面的編寫、保存時對用戶輸入的校驗、保存后數據的存儲及讀取、轉盤對系統內置場景及用戶場景兩種不同情況的數據引用
Coding 9.15 19:40 9.15 20:08 0 28 嘗試添加音樂播放
Blogging 9.15 20:19 9.15 23:35 2 194 撰寫博客
總計       1563  


PSP餅圖如下
 
5 反思與總結
5.1 記錄缺陷
根據導師及組內師兄對其他同學作業的修改意見,得知PSP中斷時間>5分鍾時應分開記錄,>30分鍾時應視為兩個任務,我在收到該意見之前的PSP記錄不符合這一要求,今后記錄時需要加以改正。
5.2 能力缺陷
該程序編寫時所涉及功能的基本思路基本可以知曉,並有一定的正確度,但在具體實現時由於程序完成時間的限制和相關技術棧的不熟練,仍然遇到較多的困難,即使花費了較多的時間,仍然在程序中的一部分參考了他人的demo代碼、部分功能未完善。
5.3 參考時缺陷
上文提到過使用demo遇到的真機無法正確運行的問題。雖然通過分析,知道了問題的原因,但若參考demo前首先測試一下demo能否在模擬器和真機運行成功,將會節省下一些時間,避免時間的浪費。
5.4 本程序目前存在的不足
較要求示例小程序相比,本作業目前存在以下不足:
- 添加場景后,數據不會自動刷新。
- 轉盤只有一種顏色。
- 點擊轉盤時沒有遮罩。
- 用戶自定義場景中尚未加入編輯和刪除的功能。
5.5 本程序目前的額外功能
較要求示例小程序相比,本作業目前存在以下額外功能:
+ 轉盤頁面的提示場景可以隨機生成。
5.6 完成本作業的收獲
+ 初步了解了微信小程序的基本結構,了解了一些組件的使用方法。
+ PSP在實際小項目中的第一次應用。
+ 對JS CSS相關知識的一次學習與實踐。
+ 程序中有很多細節需要考慮。加強了考慮的全面性。
+ 以上反思、導師和師兄提出的意見均為收獲。
+ 降低了對未知技術的恐懼感。
6 引用與致謝

感謝導師及師兄/師姐的閱讀及建議。

感謝如下內容對本作業的幫助。

[1]雷磊.《微信小程序開發入門與實踐》,清華大學出版社

[2]小程序官方文檔.https://developers.weixin.qq.com/miniprogram/dev/framework/
[3]微信小程序 自定義組件之《轉盤.https://blog.csdn.net/qq_23375733/article/details/81274955
[4]本作業中參考的轉盤示例.https://www.wxapp-union.com/forum.php?mod=viewthread&tid=420&highlight=canvas
[5]小程序 canvas 2d 新接口 繪制帶小程序碼的海報圖.https://www.cnblogs.com/alpiny/p/12574017.html
[6]使用 navigator 標簽跳轉 TAB 頁面報錯wx.switchTab: url 不支持 queryString.https://www.ijiaoyu.org/info/4.html
[7]微信小程序實現tab切換和for循環嵌套.https://blog.csdn.net/qq_42543264/article/details/106644155
[8]小程序wx:for循環列表數量的限制.https://blog.csdn.net/qq_38194393/article/details/88024809
[9]小程序開發中var that = this的用法說明.https://blog.csdn.net/qq_32534441/article/details/105607334
[10]前端相關知識速查.https://www.w3school.com.cn/
[11]小程序文字下划線的用法.https://my.oschina.net/u/2494575/blog/2254168
[12]微信小程序中e.target與e.currentTarget區別詳解.https://blog.csdn.net/shadow_zed/article/details/104398191
[13]微信小程序中button中字體默認加粗解決方案.https://blog.csdn.net/sunlit_6/article/details/116974787

7 備注

2021.9.19 14:25更新

·韓師兄指出,本博客第6部分書寫格式不正確,應修改。[9.16 提出 9.19第一次修改]

·位師兄指出,可能有更好的轉盤頁面下方提示文字樣式,如下拉框等。[9.16 提出 待實踐]

發現博客有兩處wxml代碼顯示不全了,重新添加插入還是不全的,之前都是正常的,可能是博客園臨時bug?[9.15發布時正常 9.16發現問題 9.19已修復]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM