Weapp影视评分项目开发(10):Home 页 (全局组件的实现)

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情

前言

本篇是 Home 页面实现的第3篇,也是最后一篇,将完善整个 home 页面。本篇文章将实现两个重要的全局组件,一个是内容可横向滚动的面板组件,另一个是影视信息卡组件,他们将会在项目中被多处使用。

知识点

全局组件的实现 slot 插槽 computed 的使用 组件样式穿透 虚拟化组件节点 CSS 伪元素与伪类的使用

一、影视信息卡 movie-row 组件的实现

1. 组件命名

信息卡命名为 movie-row 是因为它可以一行中存放多个,对应的还有个 movie-item 组件,它是一个信息卡占据一行空间,movie-item 组件展示的内容会更丰富些。组件预览与结构如下图所示:

image.png

2. 组件关键点

  • 海报图片设置 mode="aspectFill" 属性:由于海报图的大小不一,为了页面中显示大小一致,我们需要对其长边进行裁剪,使图片能在设定的宽高内占满空间;
  • 海报图片开启 lazy-load:因为本项目会有大量的图片,为了加载与渲染速度,也为了节约带宽与 CDN 流量费用;
  • 海报图片开启 webp:可有效降低带宽,前提是图片提供了 webp 格式;
  • 海报底部有个存放评分或者其它信息的地方,为防止字体颜色与海报颜色相近导致无法阅读,底部做了一个有透明的黑色渐变遮罩层;
  • 底部预留了 slot 插槽区域,用于内容补充;
  • 虚拟化组件节点 virtualHost: true 的使用。

3. 关键代码

1) 海报底部遮罩层的实现

海报封面底部区域使用绝对定位,使其浮在海报底部,背景为有透明度的黑色渐变,防止文字与海报同色无法阅读:

.movie-row__info {
  position: absolute; /* 绝对定位在海报图上方 */
  padding: 0 10rpx;
  left: 0;
  bottom: 0;
  height: 60rpx;
  width: 100%;
  font-size: 24rpx;
  line-height: 72rpx;
  background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.45)); /* 从下至上,透明度到0的渐变色 */
}
2) 开启样式穿透

为了父级组件能够修改其样式,我们需要开启样式穿透:

options: {
  styleIsolation: 'apply-shared'
}
3) 虚拟化组件节点

因为该组件一般显示在 m-panel 组件中,我们希望循环中最后一个元素的边距是 0,这样外层包裹元素区域就不需要设置负的 margin 值去抵消该当前组件 margin 的影响,所以使用伪类来解决:

.movie-row {
  &:nth-last-child(1) {
    margin-right: 0; /* 最后一个元素不显示外右边距 */
  }
}

但你会发现设置该样式后,这个组件的所有 margin 都是 0,这是因为小程序 自定义组件本身的那个节点是一个“普通”的节点,我们需要给其 jsoptions 开启“虚拟化组件节点”配置:

options: {
  virtualHost: true
}

注意:开启 虚拟化组件节点 是有代价的,有兴趣的小伙伴可以查看官方文档相关说明。

3. 组件使用

我们将其在 app.js 中注册为全局组件:

"usingComponents": {
  "movie-row": "components/movie/movie-row/index"
}

一般它是以多个的形式出现,所以我们用循环来遍历它:

<movie-row 
  wx:for="{{ movies }}" 
  movie="{{ item }}" 
  wx:key="id" 
/>

这是本项目中第一次使用 wx:for 语法,他的默认遍历出的元素名称为 item ,元素下标名称为 index,我们可以使用 wx:for-item 重命名 itemwx:for-index 重命名 index
特别需要注意的是,wx:key 的值如果使用 index ,其写法为 wx:key="index",如果是 item 的属性,如 id 则写法为 wx:key="id" ,也就是直接用 item 的属性,不能使用 {{ }} 模板语法将其括起来。

重命名示例:

<!-- 将 item 与 index 重命名为 movie 与 idx -->
<movie-row 
  wx:for="{{ movies }}" 
  wx:for-item="movie"
  wx:for-index="idx"
  movie="{{ movie }}" 
  wx:key="id" 
/>

二、面板 m-panel 组件的实现

1. 效果预览

panel.gif

2. 组件需求

如 图1 所示,m-panel 组件由上下两部分组成,上面红色区域为标题等信息;下方蓝色区域为内容区域,内容区域默认需要 x 轴滚动;也可以设置为不可滚动,如图2所示。

图1, m-panel 面板默认内容横向滚动:
image.png

图2,m-panel 面板设置为不可滚动:
image.png

综合以上需求,组件可配置的信息有 标题 title右侧副标题 subtitle跳转url内容区域是否可滚动 scroll-x 等信息,内容区域为 slot
涉及到跳转,就会有跳转方式,如 wx.navigateTowx.redirectTo,所以需要传入一个是否为 wx.redirectTo 跳转的字段,我们定义为 replace

全局组件的开发需要着眼于整个项目,将项目相似处抽取出来,再找到他们的不同点,通过 properties 传入不同参数实现不同的效果。
说起来容易,但这一点在项目初期可能难以把握好。比如这个组件,目前看这些参数够用了,后面却遇到了这样一个问题: header 区域的右侧箭头,是通过传入参数 to 判断是否展示的,后面有个场景需要显示箭头却不需要跳转,它是绑定了一个点击事件,箭头的作用是告诉用户,此区域可以点击,这时就需要对组件进行修改与扩展,但修改已使用的全局组件,不能影响其原有用法,最后我通过加入一个 boolean 类型字段 arrow 与原有的 to 字段双重控制,当有 to 或者 arrow === true 时显示箭头。
本项目和我们日常项目中经常会遇到这类场景,磨刀不误砍柴工,七分想三分做,准没错。

3. 组件的实现

1) panel header 的实现

panel-header 没有复杂的交互,左侧的竖线装饰是使用 css 伪元素 ::before 实现,日常项目中遇到这类的需求:它不需要一个有内容或者有意义的标签,仅仅是页面装饰,那么伪元素会是很好的选择,主要代码如下:

<view class="panel-title">{{ title }}</view>
.panel-title {
  display: inline-flex;  /* flex 也可以行内块状,其垂直居中很实用 */
  align-items: center;
  flex: 1;
  font-weight: 500;

  &::before {
    content: "";  /* 伪元素内容,次属性必须有 */
    margin-right: 8rpx;
    width: 6rpx;
    height: 28rpx;
    border-radius: 10px;
    background-color: var(--color-theme); /* 使用全局定义的主题色 */
  }
}
2) panel content 的实现

内容区域主要是可以 x 轴滚动,代码不多,也较为简单,主要是样式 overflow-x: scroll; ,不过其中还是有一些优化点的:

  • ::-webkit-scrollbar 属性,浏览器滚动条属性设置在小程序中依然有效,因为横向滚动区域内容不会很多,不需要滚动条反馈滚动进度,我们可以隐藏滚动条,让页面更美观;
  • -webkit-overflow-scrolling: touch; 属性在小程序中同样可使 ios 系统滑动更流畅;
  • 注意看示例图,内容区域的右侧是无内边距的,这种效果能让用户感觉右侧是有内容未显示完全,知道横向可以滑动。
<view class="panel-content {{ scrollX ? 'scroll-x' :''}}">
  <slot />
</view>
.panel-content {
  padding: 0 22rpx;
  
  /* x 轴可滚动时样式 */
  &.scroll-x {
    padding: 0 22rpx;
    overflow-x: scroll;
    overflow-y: hidden; /* y 轴无滚动需求 */
    white-space: nowrap; /* 内容溢出不换行 */
    -webkit-overflow-scrolling: touch; /* 优化 ios 系统弹性滚动 */
    
    /* 浏览器的滚动条设置在小程序中依然有效,此处隐藏滚动条,样式会更好看 */ 
    &::-webkit-scrollbar {
      display: none;
    }
  }
}

4. 使用示例

同样,此组件需要在多个页面使用,可以注册为全局组件,过程不再赘述。

<m-panel 
  title="正在热映" 
  subtitle="{{theater.total}}部" 
  to="/pages/movie/theater/index"
>
  <movie-row 
    wx:for="{{theater.data}}" 
    movie="{{ item }}" 
    wx:key="id" 
  />
</m-panel>

三、其它

首页还有导航菜单、文章列表等组件,导航菜单较为简单,文章列表与影视列表相似,其实现过程就不再赘述,有兴趣可以阅读对应的源码实现。

总结

本文介绍了首页中两个全局组件的实现,写全局组件要做到多思考,既要找出相同点进行合并,又要找出不同处通过参数控制其显示内容。
最后感谢大家花时间阅读。

© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容