大家好,这是小程序系列的第二十二篇文章,在这一个阶段,我们的目标是 由简单入手,逐渐的可以较为深入的了解组件化开发,从本文开始,将记录分享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
默认为 left
,badgeMaxCount
默认为 99
,badgeCountType
默认为 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文件,我们会发现,linkType
和 url
竟然 都是绑定在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
的值 redirectTo
,url的值是’…/welcome/index’,这段代码就会变成
wx['redirectTo']({
url:'../welcome/index'
});
这也就是为什么我们只需要在view上绑定了 data-url
和 data-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':''}}"
我们发现 gap
,leftGap
,rightGap
这几个属性就是 直接作用在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-class
,hover-start-time
,hover-stay-time
是什么,简单的说下,这个是小程序 官方提供的一个属性,它提供了 可以指定元素触发时的动态效果,但是仅限绑定在 View
,button
,navigator
等几个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组件,用于实现徽标属性;
之后,我们在分析到路由属性时发现,linkType
和 url
竟然都是 绑定在view上 的,当我们触发lintap的时候,会去读取 e.currentTarget.dataset 中对应的 url
和 linkType
的值,再实现路由的跳转;
(PS:都已经看到这里了,点个赞,求个关注吧,万分感谢~)