<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何優(yōu)雅的實(shí)現(xiàn)一個九宮格抽獎

          共 2801字,需瀏覽 6分鐘

           ·

          2020-07-10 18:23

          作者:黃鵬

          如何優(yōu)雅的實(shí)現(xiàn)一個九宮格抽獎

          九宮格抽獎是在移動端常見開發(fā)功能點(diǎn)之一,那如何實(shí)現(xiàn)一個高度可復(fù)用的九宮格邏輯就顯的特別重要了。接下來我們來分析下如何實(shí)現(xiàn)一個優(yōu)雅的抽獎功能。

          功能分析

          9e3c2d640093210cd9307925f466f029.webpimage.png

          圖片1

          實(shí)現(xiàn)功能:

          1. 按照右圖箭頭的方向進(jìn)行旋轉(zhuǎn)。
          2. 旋轉(zhuǎn)到某一個 格子 可以進(jìn)行一定的操作。比如到達(dá)當(dāng)前的 格子 進(jìn)行高亮, 等功能。
          3. 旋轉(zhuǎn)的速度由 ?停 -> 加速 -> 勻速 -> 減速 -> 停。


          方案:

          分析完了九宮格需要實(shí)現(xiàn)的功能,現(xiàn)在介紹一下實(shí)現(xiàn)方案。


          方案一

          基于setTimeout 的旋轉(zhuǎn)方式。通過不斷的改變setTimeout 的時間來控制旋轉(zhuǎn)速度的快慢,實(shí)現(xiàn)代碼如下:

          // count 代表旋轉(zhuǎn)的圈數(shù),id, 表示?停止的id, cb 表示動畫結(jié)束后執(zhí)行的函數(shù)。
          function?start(count,?id,?cb)?{
          ???var?sortArr?=?[1,?2,?3,?6,?9,?8,?7,?4];?//?旋轉(zhuǎn)的順序
          ???var?i?=?0;
          ???//?最大速度?150
          ???var?timeout?=?200;?//?走一格所花的時間,時間越大,速度越慢。
          ???var?that?=?this;
          ???for?(var?m?=?0;?m??????if?(that.imgdata[sortArr[m]?-?1].id?==?id)?{
          ???????break;
          ?????}
          ???}
          ???var?middle?=?sortArr.length?*?count?+?m?+?1;//?計(jì)算需要走多少格
          ???function?rotate()?{
          ?????//?結(jié)束條件
          ?????if?(i?>?sortArr.length?*?count?&&?that.imgdata[that.current?-?1].id?==?id)?{
          ???????clearInterval(that.time);
          ???????that.time?=?null;
          ???????cb();
          ???????return;
          ?????}
          ?????//?控制加,減速度。
          ?????if?(i????????timeout?=?timeout?-?160?/?middle?*?count;
          ?????}

          ?????if?(i?>?(count?-?1)?*?middle?/?count)?{
          ???????timeout?=?timeout?+?500?/?middle?*?count;
          ?????}
          ?????if?(i?==?middle?-?2)?{
          ???????timeout?=?600;
          ?????}
          ?????if?(i?==?middle?-?1)?{
          ???????timeout?=?1000;
          ?????}
          ?????//?獲取當(dāng)前停留格子的數(shù)據(jù),
          ?????that.current?=?sortArr[i++?%?sortArr.length];
          ?????setTimeout(rotate,?timeout);
          ???}
          ???this.time?=?setTimeout(rotate,?timeout);
          ?}
          }


          優(yōu)點(diǎn):動畫效果是比較好看的。有加速,勻速減速過程。
          缺點(diǎn):和頁面相關(guān)太密切。不利于復(fù)用。(pass)


          方案二

          基于sass 實(shí)現(xiàn)。通過先寫出所有小方格的css,(每一個停留區(qū)間實(shí)現(xiàn)一套css。八個就寫八次。)然后js 中只需要不停的替換class名稱就行了。代碼如下:

          @mixin qianzhuai($animationname,$name){
          #{$animationname}: $name;
          -moz-#{$animationname}: $name;
          -o-#{$animationname}: $name;
          -ms-#{$animationname}: $name;
          -webkit-#{$animationname}: $name;
          }
          .choosed {
          position: absolute;
          width: 100%;
          height: 100%;
          top: 0;
          left: 0;
          // animation-name: loader1;
          @include qianzhuai(animation-name,loader1);
          @include qianzhuai(animation-duration,3s);
          @include qianzhuai(animation-timing-function,steps(1,end));
          @include qianzhuai(animation-iteration-count,1);
          @include qianzhuai(animation-fill-mode,forwards);
          }

          @mixin transform($transforms) {
          transform: $transforms;
          -moz-transform: $transforms;
          -o-transform: $transforms;
          -ms-transform: $transforms;
          -webkit-transform: $transforms;
          }
          @function sqrt ($x) {
          @if $x < 0 {
          @warn "Argument for `sqrt()` must be a positive number.";
          @return null;
          }
          $ret: 1;
          @for $i from 1 through 24 {
          $ret: $ret - ($ret * $ret - $x) / (2 * $ret);
          }
          @return $ret;
          }
          // translate
          @mixin translate ($x, $y) {
          @include transform(translate($x, $y));
          }
          $positions: (-100%,-100%) (0%,-100%) (100%,-100%) (100%,0%) (100%,100%) (0%,100%) (-100%,100%) (-100%,0%);
          // rotate
          @mixin calc($positions,$rotatetimes,$stopposition) {
          $arrrlen: length($positions);
          $alllength: length($positions) * $rotatetimes + $stopposition ;
          @for $i from 0 through ($arrrlen *$rotatetimes + $stopposition) {
          $item: nth($positions, ($i % $arrrlen)+1);
          $first: nth($item, 1);
          $second: nth($item,2);
          $index:1;
          @if $i <= $arrrlen {
          $index:20/sqrt($arrrlen)*sqrt(($i));

          }@else if $i <= ($alllength - $arrrlen + 5) {
          $index:20 + 25/($alllength - 2*$arrrlen) * ($i - $arrrlen) ;
          }@else{
          $index:45 + 55/(4 * 4)* (($i - ($alllength - $arrrlen + 4 ))*($i - ($alllength - $arrrlen + 4 )))
          }
          #{$index}% {
          @include translate($first, $second);
          }
          }
          }
          @mixin allrotate($name,$positions,$rotatetimes:4, $stopposition:0) {

          @keyframes #{$name}{
          @include calc($positions,$rotatetimes, $stopposition);
          }
          // @-o-keyframes #{$name}{
          // @include calc($positions,$rotatetimes, $stopposition);
          // }

          }

          @include allrotate('rewards0',$positions,4,0);
          @include allrotate('rewards1',$positions,4,1);
          @include allrotate('rewards2',$positions,4,2);
          @include allrotate('rewards3',$positions,4,3);
          @include allrotate('rewards4',$positions,4,4);
          @include allrotate('rewards5',$positions,4,5);
          @include allrotate('rewards6',$positions,4,6);
          @include allrotate('rewards7',$positions,4,7);

          我們可以看到,基本上是將js部分的代碼搬到sass 中,減少js 代碼的冗余,并通過css 3d 加速,使用頁面效果更加流暢。
          總結(jié)
          優(yōu)點(diǎn):因?yàn)橛胏ss寫的,效果看起來比js寫起來的順滑許多。
          缺點(diǎn):兼容代碼過去。且不易擴(kuò)展。如果不是九宮格,是十宮格,十一宮格。修改的地方感覺就多了。(pass)
          **

          方案三 (終極方案):

          通過上訴的兩種方案,發(fā)現(xiàn)都不是十分通用。那么如何寫出更加通用的代碼。便于大家使用呢?
          經(jīng)過多次嘗試,發(fā)現(xiàn)九宮格有如下特點(diǎn):

          1. 雖然是旋轉(zhuǎn)效果,但是旋轉(zhuǎn)方式各有不同。因此不應(yīng)該過多依賴于css(方案二的弊端)。
          2. 九宮格,抽獎是抽八個獎。但是有可能抽九個獎,十個獎項(xiàng)。
          3. 旋轉(zhuǎn)的方向也不同。(方向也應(yīng)該自定義)


          367629fbc73ca6b3e19860fcbffbfba1.webp

          定義合理的數(shù)據(jù)結(jié)構(gòu)。(采用鏈表的形式)
          ?服務(wù)端返回的獎品信息列表的一般形式,可能會有其他信息,這里就不列出來了。

          ?//?服務(wù)端返回的獎品信息列表
          const?prizeList?=?[
          ??{?id:?1?},
          ??{?id:?2?},
          ??{?id:?3?},
          ??{?id:?4?},
          ??{?id:?5?},
          ??{?id:?6?},
          ??{?id:?7?},
          ??{?id:?8?},
          ];

          將我們的數(shù)據(jù)變成鏈表的形式:

          var?rewaridList?=?[
          ??{id:1,next:prizeList[2]},
          ??{id:2,next:prizeList[3]},
          ??{id:3,next:prizeList[5]},
          ??{id:4,next:prizeList[1]},
          ??{id:5,next:prizeList[8]},
          ??{id:6,next:prizeList[4]},
          ??{id:7,next:prizeList[6]},
          ??{id:8,next:prizeListp[7]}
          ];

          這樣子的形式,我們旋轉(zhuǎn)起來就會十分方便,我們拿到數(shù)組中的任意一個,我們就知道他接下來旋轉(zhuǎn)的方向了。
          注意:next 對應(yīng)的值更換的話,就代表其旋轉(zhuǎn)方向的變化。

          如何控制旋轉(zhuǎn)速度:requestAnimationFrame;

          507facce4edee73fc769673cd294dac4.webp
          我們將按照的時間片的方式,給格子分發(fā)時間片的多少,來實(shí)現(xiàn)視覺上速度的快慢。

          接下來貼出源碼:

          class?LuckDraw?{
          ????constructor(DataArr,?RotateDir,?cycleNumber,?minSpeed)?{
          ??????this.DataArr?=?JSON.parse(JSON.stringify(DataArr));

          ??????//?最大速度
          ??????this.maxSpeed?=?4;
          ??????//?全速
          ??????this.cycleNumber?=?cycleNumber?||?2;
          ??????this.myReq;
          ??????//?最小速度
          ??????this.defaultSpeed?=?minSpeed?||?15;

          ??????for?(var?i?=?0;?i?????????let?{?index,?next?}?=?RotateDir[i];
          ????????if?(typeof?this.DataArr[index].next?!==?"undefined")?{
          ??????????console.error(`RotateDir?is?error`);
          ??????????return;
          ????????}
          ????????this.DataArr[index].next?=?this.DataArr[next]
          ??????}
          ????}

          ????run(id,?running,?runend)?{
          ??????var?counter?=?0;?//?計(jì)數(shù)器
          ??????var?current?=?0;?//?當(dāng)前數(shù)字值
          ??????var?n?=?0;
          ??????var?currentObj?=?this.DataArr[0];
          ??????var?tem?=?this.DataArr[0];
          ??????while?(true)?{
          ????????if?(n?>?this.DataArr.length)?{
          ??????????console.error(`${id}不存在`);
          ??????????return;
          ????????}
          ????????if?(tem.id?==?id)?{
          ??????????break;
          ????????}
          ????????tem?=?tem.next;
          ????????n++;
          ??????}
          ??????var?allCount?=?this.cycleNumber?*?this.DataArr.length?+?n;
          ??????//?加速區(qū)間
          ??????var?addSpeed?=?this.defaultSpeed?-?this.maxSpeed;
          ??????//?減速區(qū)間
          ??????var?reduceSpeed?=?allCount?-?(this.defaultSpeed?-?this.maxSpeed);
          ??????this.running?=?running;
          ??????this.runend?=?runend;
          ??????var?_this?=?this;
          ??????this.running(currentObj);
          ??????this.myReq?=?requestAnimationFrame(step);
          ??????function?step()?{
          ????????//?current++;
          ????????//?加速環(huán)節(jié)
          ????????if?(counter???????????if?(current?Math.pow(_this.defaultSpeed?-?counter,?2))?{
          ????????????current?=?current?+?_this.defaultSpeed?/?2;
          ??????????}?else?{
          ????????????current?=?0;
          ????????????//?往前移動一個;
          ????????????counter++;
          ????????????currentObj?=?currentObj.next;
          ????????????_this.running(currentObj);
          ??????????}
          ????????}
          ????????//?勻速環(huán)節(jié)
          ????????if?(counter?>=?addSpeed?&&?counter???????????if?(current?????????????current++;
          ??????????}?else?{
          ????????????//?計(jì)數(shù)清零
          ????????????current?=?0;
          ????????????//?往前移動一個;
          ????????????counter++;
          ????????????currentObj?=?currentObj.next;
          ????????????_this.running(currentObj);
          ??????????}
          ????????}
          ????????//?減速環(huán)節(jié)
          ????????if?(counter?>=?reduceSpeed?&&?counter???????????if?(Math.sqrt(current)?<=?(_this.defaultSpeed?-?(allCount?-?counter)))?{
          ????????????current?=?current?+?2;
          ??????????}?else?{
          ????????????//?計(jì)數(shù)清零
          ????????????current?=?0;
          ????????????//?往前移動一個;
          ????????????counter++;
          ????????????currentObj?=?currentObj.next;
          ????????????_this.running(currentObj);
          ??????????}
          ????????}
          ????????//?停止
          ????????if?(counter?>=?allCount)?{
          ??????????_this.runend(currentObj);
          ??????????cancelAnimationFrame(_this.myReq);
          ??????????return;
          ????????}
          ????????_this.myReq?=?requestAnimationFrame(step);
          ??????}
          ????}
          ??}

          使用方式:

          //?服務(wù)端返回的獎品信息列表
          const?prizeList?=?[
          ??{?id:?1?},
          ??{?id:?2?},
          ??{?id:?3?},
          ??{?id:?4?},
          ??{?id:?5?},
          ??{?id:?6?},
          ??{?id:?7?},
          ??{?id:?8?},
          ];

          //?旋轉(zhuǎn)規(guī)則數(shù)組?
          const?rotateDir?=?[
          ??{?index:?0,?next:?1?},
          ??{?index:?1,?next:?2?},
          ??{?index:?2,?next:?3?},
          ??{?index:?3,?next:?4?},
          ??{?index:?4,?next:?5?},
          ??{?index:?5,?next:?6?},
          ??{?index:?6,?next:?7?},
          ??{?index:?7,?next:?0?},
          ]

          //?初始化抽獎,?3代表圈數(shù),?8代表速度,也代表時間片的個數(shù)
          const?luckDrawFn?=?LuckDraw(prizeList,?rotateDir,?3,?8);

          //?中獎id,請求服務(wù)端接口拿到
          const?id?=?7;

          luckDrawFn.run(
          ??id,?//中獎id
          ??params?=>?{?//?停留在當(dāng)前格子的回調(diào)函數(shù)
          ????//?拿到當(dāng)前?active?狀態(tài)的?id
          ????this.rewardId?=?params.id;
          ??},
          ??params?=>?{?//?最終停止的回調(diào)函數(shù)
          ????//最后轉(zhuǎn)盤停止的地方,可以彈出獎勵彈框或其他操作
          ????this.rewardId?=?params.id;
          ??})


          總結(jié):這樣子實(shí)現(xiàn),我們每次更改的只有,prizeList, rotateDir,操作邏輯可以寫在兩個提供的回調(diào)函數(shù)中,實(shí)現(xiàn)。這樣子就可以完美的提供給任何人用了,還可以兼容各種復(fù)雜的抽獎情況。



          瀏覽 19
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  熟女性爱电影 | 欧美国家一级a片 | 国产精品卡一卡二卡三 | 小早怜子一区二区三区 | 无码在线中文字幕 |