《微信小程序-进阶篇》Lin-ui组件库源码分析-列表组件List(三)

发布于:2023-01-09 ⋅ 阅读:(614) ⋅ 点赞:(0)

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

前言

上一篇我们了解了 List组件 的部分属性的实现,本篇将 分析剩下的所有属性与事件,并且我们在分析的过程中还发现了一些问题,耐心看完,你一定有所收获~

阅读对象与难度

本文难度属于:初中级,通过本文你可以了解到 Lin-ui的List组件中的属性,事件的实现,属性的解析顺序我们按照上一篇的属性用法顺序进行,本文主要内容参考以下思维导图:
在这里插入图片描述

徽标属性实现

先看张图,回忆一下什么是徽标效果
在这里插入图片描述
就是这个,这个属性相关的有5个

属性 说明 类型 可选值 默认值
badge-position 徽标显示的位置 String left/right/top/bottom right
badge-count-type 徽标数字的显示方式 String overflow/limit/custom overflow
dot-badge 显示圆点徽标 Boolean false/true false
badge-count 徽标的数值 String - -
badge-max-count 徽标数字最大值,超过最大值时显示${max-count}+ Number ----- 99

那么在源码中,这5个属性对应的 properties 如下:

badgePosition: {
  type: String,
  value: 'left'
},
dotBadge: Boolean,
badgeCount: Number,
badgeMaxCount: {
  type: Number,
  value: 99
},
badgeCountType: {
  type: String,
  value: 'overflow'
},

在这一部分,我们发现了3个默认值,分别是 badgePosition 默认为 leftbadgeMaxCount 默认为 99badgeCountType 默认为 overflow,官网看一下是否符合猜想~
在这里插入图片描述

结果发现,不是的.badgePosition 在代码中默认值是 left,但是官网上的默认值填写的却是 right,接下来我们仔细看一下源码,到底 是官方描述错误,还是说这个 在代码内部是反向实现

badgePosition

关于badge相关的html代码,一共有2段,分别是:

<!-- left -->
<l-badge 
   wx:if="{{(badgeCount > 0 || dotBadge ) && badgePosition ==='left'}}" 
   value="{{badgeCount}}" 
   dot="{{dotBadge}}" 
   max-count="{{badgeMaxCount}}" 
   number-type="{{badgeCountType}}">
    <template is="cell-left-main" data="{{image,icon,title,desc,tagContent,tagPosition,tagColor,tagShape,tagPlain,iconSize,iconColor}}" />
</l-badge>

以及

<!-- right -->
<l-badge 
  l-class="badge-right" 
  wx:if="{{(badgeCount > 0 || dotBadge ) && badgePosition ==='right'}}" 
  value="{{badgeCount}}" 
  dot="{{dotBadge}}" 
  max-count="{{badgeMaxCount}}" 
  number-type="{{badgeCountType}}">
    <template is="cell-right-main" data="{{rightDesc,tagContent,tagPosition,isLink,tagColor,tagShape,tagPlain}}" />
</l-badge>

先不说,这个属性的问题,我们发现这个 徽标属性标签属性 一样,都是内嵌的另外一个组件,l-badge,至此我们发现了 第三个lin-ui组件,然后我们再来看坐标默认显示问题;
这两段明显是是代表了显示 左侧的l-badge 还是显示 右侧的l-badge,因为这两段都是通过 wx:if 实现的,并不存在我们说的反向显示的问题,所以,我个人认为这是一个BUG~

路由属性实现

接着,我们来看路由属性

属性 说明 类型 可选值 默认值
is-link 是否显示跳转的图标 Boolean false/true true
link-type 设置跳转类型 String navigateTo/redirectTo/reLaunch/switchTab navigateTo
url 设置跳转的路径 String - -

与这3个属性相关的properties如下

isLink: {
  type: Boolean,
  value: true,
},
linkType: {
  type: String,
  value: 'navigateTo'
},
url: String

与官网的属性核对一下
在这里插入图片描述

这个没有问题,都对得上,接着再看一下 wxml中的实现方式,搜索wxml文件,我们会发现,linkTypeurl 竟然 都是绑定在view上的,如下:

<view 
  mut-bind:tap="tapcell" 
  data-url="{{url}}" 
  data-link-type="{{linkType}}">
</view>

由于是data开头,这个属性大概率是一个私有属性,那么这个跳转如何实现?不着急,往下看,既然是一个点击事件,我们接着看这个点击事件

点击事件lintap

当点击 view 的时候会触发一个 tap事件,事件的名字为:tapcell,那么就打开index.js文件找到tapcell事件,代码如下:

tapcell: function (e) {
    const {
      linkType,
      url
    } = e.currentTarget.dataset;
    if (url) {
      wx[linkType]({
        url
      });
    }
    this.triggerEvent('lintap', {
      e
    }, { bubbles: true, composed: true });
  }
}

这段代码分开看,共有两部分功能,第一部分:实现路由跳转,第二部分:暴露点击事件lintap,先看第一部分:

const {
  linkType,
  url
} = e.currentTarget.dataset;
if (url) {
  wx[linkType]({
    url
  });
}

我们发现,点击的时候会从 e.currentTarget.dataset 中取到 url 以及 linkType,并且通过代码

wx[linkType]({
  url
});

实现了页面的跳转,比如现在是 linkType 的值 redirectTourl的值是’…/welcome/index’,这段代码就会变成

wx['redirectTo']({
  url:'../welcome/index'
});

这也就是为什么我们只需要在view上绑定了 data-urldata-link-type 后即可实现跳转,再来看第二段代码

 this.triggerEvent('lintap', {
    e
  }, { bubbles: true, composed: true });

根据用法,list上可以绑定一个 名为lintap的事件,为什么这个事件名叫做 lintap,因为这里使用自定义事件的触发方式 triggerEvent,另外这个自定义事件有两个参数:

  • 第一个参数:是提供给事件的 监听对象,这里把默认参数event传递过去了;
  • 第二个参数:这个参数是一个 配置选项,有以下三个参数:
选项名 类型 是否必填 默认值 描述
bubbles Boolean false 事件是否冒泡
composed Boolean false 事件是否可以穿越组件边界,为 false 时,事件将只能在引用组件的节点树上触发,不进入其他任何组件内部
capturePhase Boolean false 事件是否拥有捕获阶段

样式属性实现

最后是样式属性,样式属性有3个,如下

属性 说明 类型 可选值 默认值
gap 设置list内左右两侧内容距list两边的间距 Number - -
left-gap
设置list内左侧内容距list左边的间距 Number -
right-gap
设置list内右侧内容距list右边的间距 Number -

我们在js中分别搜索这几个属性,得到如下结果:

gap: Number,
leftGap: Number,
rightGap: Number,

并且这几个属性并没有在js文件中另外搜索到,这就代表着 这几个属性也是直接作用在wxml上

<view 
  class="l-list l-class" 
  hover-class="{{isHover?'l-list-hover':''}}" 
  hover-start-time="20" 
  hover-stay-time="50"  
  style="{{gap?'padding:0 '+gap+'rpx;':''}} {{leftGap?'padding-left:'+leftGap+'rpx':''}} {{rightGap?'padding-right:'+rightGap+'rpx':''}}" 
  mut-bind:tap="tapcell" 
  data-url="{{url}}"
  data-link-type="{{linkType}}">
</view>

关键行在于

style="{{gap?'padding:0 '+gap+'rpx;':''}} {{leftGap?'padding-left:'+leftGap+'rpx':''}} {{rightGap?'padding-right:'+rightGap+'rpx':''}}" 

我们发现 gapleftGaprightGap 这几个属性就是 直接作用在DOM上的style中,对应的属性也只是padding 这个 css样式,通过 padding 实现了两侧的缩进功能,那么我们上次遇到的问题呢,看看这是不是一个BUG

问题

我们翻看上面的这段代码,发现一个奇怪的问题,它的样式明明是靠style实现的,但是style中的不同样式之间 竟然没有分号分隔,这也许就是造成这个问题的原因,我们尝试修改,在style的样式之间都加上分号,如下:

<view 
  class="l-list l-class" 
  hover-class="{{isHover?'l-list-hover':''}}" 
  hover-start-time="20" 
  hover-stay-time="50" 
  style="{{gap?'padding:0 '+gap+'rpx;':''}} ;{{leftGap?'padding-left:'+leftGap+'rpx':''}} ;{{rightGap?'padding-right:'+rightGap+'rpx':''}}" 
  mut-bind:tap="tapcell" 
  data-url="{{url}}" 
  data-link-type="{{linkType}}">
</view>

加上之后发现确实生效了
在这里插入图片描述

hover属性实现

hover属性在上一篇之中是放在样式属性中的,这篇单独放入一节的原因是因为hover它 虽然实现不复杂,但是它不是和上面的属性一样只做了一层转发,先来看看这个属性,用过用法我们知道传入的属性名叫做 isHover,但是我们直接搜isHover会 发现没有这个值
在这里插入图片描述

那么既然本文件没有,看看有没有混入:

import hover from '../behaviors/hover';

Component({
  behaviors:[hover]
  // ...
})

明显是有混入的,接着看看混入实现了什么功能

// eslint-disable-next-line no-undef
export default Behavior({
  behaviors: [],
  properties: {
    isHover:{
      type: Boolean,
      value: true
    }
  }
});

打开后发现很简单,就是混入了一个 isHover属性,没有别的了,这样就找到了 isHover属性 的设置来源,之后,再找找实现功能的地方

<view 
  class="l-list l-class" 
  hover-class="{{isHover?'l-list-hover':''}}" 
  hover-start-time="20" 
  hover-stay-time="50"></view>

实现hover的地方 和实现padding,url是在一个view上,但是它是通过 hover-class 进行绑定的,绑定的类名叫做 l-list-hover 这个CSS类名,这个类名实现了一些hover上的交互效果;
可能有小伙伴会问,hover-classhover-start-timehover-stay-time 是什么,简单的说下,这个是小程序 官方提供的一个属性,它提供了 可以指定元素触发时的动态效果,但是仅限绑定在 Viewbuttonnavigator等几个DOM上,具体属性及作用如下:

属性 类型 默认值 必填 说明
hover-class string none 指定按下去的样式类。当 hover-class=“none” 时,没有点击态效果
hover-stop-propagation boolean false 指定是否阻止本节点的祖先节点出现点击态
hover-start-time number 50 按住后多久出现点击态,单位毫秒
hover-stay-time number 400 手指松开后点击态保留时间,单位毫秒

小结

主要分析了Lin-ui中List组件实现,通过分析我们发现List组件其实是一个 复合组件,它的内部包含有三个Lin-ui中的其他组件:

  • 第一个组件:Icon组件,用于前置以及后置的icon图标;
  • 第二个组件:tag组件,用于显示list后部的标签;
  • 第三个组件:l-badge组件,用于实现徽标属性;

之后,我们在分析到路由属性时发现,linkTypeurl 竟然都是 绑定在view上 的,当我们触发lintap的时候,会去读取 e.currentTarget.dataset 中对应的 urllinkType 的值,再实现路由的跳转;
(PS:都已经看到这里了,点个赞,求个关注吧,万分感谢~)


网站公告

今日签到

点亮在社区的每一天
去签到