Erlo

JI-UI适用于微信小程序的UI库(二)——j-local-popup点击位置弹出层

时间:2021-06-25   阅读:62次   来源:开源中国
页面报错
点赞

读者你好,我将在这一系列文章中逐步更新JI-UI的公共UI库。但在短期内只会更新由我创作的部分。

问题的引出

全局弹出层无疑的最常见的弹出层实现,但是它带来的问题。在我看来,不够轻型化,难以胜任某些场景。 我希望,可以实现如下的行为:

如图可以看到,我在点击选择字体颜色图标时,弹出层会跟随鼠标点击(实际中当然是跟随用户触碰)弹出。

问题的解决

要点

  • 要获取用户点击位置;事件里会有
  • 要获取弹出层的宽高;这里肯定要动态获取,通过this.createSelectorQuery()实现
  • 确定弹出层的位置;要考虑到不能超出页面边界,以及从实用性的角度,应该考虑从上方弹出、从下方弹出以及从左边、从右边弹出。
  • 弹出层怎么取消?我们考虑了如何弹出,但是也务必考虑它的注销流程。实际上我们在设计自定义组件的时候,应当考虑它的整个生命周期。简略来说,即组件的创建、工作、销毁。

解决问题

组件的wxml部分






  

解析一下,这段代码中中存在两个插槽,其中一个为main,另一个为popup;

main是设计给被点击对象的,这样子想使用触碰弹出层的话方式会非常简单,只需要把原本的代码带上slot="main"放进组件中即可

以下边这段代码为例,我们希望点击它可以弹出“Love you”。


     hello

只需要:

 
   
     hello
   
   Love you

同样的,slot名为popup的组件将作为点击后的弹出层出现。


组件的js部分

阅读了wxml部分,你应当知道组件是创建方法是openPopup,销毁它则是通过closePopup

下边是openPopup的解析,closePopup较为简单,如果有需要可以自行在git中查看。

openPopup(e){
      var that=this;
      let detail=e.changedTouches[0];
      var top=detail.clientY;
      var left=detail.clientX;
      var width=0;
      var height=0;
      new Promise((resolve,reject)=>{
        that.setData({
          visible:true,
          ishow:true
        },()=>{
          let o = that.createSelectorQuery().select(".out-class").boundingClientRect(rect => {
            width=rect.width;
            height=rect.height;
          }).exec((res)=>{
            resolve(res[0])
          });
        })
      }).then(res=>{
        if (that.properties.position=='top') {
          that.setData({
            top:top-(height*10)-5,
            left:left-(width*10/2),
            show:true
          })
        }
      })
    }

基本上,代码由三步组成。

1. 开始渲染组件

that.setData({
    visible:true,
    ishow:true
}

2.在渲染完组件后获取popup插槽父组件的高度、宽度

that.createSelectorQuery().select(".out-class").boundingClientRect(rect => {
        width=rect.width;
        height=rect.height;
    }).exec((res)=>{
        resolve(res[0])
});

3. 处理top从上方弹出

that.setData({
    top:top-(height*10)-5,
    left:left-(width*10/2),
    show:true
})

这里对height和width进行*10是因为初始状态通过scale(0.1)改变了组件的大小,-5则是一定程度的偏移。


组件的动画效果

演示图中,我们看到的是组件的放大缩小显隐,从我个人的角度我认为这种形式的动画会让我更舒适。

这种效果并不是很难做到。

opacity:0;

transform:scale(0.1)

opacity改变透明度,transform中的scale改变大小。

当我们把这两个初始值取消,并在tranistion中配置好贝塞尔曲线、影响参以及动画时间

transition: all ease .6s;

于是我们便完成了这个简单的动画


一个有趣的事情

有一位初学前端的朋友问我,为什么你在动画里不通过改变width和height实现,是因为这个函数方便么?

显然不能只是这样......

transform里几个函数都有极强的功能。细究会发现其中的translate移动和scale缩放的部分或者全部功能其实是可以通过改变其他css属性实现的。

  • 通过直接改变width和height只会改变对应组件的长宽,子组件不会被改变,直接改变长宽适用于卷轴式的动画
  • 通过带有top、left等的属性我们可以改变组件位置,但是为什么我们不应该这样做?因为通过这种方式创建出来的动画不流畅,可能我们的肉眼不一定能很好察觉,但是性能可以好为什么不做好点。

至于为什么通过带有top、left等的属性改变组件位置创建的动画并不流畅,这和浏览器的工作机制有关系,之后会专门说明。


Tips&Bugs

tip:使用catchtouch而不是bingtouch或是bindtap,因为点击这里并不希望事件传递出去使得出现输入框失焦等问题

bug:是的,我没有做不能超出页面边界的控制这一部分。因为目前还没遇见该问题,暂且不想花费宝贵的期末复习时间。

 

JI-UI库gitee地址:https://gitee.com/grinzero/ji-ui 文件已经上传了一部分

相关推荐

提交留言

评论留言

还没有评论留言,赶紧来抢楼吧~~

吐槽小黑屋()

* 这里是“吐槽小黑屋”,所有人可看,只保留当天信息。

  • Erlo吐槽

    Erlo.vip2021-09-28 02:22:36Hello、欢迎使用吐槽小黑屋,这就是个吐槽的地方。
  • 返回顶部

    给这篇文章打个标签吧~

    棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认