注意
本文针对微信小程序初学者,如果已经开发过,可以直接移步!
本文写于几年前,现在部分东西有些许变化,但是依旧可以帮助你,不想看本文章可以直接参考微信小程序文档:developers.weixin.qq.com/miniprogram…
首先,我们应该明确,如何才能自己做一个自定义组件!
Component概念
Component像页面一样由wxml、wxss、js和json4个文件组成,且需要把这4个文件放在同一个目录中。与页面不一样的是,Component中的构造函数(也可以称构造器)是Component({}),而页面中的构造函数是Page({})。
第二,创建两个文件夹,一个定义component,一个引用component!
我建立如下:
菜鸟将 lunbo 作为组件,使用 button 引用组件:
wxml:
<!--这里的lunbo是json文件引入的component,可以任意取名,但最好是其功能-->
<lunbo min="1"></lunbo>
json:
{
"usingComponents": {
"lunbo":"../lunbo/land"
}
}
页面的数据怎么来?
这个官方文档倒是很清楚,页面的数据分两种
data
这是component里的私有数据,只用于你组件的渲染,引用该component的页面无法传递过来。
properties
component留给引用页面传递参数的,也是用来直接渲染页面用的。
所以,可以很轻松的将以前的:
Page({
data: {
nowIdx:0,
imglist:[
{
img:"../../imgs/s1.jpg",
text: "课程理论"
},
{
img:"../../imgs/s2.jpg",
text: "学习视频"
},
{
img:"../../imgs/s3.jpg",
text: "仪器演示"
},
{
img:"../../imgs/s4.jpg",
text: "我的考试"
}
/*图片自己弄*/
]
},
swiperChange:function(e){
this.setData({
nowIdx: e.detail.current,
})
},
改成:
Component({
data: {
nowIdx:0,
imglist:[
{
img:"../../imgs/s1.jpg",
text: "课程理论"
},
{
img:"../../imgs/s2.jpg",
text: "学习视频"
},
{
img:"../../imgs/s3.jpg",
text: "仪器演示"
},
{
img:"../../imgs/s4.jpg",
text: "我的考试"
}
/*图片自己弄*/
]
},
swiperChange:function(e){
this.setData({
nowIdx: e.detail.current,
})
},
这时页面会警告:
翻看文档,你会发现,原来自定义的函数必须得写道一个叫 methods 的东西里面:
Component({
data: {
nowIdx:0,
imglist:[
{
img:"../../imgs/s1.jpg",
text: "课程理论"
},
{
img:"../../imgs/s2.jpg",
text: "学习视频"
},
{
img:"../../imgs/s3.jpg",
text: "仪器演示"
},
{
img:"../../imgs/s4.jpg",
text: "我的考试"
}
/*图片自己弄*/
]
},
methods:{
swiperChange:function(e){
this.setData({
nowIdx: e.detail.current,
})
},
},
}
生命周期
这样基本上就大致知道了component的用法,但是,最重要的当然是生命周期了,所以菜鸟接下来这样干了:
Component({
data: {
nowIdx:0,
imglist:[
{
img:"../../imgs/s1.jpg",
text: "课程理论"
},
{
img:"../../imgs/s2.jpg",
text: "学习视频"
},
{
img:"../../imgs/s3.jpg",
text: "仪器演示"
},
{
img:"../../imgs/s4.jpg",
text: "我的考试"
}
/*图片自己弄*/
]
},
methods:{
swiperChange:function(e){
this.setData({
nowIdx: e.detail.current,
})
}
},
created:{
function(){
console.log(aaa)
}
},
attached:{
function(){
console.log(bbb)
}
}
})
但是这里报错莫名其妙:
菜鸟一开始看着懵了,我没定义生命 n.apply 呀?为什么会报错,后来才发现关注点错了,因该是后面的一句:
[component]:Lifetime Methods Eorror。
后来发现,原来是:
生命周期函数不能用 {} 括起来,而且 function 必须写在冒号后面,不然也会报错
千万不要小看这一个,这真的是致命错误,可能大佬也不能很快发现。
所以代码变成了这样:
Component({
//这里的值打印得用this.data.min
data: {
nowIdx:0,
imglist:[
{
img:"../../imgs/s1.jpg",
text: "课程理论"
},
{
img:"../../imgs/s2.jpg",
text: "学习视频"
},
{
img:"../../imgs/s3.jpg",
text: "仪器演示"
},
{
img:"../../imgs/s4.jpg",
text: "我的考试"
}
/*图片自己弄*/
]
},
methods:{
swiperChange:function(e){
this.setData({
nowIdx: e.detail.current,
})
},
},
created:function () {
console.log("created")
},
attached:function () {
console.log("attached")
}
})
发现运行结果如下:
这成功的说明了,这两个函数的顺序,还有其它生命周期函数,有兴趣的读者可以去自己试试!
其他生命周期
这里就不拖泥带水了,component代码:
Component({
created:function () {
console.log("land created")
},
attached:function () {
console.log("land attached")
},
ready:function () {
console.log("land ready")
},
moved:function () {
console.log("load moved")
},
detached:function () {
console.log("land detached")
}
})
引用界面代码:
Page({
gotovar:function () {
wx.redirectTo({
url: '../varshiyan/var',
})
},
onLoad:function (params) {
console.log("dome onload")
},
onReady: function () {
console.log("dome onready")
},
onShow: function () {
console.log("dome onshow")
},
onHide: function () {
console.log("dome onhide")
},
onUnload: function () {
console.log("dome onunload")
},
})
输出结果:
这里提醒各位注意一点
那就是跳转用 wx.redirectTo,这样才可以执行页面卸载函数
结论:
component 的创建生命周期在页面之前,卸载生命周期在页面之后,页面切换后台后,不会再次执行 component 生命周期。
现在微信小程序文档写得挺清楚,见:developers.weixin.qq.com/miniprogram…
接收参数:properties
菜鸟又想,这component咋传参数进来的?
可是搜了半天也只有这篇文章讲得比较好:微信小程序自定义组件Component总结
现在微信小程序文档写得挺清楚,见:developers.weixin.qq.com/miniprogram…
可是这样,菜鸟表示想知道是否传进去了呀?于是我变成了:
Component({
properties:{
myProperty: {
type: String,
value: '',
}
},
data: {
nowIdx:0,
imglist:[
{
img:"../../imgs/s1.jpg",
text: "课程理论"
},
{
img:"../../imgs/s2.jpg",
text: "学习视频"
},
{
img:"../../imgs/s3.jpg",
text: "仪器演示"
},
{
img:"../../imgs/s4.jpg",
text: "我的考试"
}
]
},
methods:{
swiperChange:function(e){
this.setData({
nowIdx: e.detail.current,
})
},
},
created:function () {
console.log("created")
console.log(this.properties.myProperty.value)
},
attached:function () {
console.log("attached")
console.log(this.properties.myProperty.value)
}
})
这样只会得到这样的结果:
为什么是undefined?自然是因为没有得到该值,菜鸟又做了好多改法还是不行,最后终于在小程序文档里面发现了:
原来 properties里面的值其实实质跟data里面的值一样,就是一个对外一个对内,所以打印因该用this.data.XXXX
于是代码变成了:
Component({
properties:{
min: {
type: Number,
value: 0
},
},
//这里的值打印得用this.data.min
data: {
nowIdx:0,
imglist:[
{
img:"../../imgs/s1.jpg",
text: "课程理论"
},
{
img:"../../imgs/s2.jpg",
text: "学习视频"
},
{
img:"../../imgs/s3.jpg",
text: "仪器演示"
},
{
img:"../../imgs/s4.jpg",
text: "我的考试"
}
/*图片自己弄*/
]
},
methods:{
swiperChange:function(e){
this.setData({
nowIdx: e.detail.current,
})
},
},
created:function () {
console.log("created")
console.log(this.data.min)
},
attached:function () {
console.log("attached")
console.log(this.data.min)
}
})
注意
1、这里传的是string 和 Number 类型,所以直接传的,其他类型需要用
{{}}括起来,不然会被当成字符串传过去,导致类型不对!2、WXML 不能直接调用组件的 methods 方法,需要在
methods中封装为可用的数据,或者使用计算属性。菜鸟建议:组件中的数据全部由父组件传递,且在父组件就转成你需要的数据格式!3、wxml 中,使用 data 中定义的数据只能用于显示,不能用于逻辑!原因:
WXML 不支持在模板中调用
includes(),因为小程序的 WXML 解析器只支持简单的变量访问和? :三元运算符,而不能执行复杂的 JavaScript 代码(如map、filter、includes)。正确的做法:应该在 JS 代码中 提前计算 这个值,并存到
data里,然后直接在 WXML 里使用。
监听:observers
然后菜鸟还是感觉不行,这知道的太少了,最中方再会一个,于是就将目标锁定在了observers,文档里面说:
然后我的代码就变成了这样:
Component({
properties:{
min: {
type: Number,
value: 0
},
},
//这里的值打印得用this.data.min
data: {
nowIdx:0,
imglist:[
{
img:"../../imgs/s1.jpg",
text: "课程理论"
},
{
img:"../../imgs/s2.jpg",
text: "学习视频"
},
{
img:"../../imgs/s3.jpg",
text: "仪器演示"
},
{
img:"../../imgs/s4.jpg",
text: "我的考试"
}
/*图片自己弄*/
]
},
methods:{
swiperChange:function(e){
this.setData({
nowIdx: e.detail.current,
min:10
})
},
},
observers:{
sja:function(e) {
console.log("observers")
}
},
created:function () {
console.log("created")
console.log(this.data.min)
},
attached:function () {
console.log("attached")
console.log(this.data.min)
}
})
然后发现,啥也不会发生,我就一直很奇怪,后来看文档,越看越感觉奇怪
sja:function(e) {
console.log("observers")
}
最后发现原来这里的sja不是乱写的,而是你要监听的字段的名字
补充讲解:3d轮播图
这里补充讲解一下3d轮播图思路:
3d轮播wxml代码:
<block>
<swiper
class="components_swiper"
bindchange="swiperChange"
autoplay="{{true}}"
circular="{{true}}"
duration="1000"
interval="3000"
previous-margin="150rpx"
next-margin="150rpx"
>
<swiper-item class="components_swiper_item" wx:for="{{imglist}}" wx:key="index">
<view class="components_swiper_item_view {{nowIdx==index?'act':''}}" bind:tap="gototest">
<image class="components_swiper_item_view_img" src="{{item.img}}"></image>
<view style="width:90%;font-size:13px;margin-top:15rpx">
<text>{{item.text}}</text>
</view>
</view>
</swiper-item>
</swiper>
</block>
3d轮播wxss代码
.components_swiper{
padding: 20rpx;
}
.components_swiper_item_view{
background-color: gainsboro;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
transform: scale(0.7);
transition: all 1s; //添加动画效果,不然会很突然
border-radius: 20rpx;
}
.components_swiper_item_view.act{
transform: scale(1);
transition: all 1s;
}
.components_swiper_item_view_img{
width: 90%;
height: 75%;
border-radius: 15rpx;
}
3d轮播的json、js代码
Component({
properties:{
min: {
type: Number,
value: 0
},
},
// 这里的值打印得用this.data.min
data: {
nowIdx:0,
imglist:[
{
img:"../../imgs/s1.jpg",
text: "课程理论"
},
{
img:"../../imgs/s2.jpg",
text: "学习视频"
},
{
img:"../../imgs/s3.jpg",
text: "仪器演示"
},
{
img:"../../imgs/s4.jpg",
text: "我的考试"
}
/*图片自己弄*/
]
},
methods:{
swiperChange:function(e){
this.setData({
nowIdx: e.detail.current,
min:10
})
},
},
observers:{
"min":function(e) {
console.log("observers")
}
},
created:function () {
console.log("created")
console.log(this.data.min)
},
attached:function () {
console.log("attached")
console.log(this.data.min)
}
})
{
"Component":"true", // 必须写,表示其是组件
"usingComponents": {}
}
思路
每当 swiper 改变的时候就获取得到这个图片对应的 e.detail.current(就相当于是该图片是数组中的第几张),然后将其与 wxml 里面循环遍历的 index 比较,相等就表示该图片在第一张,就用大的样式。