Weapp影视评分项目开发(10):Home 页 (全局组件的实现)
前言
本篇是 Home 页面实现的第3篇,也是最后一篇,将完善整个 home 页面。本篇文章将实现两个重要的全局组件,一个是内容可横向滚动的面板组件,另一个是影视信息卡组件,他们将会在项目中被多处使用。
知识点
全局组件的实现
slot 插槽
computed 的使用
组件样式穿透
虚拟化组件节点
CSS 伪元素与伪类的使用
一、影视信息卡 movie-row
组件的实现
1. 组件命名
信息卡命名为 movie-row
是因为它可以一行中存放多个,对应的还有个 movie-item
组件,它是一个信息卡占据一行空间,movie-item
组件展示的内容会更丰富些。组件预览与结构如下图所示:

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
,这是因为小程序 自定义组件本身的那个节点是一个“普通”的节点,我们需要给其 js
的 options
开启“虚拟化组件节点”配置:
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
重命名item
,wx: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. 效果预览

2. 组件需求
如 图1 所示,m-panel
组件由上下两部分组成,上面红色区域为标题等信息;下方蓝色区域为内容区域,内容区域默认需要 x
轴滚动;也可以设置为不可滚动,如图2所示。
图1, m-panel
面板默认内容横向滚动:
图2,m-panel
面板设置为不可滚动:
综合以上需求,组件可配置的信息有 标题 title
、右侧副标题 subtitle
、跳转url
、内容区域是否可滚动 scroll-x
等信息,内容区域为 slot
。
涉及到跳转,就会有跳转方式,如 wx.navigateTo
与 wx.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>
三、其它
首页还有导航菜单、文章列表等组件,导航菜单较为简单,文章列表与影视列表相似,其实现过程就不再赘述,有兴趣可以阅读对应的源码实现。
总结
本文介绍了首页中两个全局组件的实现,写全局组件要做到多思考,既要找出相同点进行合并,又要找出不同处通过参数控制其显示内容。 最后感谢大家花时间阅读。
转载自:https://juejin.cn/post/7174064506702659615