• 《微信小程序-进阶篇》Lin-ui组件库源码分析-Button组件(二)


    大家好,这是小程序系列的第十五篇文章,在这一个阶段,我们的目标是 由简单入手,逐渐的可以较为深入的了解组件化开发,从本文开始,将记录分享lin-ui的源码分析,期望通过对lin-ui源码的学习能加深组件化开发的能力:
    1.《微信小程序-进阶篇》package.json必须掌握的字段知识(二)
    2.《微信小程序-进阶篇》Lin-ui组件库的安装与引入
    3.《微信小程序-进阶篇》Lin-ui组件库源码分析-Button组件(一)
    ——
    求关注,求收藏,求点赞,这是一个系列文章,建议专栏收藏,肯定分享的都是跟小程序相关的,旨在能提高在小程序中的能力,谢谢~

    前言

    上一篇我们介绍了Button组件,我们从文件结构的角度大致预览了一遍Button组件的实现,了解了button组的文件结构以及属性中样式属性的实现,本篇主要的内容为Button组件的功能属性以及事件相关知识~

    阅读对象与难度

    本文难度属于:中级,通过本文你可以了解到 Lin-ui的Button组件中功能属性以及事件在其背后是如何运转的一些知识,本文主要内容参考以下思维导图:
    在这里插入图片描述

    Button组件

    功能属性

    这类属性的实现难度往往要 大于 单纯的 样式属性,它除了 样式进行变化,还会涉及要一些功能的变动,接下来我们一个一个来学习lin-ui中的Button的功能属性:

    loading属性

    loading属性 一共有两部分实现,第一部分为 css,这部分主要承担的职能为 样式 以及 动画 的实现,第二部分为 逻辑代码,主要实现的功能是当value值为 true/false 的时候,dom元素 显示/隐藏,先看第一部分,以下就是Lin-ui中CSS部分的源码

     // Loading
    &-loading{
        opacity: 0.6;
        display: inline-block;
        vertical-align: middle;
        width: 24rpx;
        height: 24rpx;
        background: transparent;
        border-radius: 50%;
        border: 4rpx solid @btn-loading-color;
        border-color: @btn-loading-color @btn-loading-color @btn-loading-color transparent;
        animation: btn-spin 0.6s linear;
        animation-iteration-count: infinite;
    }
    
    @keyframes btn-spin {
        0% {
            transform: rotate(0);
        }
        100% {
            transform: rotate(360deg);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    我们可以看到 loading 的动画就是执行了一个名为 btn-spinanimation,而这个 animation 的动画效果为 做360度的旋转,持续时间为0.6s
    逻辑代码则就是一个 wx:if 的判断

     <view wx:if="{{loading}}" class="l-btn-loading {{'margin-' + size}} {{ plain ?'l-btn-loading-' + type : '' }}">view>
    
    • 1

    我们可以看到当loading的值为true的时候,显示这个带有动画的DOM,为false的时候则销毁;

    思考
    当看到这里的时候,其实我个人感觉 loading这一块应该单独拆分成一个组件,因为loading效果个人觉得这是一个非常常见的效果,不应该仅仅只在button中出现,至少包括请求时的遮罩层上的loading动画;

    因此比较合适的做法是 为了保证组件库中动画的一致性,loading组件,或者至少说loading的动画应该是 统一管理 的,而使用的时候应该类似以下这种,通过参数将显示不同的loading动画

    <l-loading animate="{{type}}">l-loading>
    
    • 1

    当然,这个仅仅是针对button组件阅读的思考,可能会作者有别的考量没有这么实现,或者说这种做法有别的弊端是博主没有考虑到的;

    disabled属性

    disabled属性 同样有两部分组成,一部分 css,这部分包括了当添加disabled样式时按钮显示的状态,另外一部分则为 逻辑代码,这部分 其实和loading的实现接近,也就是 disabled 为true的时候触发效果,先看css代码

    // Disabled
    &-disabled{
        opacity: 0.8;
    }
    
    • 1
    • 2
    • 3
    • 4

    css的代码一共只有以上者一条,就是说当处于 disabled 状态时 button 整体的透明度改成0.8,接着看判断代码

     view>
    
    • 1
    • 2

    它在模版中写了一个 三元表达式,通过判断 disabled 的值是否为 true 来决定是否将 l-btn-disabled 这个class类名添加到DOM上;

    disabledHover属性

    这个属性的作用为 是否禁用禁用 hover 效果,实现机制与 disabled 几乎完全一致,简单的说就是hover的样式单独写在了 btn-hoverl-hover-class 里,当 disabled 或者 disabledHover 为true的时候,将这个类名去掉,相当于去掉了带有hover效果的样式

     <view class="l-btn "
           hover-class="{{disabled?'':disabledHover?'':'btn-hover l-hover-class'}}"
          >
    view>
    
    • 1
    • 2
    • 3
    • 4

    插槽

    Button的插槽一共 只有一个,而且还是默认的,Lin-Ui中直接将它放在了icon组件的后面,如下代码所示

    <view class="l-btn {{ 'l-btn-' + size }} {{ 'l-btn-' + type }} {{ 'l-btn-' + shape }} {{plain?'l-btn-plain':''}} {{ disabled ? 'l-btn-disabled' : ''}} l-class "
          hover-class="{{disabled?'':disabledHover?'':'btn-hover l-hover-class'}}"
          hover-stop-propagation="{{hoverStopPropagation}}"
          hover-start-time="{{hoverStartTime}}"
          hover-stay-time="{{hoverStayTime}}"
          style="{{width?'min-width:'+width+'rpx;':''}} {{height?'height:'+height+'rpx;'+'line-height:'+height+'rpx;':''}} {{size=='long'?'border-radius:0;':''}} {{'background-color:'+bgColor}}">
      <view wx:if="{{loading}}" class="l-btn-loading {{'margin-' + size}} {{ plain ?'l-btn-loading-' + type : '' }}"></view>
      <l-icon l-class="l-icon-class" class="{{'margin-' + size}}" wx:if="{{icon}}" name="{{icon}}" color="{{iconColor}}" size="{{iconSize}}" />
      
      <slot/>
    
    </view>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这样也就实现了当输入文字的时候,文字出现的位置在loading动画图表的后方

    <l-button loading="{{true}}">测试按钮</l-button>
    
    • 1

    我们可以做一个实验,调整插槽的位置,我们将插槽的位置调整到loading前面去,如下代码

    <view class="l-btn {{ 'l-btn-' + size }} {{ 'l-btn-' + type }} {{ 'l-btn-' + shape }} {{plain?'l-btn-plain':''}} {{ disabled ? 'l-btn-disabled' : ''}} l-class "
          hover-class="{{disabled?'':disabledHover?'':'btn-hover l-hover-class'}}"
          hover-stop-propagation="{{hoverStopPropagation}}"
          hover-start-time="{{hoverStartTime}}"
          hover-stay-time="{{hoverStayTime}}"
          style="{{width?'min-width:'+width+'rpx;':''}} {{height?'height:'+height+'rpx;'+'line-height:'+height+'rpx;':''}} {{size=='long'?'border-radius:0;':''}} {{'background-color:'+bgColor}}">
      
      <slot/>
      
      <view wx:if="{{loading}}" class="l-btn-loading {{'margin-' + size}} {{ plain ?'l-btn-loading-' + type : '' }}">view>
      <l-icon l-class="l-icon-class" class="{{'margin-' + size}}" wx:if="{{icon}}" name="{{icon}}" color="{{iconColor}}" size="{{iconSize}}" />
    view>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    那么按钮的文字应该是在loading的动画前面,结果也确实如我们所料
    在这里插入图片描述

    事件实现

    lin-ui中Button组件的事件 常规 的只有1个,叫做:handleTap,它被绑定在按钮的顶层元素上,位置如下

    <label for="{{name}}" mut-bind:tap="handleTap" class="l-label-class">
      // 其它代码
    </label>
    
    • 1
    • 2
    • 3

    绑定的方式则通过 mut-bind 来绑定(如果不清楚mut-bindbindcatch等关键词代表的含义,可以查看博主的另外一篇博文:《微信小程序-基础篇》小程序中的事件与冒泡),handleTap 实现代码如下,也是非常简单的:

      methods: {
        // button点击事件
        handleTap() {
          if (this.data.disabled || this.data.loading) return false;
          this.triggerEvent('lintap', {}, {
            bubbles: true,
            composed: true
          });
        },
        // 开放能力事件回调
        openTypeEvent(data) {
          this.triggerEvent(data.type, data.detail, {});
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    代码首先判断了当前组件的状态,如果当前组件处于disabled或者loading状态时,按钮不可点击,接着就是触发了 lintap 这个 自定义事件 了,这里我们知道了如果想要触发点击事件,比如通过如下方式触发

    <l-button bind:lintap="handleClick"><l-button>
    
    • 1

    既然知道了事件名是在这里写入的,那么我们理所当然的也可以修改,比如我们将自定义事件名改为tTap,如下

    <l-button bind:tTap="handleClick"><l-button>
      
    methods: {
        // button点击事件
        handleTap() {
          if (this.data.disabled || this.data.loading) return false;
          this.triggerEvent('tTap', {}, {
            bubbles: true,
            composed: true
          });
        },
        // 开放能力事件回调
        openTypeEvent(data) {
          this.triggerEvent(data.type, data.detail, {});
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    点击后如期打印了结果,符合我们的猜想
    在这里插入图片描述

    看到这里,可能有小伙伴会问,官网上的时间不是挺多的吗,怎么只介绍了一个 lintap,其实剩下的那些事件都属于开放能力,lin-ui也只是做了一层转发,实际上都是小程序官方提供的能力,源码中我们也没有看到对对应的事件有任何其他操作;

    小结

    本文主要讲述了Lin-UI的几个功能属性的实现,其实还是挺简单的,说到底就是 通过三元表达式判断了一下样式或者DOM是否显示,接着我们看了下Button中的 插槽,它仅有一个插槽用作文字的录入,最后是事件,我们通过 分析了事件的代码并且尝试修改了自定义事件名
    (PS:都已经看到这里了,点个赞,求个关注吧,万分感谢~)

  • 相关阅读:
    域名列入备案黑名单解除教程
    STM32CubeMX教程19 I2C - MPU6050驱动
    nginx的下载安装配置(Window)
    Axios+Elementui+Vue+原生JS+后端原生java的JAVA web小组项目踩坑总结
    Ps 滤镜:旋转扭曲
    HM-RocketMQ2.7【整体联调、项目优化】
    windows下安装配置CGAL
    [附源码]计算机毕业设计云南美食管理系统Springboot程序
    计算机网络中拥塞控制的门限值怎么设置
    Vue根据条件更改列表明细某一行的背景颜色-简单实现
  • 原文地址:https://blog.csdn.net/zy21131437/article/details/126023188