资讯中心

及时了解相关的市场研究数据和报告,为研究和咨询及IT行业,

电商运营者提供适当前沿资讯。


小程序开发日记 -- 引导提示的实现

发布时间:2020-06-27 10:24:50

微信小程序的个人信息保护现状:独立隐私政策缺位,未授权获取位置信息等屡见不鲜

许多APP、网页在第一次使用时都会出现一个引导操作的小交互,类似下面这种。


支付宝App


这种引导提示一般由三部分构成:一是覆盖在原界面之上的一层蒙版,二是高亮需要提示的地方,最后就是文字说明(或图片)。


那么在小程序中可以实现类似的效果吗?答案是肯定的,不过我们先实现一版简单的效果,明白原理后大家就可以自行扩展了。


简易的引导提示效果


首先,我们需要一个蒙版作为引导层的背景。

<view class='mask' catchtap='_onMaskTap' catchtouchmove='_onTouchMove' hidden='{{!show}}'></view>


其次,也是关键的一个步骤,找到需要高亮的元素部分,使用一个空元素将其大小和位置设置成与高亮元素相同的大小和位置,且背景色设置为白色,然后将高亮元素的z-index提高(至少大于这个空元素的z-index)。注意:可适当调整空元素的大小及位置,让其看起来有种包裹住高亮元素的效果。

<view class='mask' catchtap='_onMaskTap' catchtouchmove='_onMaskTouchMove' hidden='{{!show}}'></view>
<view class='highlight' style="width:{{h.width}};height:{{h.height}};top:{{h.top}};left: {{h.left}};border-radius: {{h.radius}};" hidden='{{!show}}'></view>


最后,添加提示文字区域。注意:如果提示区域的left距离+提示区域的宽度 > 屏幕宽度时,需要将提示区域的left坐标调整到left+提示区域宽度 - 屏幕宽度的位置,并适当留出一定的边距,以免看起来太拥挤。

<view class='mask' catchtap='_onMaskTap' catchtouchmove='_onMaskTouchMove' hidden='{{!show}}'></view>
<view class='highlight' style="width:{{h.width}};height:{{h.height}};top:{{h.top}};left: {{h.left}};border-radius: {{h.radius}};" hidden='{{!show}}'></view>
<view class='tip-container' style="min-width:{{minWidth}}px;top:{{t.top}};left:{{t.left}};" hidden='{{!show}}'>
  <view class="tip-text-wrapper">
    <text class="tip-text">{{tips}}</text>
  </view>
</view>


完整代码如下:

Page({
  data: {
    minWidth: 200
  },
 
  _onMaskTap: function () {
    this.setData({
      show: false
    })
  },
 
  _onMaskTouchMove: function () {
    // 消化掉触摸移动事件,防止事件传递
    return false
  },
 
  /**
  * 创建提示
  * id : 高亮元素id
  * text: 提示文字
  */
  create: function (id, text) {
    let that = this
    const query = wx.createSelectorQuery()
    query.select(id).fields({
      dataset: true,
      size: true,
      rect: true,
      scrollOffset: true,
      properties: ['scrollX', 'scrollY'],
      computedStyle: ['margin', 'backgroundColor'],
      context: true,
    }, function(res) {
      const left = res.left      // 节点的左边界坐标
      const top = res.top        // 节点的上边界坐标
      const width = res.width    // 节点的宽度
      const height = res.height  // 节点的高度
      // const margin = res.margin
      const size = (width > height ? (width + 10) : (height + 10) )
 
      const highLight = {
        width:  (width + 10) + 'px',
        height: (height + 10) + 'px',
        top: (top - 5) + 'px',
        left: (left - 5) + 'px',
        radius: (size * 0.5 ) + 'px'
      }
 
      const realWidth = (left - 5) + that.data.minWidth
      const windowWidth = wx.getSystemInfoSync().windowWidth - 5
      let tipContainer = {}
      if (realWidth >= windowWidth) {
        tipContainer = {
          top: top + height + 'px',
          left: ((left - 5) - (realWidth - windowWidth)) + 'px'
        }
      } else {
        tipContainer = {
          top: top + height + 'px',
          left: (left - 5) + 'px'
        }
      }
 
      that.setData({
        h: highLight,
        t: tipContainer,
        tips: text,
      })
    }).exec()
  },

})

...

<view class="row x-end y-center" catchtap="onTestTap">
  <view id="test" class="{{highlightStyle}}">
    <image src="/images/icon-hot.png" class="icon-size-normal"/>
    <text class="font-small">小测试</text>
  </view>
</view>

...

<view class='mask' catchtap='_onMaskTap' catchtouchmove='_onTouchMove' hidden='{{!show}}'></view>
<view class='highlight' style="width:{{h.width}};height:{{h.height}};top:{{h.top}};left: {{h.left}};border-radius: {{h.radius}};" hidden='{{!show}}'></view>
<view class='tip-container' style="min-width:{{minWidth}}px;top:{{t.top}};left:{{t.left}};" hidden='{{!show}}'>
  <view class="tip-text-wrapper">
    <text class="tip-text">{{tips}}</text>
  </view>
</view>

.mask {
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  position: fixed;
  opacity: 0.8;
  background-color: #000;
  z-index: 999999;
  background: -webkit-gradient(radial,center center,0px,center center,100%,color-stop(0%,rgba(0,0,0,0.4)),color-stop(100%,rgba(0,0,0,0.9)));
  background: -webkit-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);
  background: radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);
}

.highlight {
  position: absolute;
  z-index: 9999998;
  background-color: white;
  border-radius: 8rpx;
  box-shadow: 0 4rpx 30rpx rgba(0,0,0,.4);
}
.tip-container {
  box-sizing: content-box;
  position: absolute;
  z-index: 10000000;
}
.tip-text-wrapper {
  position: absolute;
  width: 100%;
  left: 0rpx;
  top: 20rpx;

  background-color: yellowgreen;
  padding: 20rpx 0rpx 20rpx 0rpx;
  border-radius: 6rpx;
  box-shadow: 0 2rpx 20rpx rgba(0,0,0,.4);
}

.tip-text-wrapper .tip-text {
  padding: 20rpx;
  font-size: 0.8rem;
  color: white;
  font-weight: bold;
}

.active {
  position: relative;
  z-index: 9999999!important;
}


如何使用:

Page({
  onLoad: function (options) {
    ......
    that.create("#test", "提示:五十音测试在这里哦")
    that.setData({
      show: true,
      highlightStyle: 'active'
    })
  }
})


以上就是一个简单的引导提示的实现,不过它还存在许多缺陷。


1. 高亮元素外框和提示文字框不支持异形(如圆形)。

2. 因高亮元素的z-index层级最高,引导蒙版无法覆盖,如果其本身有点击等事件,点击时则可直接触发。可以通过引入变量控制其是否绑定点击事件来解决。

3. 对原生控件,如:inputtext、textarea、video等无法生效。

4. 使用之前要准备的工作太多,如果定义成一个组件的话,可以减少不少步骤。感兴趣的同学可以尝试一下。

5. 不支持多个提示依次展示。


最后,祝大家端午安康。



相关文章

留言板

留言板

电话沟通

0760-8855 4567

TOP