支付宝小程序中如何开发营销组件

简介: 运营:刚刚提了个活动需求,咱们还需要拉新,最近用户注册比有下降呀。产品:为了跟用户有互动,表现形式 咱们就用“老虎机”吧,网上demo那么多随便拷拷就能用的吧。开发:要不你来做~ ?闲话不多说,咱们进入正题吧。

老虎机动画效果图.gif

了解到要做的活动表现形式为老虎机,首先当然是google,百度跑跑找找demo,看下人家是怎么实现的。
网上老虎机的插件挺多的,实现原理也各不一样。
这里先给个网上找的老虎机的效果demo: 老虎机效果demo,效果是这么个效果,但是咱们得了解原理吖,看了下源码,jQuery做的?,小程序内又不能用jQuery,咋操作呢?

剖析了一波,划重点(要考的):

css的 background-position属性是设置背景图像的起始位置,那么我们控制背景图在0-3秒的时间内显示不同的位置,再加上过渡动画就可以达到老虎机旋转的效果

实现底部滚动停止后显示弹窗且跟后端返回的中奖码一致
image.png
先贴一段代码

AXML
  <view class="box-1">
    <view class="wheel-boxs">
      <view class="box-list" a:for="{{boxStatus}}" a:key="index">
        <view class="box-text" a:if="{{!isStart}}">{{item}}</view>
        <!-- 核心代码 -->
        <view class="box-image" style="background: url('https://qiniu-image.qtshe.com/20181113wheels.png'); 
         background-position-y: {{isStart ? ((16 - item) * 100) + 1500 + 'rpx' : 0}}; background-size: 100% 100%; 
         transition-property: {{isStart ? 'all' : 'none'}}; transition-delay: {{(index + 1) * 100 + 'ms'}};
         transition-duration: 3.5s;">
        </view>
        {{item}}
      </view>
    </view>
    <view class="start-box">
        <view class="timeStemp" a:if="{{remainTime <= 3600}}">开奖倒计时: {{formatTime}}</view>
        <block a:else>
          <form onSubmit="startDraw" report-submit="true" a:if="{{pageVo.remainCount !== 0}}" >
            <button hover-class="none" formType="submit" class="animate-btn" />
          </form>
          <block a:else>
            <view class="no-draw" a:if="{{status.down>今日次数已用尽,明日再来</view>
            <view class="no-draw" a:else>请完成下方任务获取次数</view>
          </block>
        </block>
    </view>
    <view class="last-tips" a:if="{{remainTime > 3600}}">当前剩余 {{pageVo.remainCount || 0}} 次攒码机会</view>
  </view>
ACSS
.wheel-boxs {
  width: 680rpx;
  padding: 0 80rpx;
  margin-top: 16rpx;
}

.box-list {
  width: 90rpx;
  height: 100rpx;
  background: url(https://qiniu-image.qtshe.com/20190829openseason_03png) no-repeat center center;
  background-size: 100% 100%;
  display: inline-block;
  margin-right: 16rpx;
  overflow: hidden;
}

.box-list:last-child {
  margin-right: 0;
}

.box-tips {
  width: 500rpx;
  height: 54rpx;
  background: #ffcc1a;
  overflow: hidden;
  background-size: 100% 100%;
  margin: 20rpx auto;
  color: #7d2f0e;
  font-size: 24rpx;
  text-align: center;
  line-height: 54rpx;
  margin-top: 36rpx;
  border-radius: 54rpx;
}

.box-text {
  width: 100%;
  height: 100rpx;
  line-height: 100rpx;
  text-align: center;
  font-size: 44rpx;
  color: #FFF;
  font-weight: 600;
  font-family: 'HYRunYuanJ'
}

.box-image {
  height: 1500%;
}

.start-box {
  width: 100%;
  text-align: center;
  margin: 16rpx 0 8rpx;
}

.start-box button {
  width: 290rpx;
  height: 76rpx;
  background: url(https://qiniu-image.qtshe.com/20190829startDrawpng) no-repeat center center;
  background-size: 290rpx 76rpx;
  margin: 0 auto;
}

.timeStemp {
  margin: 24rpx auto 0;
  height: 80rpx;
  padding: 0 32rpx;
  line-height: 80rpx;
  text-align: center;
  color: #7d2f0e;
  background: url(https://qiniu-image.qtshe.com/20190829currt.png) no-repeat left top;
  background-size: 100% 100%;
  border-radius: 30rpx;
  font-size: 32rpx;
  display: inline-block;
}

.no-draw {
  height: 68rpx;
  font-size: 30rpx;
  text-align: center;
  color: #FFF;
  margin: 0 auto;
  border-radius: 68rpx;
  background: #9c9c9c;
  max-width: 400rpx;
  line-height: 68rpx;
}

.last-tips {
  width: 100%;
  text-align: center;
  color: #000;
  font-size: 24rpx;
}

.last-tips text {
  color: #f8294a;
}
JS
var timer = null
var app = getApp()
Page({
  data: {
    season: 1, //当前是第几场
    isStart: false, //是否开始抽奖
    isDialog: false, //是否显示弹窗
    dialogId: 1, //显示第几个弹窗
    remainTime: 3600,
    formatTime: '60分00秒',
    pageVo: {}, //页面基础数据大对象
    boxTips: '本场开学码将在9月30日 19:00截止领取', //页面中部文案显示
    typeTips: '9月30日20点开奖哦!',
    boxStatus: ['码', '上', '有', '红', '包'], //五个抽奖默认文案
    results: [], //抽中的码
  },
  onLoad(options) {
    //引用外部字体
    my.loadFontFace({
      family: "HYRunYuanJ",
      source: 'url("https://qiniu-app.qtshe.com/HYRunYuanJ.ttf")'
    })
    my.showLoading({
      content: '加载中'
    })
  },
  onShow() {
    
  },
//格式化时间
  getdate(timeSteamp) {
    timeSteamp = new Date(timeSteamp)
    let m = timeSteamp.getMonth() + 1
    let d = timeSteamp.getDate()
    return (m < 10 ? "0" + m : m) + "月" + (d < 10 ? "0" + d : d) + "日"
  },
  //初始化页面数据
  initData() {
    let postData = {
      id: 1
    }
    app.ajax(‘xxx’, postDat).then((res) => {
      my.hideLoading()
      if (res.success) {
        this.setData({
          pageVo: res.data
        })
      } else {
        util.toast(res.msg || '团团开小差啦,请稍后再试')
      }
    }, () => {
      my.hideLoading()
      util.toast('团团开小差啦,请稍后再试')
    })
  },
  //开始抽奖
  startDraw(e) {
  //收集一波formId
    util.addFormId(e.detail.formId)
    let postData = {
        season: this.data.pageVo.season
    }
    my.showLoading({
      content: '加载中'
    })
    app.ajax('xxx', postData).then((res) => { //发送请求给后端,拿到中奖码
      my.hideLoading()
      if (res.success) {
        this.setData({
          isStart: true,
          results: res.data.result.split(','), //后端返回的中奖码
          dialogId: res.data.special ? 3 : 2  //显示弹窗,如果有彩蛋显示第三个弹窗,如果没有显示第二个弹窗
        })
        var t = setTimeout(() => {
          this.setData({
            isStart: false,
            isDialog: true, //显示弹窗
            boxStatus: ['码', '上', '有', '红', '包'] //五个抽奖默认文案
          })
          clearTimeout(t)
          this.initData()
        }, 4000)  //页面上内容滚动了4秒,这里延时4秒
      } else {
        util.toast(res.msg || '团团开小差啦,请稍后再试')
      }
    }, () => {
      my.hideLoading()
      util.toast('团团开小差啦,请稍后再试')
    })
  },
  //倒计时日期格式化
  timestamp(time) {
    let min = Math.floor((time / 60) % 60)
    let sec = Math.floor(time % 60)
    min = min < 10 ? '0' + min : min
    sec = sec < 10 ? '0' + sec : sec
    this.setData({
      formatTime: `${min}分${sec}秒`
    })
  },
  //执行倒计时
  countDown(item) {
    clearInterval(timer)
    timer = setInterval(() => {
      if (item === 0) {
        this.initData()
        clearInterval(timer)
      } else {
        item -= 1
        this.timestamp(item)
      }
    }, 1000)
  },
  onShareAppMessage() {
    return {
      title: '“码”上有红包!点我瓜分10万开学季礼金>>',
      path: 'xxx',
      bgImgUrl: 'https://qiniu-image.qtshe.com/20190829zfbshare.jpg'
    }
  },
  onHide() {
    clearInterval(timer)
  },
  onUnload() {
    clearInterval(timer)
  }
})

最后完整的实现效果在这里:
微信小程序版
点我查看完整的视频效果
支付宝小程序版(看着效果卡顿,真机正常)
点我查看完整的视频效果

注意两个点:

  • 旋转的背景图是雪碧图。我这里用到的是这张(https://qiniu-image.qtshe.com/20181113wheels.png)可供参考
  • 控制好图的位移单位,需要计算下,这样才可以让后端返回的值与你的图相匹配。我这里是15个icon所以计算方式如下
<view class="box-image" style="
     background: url('https://qiniu-image.qtshe.com/20181113wheels.png'); 
     background-position-y: {{isStart ? ((16 - item) * 100) + 1500 + 'rpx' : 0}}; 
     background-size: 100% 100%; 
     transition-property: {{isStart ? 'all' : 'none'}}; 
     transition-delay: {{(index + 1) * 100 + 'ms'}}; 
     transition-duration: 3.5s;">
</view>

这里可以封装成自定义组件,传入图片以及数量即可。后面如果有再用到 我会封装下再发出来。

最后说下弹窗显示的图的匹配方法,根据图片大小计算,比较麻烦:
axml

<view class="ci-wrapper">
  <view a:if="{{icontype ==='nomal'}}" class="icon-default  icon-nomal" style=" background-position-y: {{(-24 -  117.86 * (typeId - 1)) + 'rpx'}};"></view>
  <view a:else class="icon-default  icon-fade" style=" background-position-y: {{(-20 - 110.73 * (typeId - 1)) + 'rpx'}}; "></view>
</view>

acss

.ci-wrapper {
}
.icon-default {
  width: 70rpx;
  height: 70rpx;
  background-repeat: no-repeat;
 
}
.icon-nomal {
  background-image: url(https://qiniu-image.qtshe.com/20181113wheels.png);
  background-position-x: -17rpx;
   background-size: 100rpx 1768rpx
}
.icon-fade {
  background-image: url(https://qiniu-image.qtshe.com/20181113wheels_fade.png);
  background-size: 110rpx 1661rpx;
  background-position-x: -18rpx;
}

Js

Component({
  props: {
    icontype: 'nomal',
    iconid: 1
  },
  data: {
    nomalOrigin: {
      x: -17,
      y: -24
    },
    fadeOrigin: {
      x: -17,
      y: -24
    },
    typeId: 1
  }
})

以上就是一个完整小程序的老虎机实现方案,有什么优化点大家可以指出来,后续会整理一下出个文件拷贝就可使用。
因为支付宝端,暂无代码片段功能,所以写了个微信小程序版本的代码片段:https://developers.weixin.qq.com/s/1k5eSnmh7z72

相关文章
|
15天前
|
人工智能 小程序
【一步步开发AI运动小程序】十五、AI运动识别中,如何判断人体站位的远近?
【云智AI运动识别小程序插件】提供人体、运动及姿态检测的AI能力,无需后台支持,具有快速、体验好、易集成等特点。本文介绍如何利用插件判断人体与摄像头的远近,确保人体图像在帧内的比例适中,以优化识别效果。通过`whole`检测规则,分别实现人体过近和过远的判断,并给出相应示例代码。
|
1天前
|
运维 小程序 前端开发
结合圈层营销策略,打造稳定可靠的圈子app系统,圈子小程序!
圈子系统是一种社交平台,用户可按兴趣、职业等创建或加入“圈子”,进行内容发布、讨论和资源共享。开发时需考虑需求分析、技术选型(如PHP、MySQL)、页面设计、功能实现(注册、登录、发布、评论等)、测试优化及运维管理。圈层营销则通过精准化、高端化的方式传递品牌信息,增强客户归属感。圈子小程序基于微信等平台,具备跨平台、便捷性和社交性,开发过程中需明确需求、选择技术框架、设计页面并确保稳定性和流畅性。
|
8天前
|
人工智能 小程序 API
【一步步开发AI运动小程序】十七、如何识别用户上传视频中的人体、运动、动作、姿态?
【云智AI运动识别小程序插件】提供人体、运动、姿态检测的AI能力,支持本地原生识别,无需后台服务,具有速度快、体验好、易集成等优点。本文介绍如何使用该插件实现用户上传视频的运动识别,包括视频解码抽帧和人体识别的实现方法。
|
14天前
|
人工智能 小程序 UED
【一步步开发AI运动小程序】十六、AI运动识别中,如何判断人体站位?
【云智AI运动识别小程序插件】提供人体、运动及姿态检测的AI能力,本地引擎无需后台支持,具备快速、体验好、易集成等优势。本文介绍如何利用插件的`camera-view`功能,通过检测人体站位视角(前、后、左、右),确保运动时的最佳识别率和用户体验。代码示例展示了如何实现视角检查,确保用户正或背对摄像头,为后续运动检测打下基础。
|
20天前
|
人工智能 小程序 API
【一步步开发AI运动小程序】十三、自定义一个运动分析器,实现计时计数02
本文介绍如何利用“云智AI运动识别小程序插件”开发AI运动小程序,详细解析了俯卧撑动作的检测规则构建与执行流程,涵盖卧撑和撑卧两个姿态的识别规则,以及如何通过继承`sports.SportBase`类实现运动分析器,适用于小程序开发者。
|
13天前
|
移动开发 小程序 PHP
校园圈子论坛系统采取的PHP语音和uni账号开发的小程序APP公众号H5是否只需要4800元?是的,就是只需要4800元
关于校园圈子论坛系统采用PHP语言和uni-app开发的小程序、APP、公众号和H5是否仅需4800元这个问题,实际上很难给出一个确定的答案。这个价格可能受到多种因素的影响
49 8
|
9天前
|
人工智能 小程序 数据处理
uni-app开发AI康复锻炼小程序,帮助肢体受伤患者康复!
近期,多家康复机构咨询AI运动识别插件是否适用于肢力运动受限患者的康复锻炼。本文介绍该插件在康复锻炼中的应用场景,包括康复运动指导、运动记录、恢复程度记录及过程监测。插件集成了人体检测、姿态识别等功能,支持微信小程序平台,使用便捷,安全可靠,帮助康复治疗更加高效精准。
|
15天前
|
人工智能 小程序 JavaScript
【一步步开发AI运动小程序】十四、主包超出2M大小限制,如何将插件分包发布?
本文介绍了如何从零开始开发一个AI运动小程序,重点讲解了通过分包技术解决程序包超过2M限制的问题。详细步骤包括在uni-app中创建分包、配置`manifest.json`和`pages.json`文件,并提供了分包前后代码大小对比,帮助开发者高效实现AI运动功能。
|
6月前
自适应IT互联网营销企业网站pbootcms模板
一款蓝色自适应IT互联网营销企业网站pbootcms模板,该模板采用响应式设计,可自适应手机端,适合一切网络技术公司、互联网IT行业,源码下载,为您提供了便捷哦。
61 2