我正在参与掘金创作者训练营第4期,点击了解活动详情,一起学习吧!
前言
最近在玩微信小程序的时候有一个需求,就是弹框中要显示图片信息,机智的我瞬间想到了wx.showModal,但是看了一会眉头一皱,官方API并不支持在弹窗中添加图片;口吐芬芳的同时想了想还是自定义一个吧,顺便熟悉下自定义组件。
为什么使用自定义组件
可能有些人觉得这个需求完全可以在page页面中直接实现,为什么还要写成自定义组件呢?
- 提高代码可复用性:如果不用组件,每次遇到相同的业务场景都需要重新编写代码,而被抽离后的组件可以在其适用的场景内被重复使用,很大程度上提高开发效率。
- 降低代码维护难度:当页面中的某个组件出现 Bug,不需要在大量的代码中查找这个布局,只需要在这个组件内寻找,所以可以充分说明组件化在降低代码维护难度方面的优势。
创建自定义组件
首先我们在项目根目录下创建components目录用于专门创建自定义组件,当然你想要换个英文名字也行,我已经给你试过了;接着我们在components目录下创建自定义组件的名称,为了更直观一点,我们命名为multi-modal,然后在此目录下右键选择新建Component并命名为index,基本的自定义组件就创建好了;是不是惊喜的发现目录结构和page页面一毛一样,没错,就连写起来都一样。
实现组件布局
既然我们的组件名称都叫multi-modal了,要是跟它没点关系,我都不好意思说我也是modal,因此我们这里这里布局样式尽量和官方的保持风格一致,这样整体感官也会比较舒服;因为整体比较简单,所以我们只添加主要代码进行介绍(你看文章头部活动,主要是这玩意它不让我贴大片代码)。
首先我们发现窗口背景是有一层蒙版效果的,我们来看下它的主要样式,整体简单比较好理解,但是有一个z-index属性需要注意,它是用来指定一个元素的堆叠顺序的,如果涉及到与其他组件的前后问题,可以使用此属性来调整顺序。
.overlay {
position: fixed;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
}
既然要添加图片信息,那肯定就需要image组件,但是值得注意的是image组件默认是要指定大小的,而且图片也会占据整个组件,可是我们要展示的图片有可能没有那么大,那样就会拉伸最终导致显示效果不佳,这里有一个小技巧,我们可以给image组件设置mode="heightFix",这个属性值的作用是调整缩放模式,高度不变,宽度自动变化,保持原图宽高比不变,这样我们就可以尽量保持图片的显示效果。
<image class="dialog-image" src="{{image}}" mode="heightFix" wx:if="{{image}}"></image>
.dialog-image {
width: 100%;
height: 250rpx;
padding: 20rpx;
box-sizing: border-box;
}
如果我们的弹框只支持图片显然是不够的,因此我们再添加一个描述文本,让它更全面,然后弹框整体高度自适应;等等,高度自适应?那我如果文本很多的话岂不是... ...,果然,都给我顶到导航栏去了;很容易的我们就考虑到如果文本过多让它自己滑动不就好了,因此我们果断加入scroll-view标签,然后给它一个最大高度,再看下效果,完美!
这里还有一个小技巧,如果不想看到丑陋的滚动条可以使用enhanced和show-scrollbar来隐藏,注意show-scrollbar的值要用 "{{ }}" 包裹起来;其他的标题和确认取消点击按钮布局和样式就相对比较简单了,这里不再过多描述。
<scroll-view class="dialog-desc" scroll-y="true" enhanced="true" show-scrollbar="{{false}}" wx:if="{{desc}}">
<view class="dialog-desc">{{desc}}</view>
</scroll-view>
.dialog-desc {
width: 100%;
max-height: 300rpx;
font-size: 28rpx;
font-weight: 400;
padding: 0rpx 30rpx 30rpx;
color: #4C4C4C;
box-sizing: border-box;
}
实现组件逻辑
上面我们已经完成了自定义组件的布局,但是只有布局的话是不完整的,下面我们来看看最重要的逻辑部分index.js,下边是默认创建完成的js文件内容;
properties: {
//组件的属性列表
},
data: {
//组件的初始数据
},
methods: {
//组件的方法列表
}
知道大概的内容后我们来分析下需要哪些属性和方法,首先既然是个弹窗肯定需要一个属性来控制其显示隐藏状态的,另外标题图片以及内容描述文本也都需要动态添加,不然就没有意义了,这些参数都是需要通过外部传入的,因此我们需要将其定义在对外属性properties中,然后在wxml中进行数据绑定;这里注意到我们在显示隐藏、图片以及文本描述的地方添加了wx:if,如果没有传入该属性值,我们就不去显示,大大提高了使用的灵活度;当然,假如你最下边不需要取消按钮,也是可以通过同样的方式来定义一个属性值来控制。
properties: {
show: false, //是否显示 默认隐藏
title: '', //弹框标题 默认隐藏
image: '', //弹框图片 默认隐藏
desc: '', //弹框描述文本 默认隐藏
showNegative: false, //弹框左边按钮 默认隐藏
},
<view class="overlay flex-colunm-center" wx:if="{{isShow}}">
<view class="dialog-title">{{title}}</view>
<image class="dialog-image" src="{{image}}" mode="heightFix" wx:if="{{image}}"></image>
<scroll-view class="dialog-desc" scroll-y="true" enhanced="true" show-scrollbar="{{false}}" wx:if="{{desc}}">
<view class="dialog-desc">{{desc}}</view>
</scroll-view>
</view>
因为点击确定或者取消后弹框应该取消,所以我们直接在自定义组件中处理这块逻辑,但是通过this.setData({})只能修改初始数据data中的值,并不能修改外部属性properties中的值,通过查看官方API我们发现有个observers监听器可以用于监听 properties 和 data 的变化,因此我们可以在初始数据中定义一个 isShow 属性,然后通过监听外部属性show的值来改变isShow的值,这样外部属性通过isShow,内部属性通过 show 就很好的解决了这个问题;需要注意的是需要监听哪个字段第一个参数就是该字段。
observers: {
'show': function (show) {
this.setData({
isShow: show
})
},
},
只是可以传入数据的话是远远不够的,一般情况下我们还需要获取到弹框中的数据或状态,比如我们要知道用户点了确定还是取消,首先在自定义组件中的wxml中添加确定取消的点击事件bindtap="onNegativeClick"和bindtap="onPositiveClick",然后在一开始我们提到的组件方法列表中添加点击事件方法,但是如何将获取到的点击内容传递出去呢,这个时候就要用到触发事件triggerEvent方法,第一个参数是自己定义的触发事件名称,获取数据时需要用到,后边就是触发事件后回调的数据。
onPositiveClick(e) {
this.triggerEvent('onPositiveClick', 'click Positive')
this.setData({
isShow: false
})
}
}
使用自定义组件
刚才我们已经自己创建了一个自定义组件,接下来找一个page界面来看下效果,找到page的json文件,配置组件的名称和路径,multi-modal可以自己定义,但是路径一定要准确。
"usingComponents": {
"multi-modal":"/components/multi-modal/index"
}
接着我们在wxml中使用刚才定义的组件,注意标签名称要和你json文件中定义的保持一致,而且属性名称也要和自定义组件中的外部属性保持一致,值得注意的是bindonNegativeClick和bindonPositiveClick,这两个就是触发事件的回调绑定,而且他们的格式都是“bind触发事件名称” 或者 “bind:触发事件名称”,这下知道刚才自定义组件中定义的触发事件名称有什么用途了吧,然后自己定义一个方法名称去接收触发事件的数据。
<multi-modal show="{{showMultiModal}}" showNegative="{{showNegative}}"
title="{{title}}" image="{{image}}" desc="{{desc}}"
bindonNegativeClick="onNegativeClick" bindonPositiveClick="onPositiveClick">
</multi-modal>
onNegativeClick(e) {
console.log('onNegativeClick',e)
},
onPositiveClick(e) {
console.log('onPositiveClick',e)
}
接下来就是见证奇迹的时刻了,我们在page界面中添加一个点击事件,并且将上边的showMultiModal属性值传入true,我们来看下效果,同时点击确定时回传的数据我们也获取到了。
总结
到此为止我们的自定义组件已经介绍完了,这里只是简单的介绍了如何去创建一个自定义组件,其实自定义组件还有很多属性和方法我们没有提及到,但是实现逻辑是一样的,大家可以去参考官方文档多去实践一下,这样就能很快的掌握了。