47

小程序组件开发之时间轴组件及组件关系

 4 years ago
source link: https://www.tuicool.com/articles/VrmqUrn
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

本文是面向初学者的,大牛可以忽略,以时间轴组件为例简单聊一下小程序的组件开发。

先简单介绍一下公司业务和前端项目情况吧。公司是做金融行业财富管理的业务,涉及主要是做基金、保险这一块。前端项目目前涉及B端后台管理系统、C端小程序、Node服务端,其中业务重点在小程序端,我们只有微信小程序端,没有做其他小程序,也没有使用市面上流行的各种多端框架,我们使用原生开发方式,UI组件我们也选择了自研,目前我们开发了一套金融风格的小程序端UI组件库,有过开源的打算,但目前我们还在内部沉淀使用中,目前积累了 34+ 个组件了,支持主题和国际化,基本上满足了目前开发的需要。

所以,本文要说的是我们组件库最近添加的一个新组件,时间轴组件,也是笔者开发的,笔者由于在公司主要负责小程序端的开发,基于业务的需要贡献了开发了不少组件,那么多组件之所以讲这个组件,是因为其他大部分组件的开发都很普通,体现不了小程序特有的东西,要么是组件太复杂代码太多不适合用文字表达,而时间轴(Timeline)组件我觉得刚刚好,不肥不瘦不偏不倚20不足18有余,比较好拿来作为素材聊聊。

另外,为了写本文我把此组件做成了 小程序代码片段 ,代码片段是一种可分享的小项目,可用于分享小程序和小游戏的开发经验、展示组件和 API 的使用、复现开发问题等等,代码片段详细信息可以去官方文档看看。

时间轴组件(源代码)代码片段 ,点击链接可以直接通过小程序开发工具直接打开查看,可以边看源代码边看文章。

注意:请确保你的开发者工具版本 >= 1.02.1904280

组件分析设计

在着手写代码之前,还是先做一翻分析设计。

分析什么?我们需要分析业务方对组件的详细需求、交互以及设计稿效果,弄清楚有没有什么特别的地方,需求是否适合使用时间轴组件来呈现等,对于不合理的需求,作为开发我们有责任提出问题和建议来。

设计什么?我们需要设计组件的目录结构、API以及对使用者友好的示例文档,通常除了API外,目录结构、命名和文档我们都会现有一个规范,按给定的规范做即可,但是如何设计一组好的API就需要开发者具有一定的经验。

当然,对于常用的组件,我们也许用不着这么认真,直接参考市面上已有的组件库找着样子抄就行了,事实上我们除了少数几个组件别具特色外别家没有外,其他组件我们也是直接参考别的组件库是怎么做的,但我这里抛砖引玉吧,不仅仅是开发组件,任何需求的迭代开发都是一样的,特别是复杂的需求,我们更需要设计。

对于组件开发来说,最好的设计文档就是示例文档,文档先行。看一下 Timeline 组件的文档吧:

NJfeiyf.png!web

Timeline 组件的文档

什么不支持自定义 slot,什么地方支持自定义,这就很清晰了,事件轴点可以自定义样式,时间轴的内容体可以自定义,以及一些外部样式 class。

当然这是最终完善的文档,我们首先应该定义好组件的 Attributes(Props)、Slot ,命名、类型这些都事先定义好,这是最基础的,分析出来我们的组件应该提供什么样的能力,定义什么样的接口。其次,我们应该写好代码示例,先想好我们的组件是如何使用的,然后我们再支持这样的实现。这里可以看出,组件使用了父子嵌套组件模式:

<pps-timelinereverse="{{false}}">
  <pps-timeline-item
    wx:for="{{activity}}" 
    wx:key="{{index}}"
    timestamp="{{item.timestamp}}"
    dotStyle="border-color: #33cd5f; color: #33cd5f">
      {{item.content}}
  </pps-timeline-item>
</pps-timeline>

为什么这里要使用父子组件模式呢,其实不这样也是可以很好的完整组件。做好了这些工作后我们开始写代码吧。

组件实现

timeline

因为我们是使用父子组件嵌套模式,所以在创建目录时就可以这样体现:

timeline
--index.wxml
----timeline-item
------index.wxml

当然,在小程序中要实现父子组件关联关系并不是非要这样,事实上没有层级规定限制,父子组件平级放置也是可以的,但我推荐这样,阅读起来更清晰名了。

父组件内部其实很简单,就是一个 slot,以便能够放入子组件

<!-- timeline/index.wxml -->
<viewclass="pps-timeline custom-class {{reverse?'desc':'asc'}}">
  <slot/>
</view>

custom-class 是定义组件的根外部样式,以便在外部传入样式,为什么要这样呢,小程序的组件技术采用的 WebCompontent 技术,不了解的同学可以搜索一下,这里我写了 demoreverse 是个 prop ,控制时间轴是顺序展示还是倒序展示,这个在父组件来控制是最好不过的(当然,你也可以把传入的数组排序好也是一样的)。

timeline-item

核心都在这个里面,我们先来分析一下DOM结构,以便确定怎么构建HTML结构

yIFRR3E.png!web

具体代码就不贴了,可以打开代码片段查看。

排序:父子组件间关系

组件间关系这是这个组件最关键的地方,不同于 Vue.js 组件方案,只有实现这个才能实现在 timeline 上实现 reverse。关于组件的关联关系详细可以看 文档

在 timeline/index.js 和 timeline-item/index.js 中分别定义 timeline 是 timeline-item 的父级,timeline-item 是 timeline 的子级,由 relations 选项来定义。关键是确定最后一个节点,因为最后一个节点是没有连接线的,这个需要处理(其实数据不复杂的情况下更建议对传入的数组进行排序,这样就不需要处理DOM结构了)。

timeline/index.js

relations: {
    './timeline-item/index': {
      type: 'child',
      linked: function (target){
        // 每次有custom-li被插入时执行,target是该节点实例对象,触发在该节点attached生命周期之后
        this._getAllChildren()
      },
      unlinked: function (target){
        this._getAllChildren()
      }
    }
  },

timeline-item/index.js

relations: {
    '../../timeline/index': {
      type: 'parent'
    }
  },

有了关联关系,我们可以调用 this.getRelationNodes 方法获取所有的子节点,这个写在 timeline-item/index.js 中

methods: {
    _getAllChildren() {
      const nodes = this.getRelationNodes('./timeline-item/index')
      if (nodes.length) {
        const lastIndex = nodes.length - 1
        const { reverse } = this.data
        nodes.forEach((element, index) => {
          const isLast = index === lastIndex
          element.updateIsLastElement({
            index,
            isLast,
            reverse
          })
        })
      }
    }
}

然后遍历每一个子节点,调用子节点 methods 中的 updateIsLastElement 处理方法。这里需要特别注意的是 在 unlinked 中也要再次调用 _getAllChildren ,因为当使用 setData 删除一个子项时需要重新计算子节点个数。

所谓的排序,就是 Flex CSS 操作而已

.pps-timeline.desc{
  display: flex;
  flex-direction: column;
}
.pps-timeline.asc{
  display: flex;
  flex-direction: column-reverse;
}

这个组件还有很多可以改进的地方,这里作为一种思路吧。

注意

在引用小程序端的时候,父子组件都需要在json中引入,如果你的项目是用 npm 进行管理的,那么不要在全局的 app.json 中引入,要在使用的页面中引入,否则引用不到。

推荐几个优秀的组件库

  • iView Weapp 。出自著名的Vue组件库 iView 之家,跟 iView 一脉相承。
  • Vant Weapp 。“大名鼎鼎”的大厂有赞出品,Vue 组件库 Vant 的小程序版本,两者基于相同的视觉规范,提供一致的 API 接口。
  • Color UI 。最“风骚”的组件库,多彩靓丽,组件丰富,色彩华丽,动画酷炫。
  • wux-weapp 。最大而全的组件库,各种组件应有尽有,组件宝库。

后记

笔者小程序开发经验也不是很丰富,如有错误请指出,小程序的自定义组件涉及的东西比 Vue.js 多多了,比如模板和样式怎么处理、组件间通信、组件间关系、组件生命周期等都具有小程序特色。纯原生开发一个复杂的小程序,不借助轮子个人感觉还是很麻烦的,尤其现在这么多小程序,哪天需要支持其他小程序呢,我想不会有人一个个对接原生开发吧,由于我们业务时toB的,所以目前还不需要考虑其他平台小程序。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK