微信小程序自定义标签组件component封装、组件生命周期,组件通信

微信小程序自定义标签组件component封装、组件生命周期,组件通信

本文来说下小程序的自定义标签组件封装。
相比于vue,react的非路由组件,微信小程序的component组件要麻烦些,而且生命周期,数据接收传递方式也和路由组件不同!
假设你已经创建好了微信小程序项目!

新建component组件

本文以封装一个可用于关闭,添加,删除的按钮组件为例。
首先找到项目里面pages文件夹,鼠标右键pages文件夹,选择新建目录,输入名字globalComponents,该文件夹用于存放component组件。鼠标右键globalComponents文件夹,选择新建目录,输入名字closeAddReduceBtn,再右键closeAddReduceBtn文件夹,选择新建Component,输入名字closeAddReduceBtn。现在一个名为closeAddReduceBtn的component组件就创建好了。


在这里插入图片描述

component组件配置

创建好closeAddReduceBtn组件后,到pages下面的index文件夹,找到index.json文件,加上component组件配置,即usingComponents配置项。
index.json文件代码:

{
  "usingComponents": {
   "Radios": "../../globalComponents/Radios/closeAddReduceBtn"
  }
}

此行: "Radios": "../../globalComponents/closeAddReduceBtn/closeAddReduceBtn",closeAddReduceBtn是自定义的标签名,后面是组件相对路径

引入标签组件

配置好后,到index.wxml文件中,写上自定义标签组件即可


在这里插入图片描述

component组件关键生命周期

这里只说关键,重要的生命周期
打开closeAddReduceBtn.js,我们可以看到,里面的内容,不同玉路由组件,component组件是由Component构造函数渲染的,onLoad,onShow什么的都没了。

// globalComponents/closeAddReduceBtn/closeAddReduceBtn.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {

  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {

  }
})

properties 是属性列表,通常用于接收父组件传递的值
data 用于存放组件本身的值
methods 用于存放自定义的函数,类似vue的methods,在component里面,你直接像在路由组件里面写方法是不能生效的,方法必须写在methods里面。
组件加载执行的函数是attached() {},需要我们手动加上,
组件页面初始化完成执行的函数是ready(){},手动给加上后,组件代码

// globalComponents/closeAddReduceBtn/closeAddReduceBtn.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {

  },

  /**
   * 组件的初始数据
   */
  data: {

  },
  /**
  *组件加载执行
  */
  attached() {
  },
   /**
  *组件初始化完成执行
  */
  ready(){
  },
  /**
   * 组件的方法列表
   */
  methods: {

  }
})

closeAddReduceBtn组件页面构建

下面我们将closeAddReduceBtn组件页面写完
closeAddReduceBtn.wxml

<view  
   class="closeAddReduceBox"
   style="width:{{boxSize}}rpx;height:{{boxSize}}rpx;background-color:{{boxBackgroundColor}};border-width:{{boxBorderWidth}}rpx; transform: rotate({{rotate}});border-color:{{boxBorderColor}}"
   bindtap="clickBtn"
   >
  <text style="background-color:{{childBackgroundColor}};width:{{firstChildWidth}}rpx;height:{{firstChildHeight}}rpx"></text>
  <text wx:if="{{!isSingle}}" style="background-color:{{childBackgroundColor}};width:{{lastChildWidth}}rpx;height:{{lastChildHeight}}rpx"></text>
</view>

closeAddReduceBtn.wxss

.closeAddReduceBox{
  position: relative;
  border-radius: 50%;
  border-style: solid;
}
.closeAddReduceBox text{
  position: absolute;
  left:50%;
  top:50%;
  transform: translate(-50%,-50%)  
}

需要重点说的是closeAddReduceBtn.js
首先在properties中定义需要父组件传递的数据,定义数据为对象,其中type属性是定义接收的数据类型,value是默认值,如果需要默认值,可以在value里面定义。observer是定义传递值有变化时的监听函数,不过注意observer的值是函数名字符串,然后需要到methods中定义该函数
属性示例:
boxSize:{
type:Number,
value: 32,
observer:"getBoxSize"
},//按钮尺寸

Component({
  /**
   * 组件的属性列表
   */
  properties: {
    boxSize:{
      type:Number,
      value: 32,
      observer:"getBoxSize"
    },//按钮尺寸
    boxBackgroundColor:{
      type:String
    },//背景颜色
    boxBorderWidth:{
      type:Number
    },//边框宽度
    boxBorderColor:{
      type: String
    },//边框颜色
    rotate:{
      type:String
    },//选择角度
    childBackgroundColor:{
      type:String,
      value:'#ffffff'
    },//按钮里面横线颜色,即加减图标颜色
    childSize:{
      type:Number,
      value:0
    },//按钮里面横线尺寸,即加减图标尺寸
    isSingle:{
      type:Boolean,
      value:false
    },//是否只有一条线,即删除按钮,或者减号按钮
    bold:{
      type:Boolean,
      value:false
    }//是否加粗边框
  },

  /**
   * 组件的初始数据
   */
  data: {
    firstChildWidth:0,//第一根横线宽度
    firstChildHeight:0,//第一根横线高度
    lastChildWidth:0,//第二根横线宽度
    lastChildHeight:0,//第二根横线高度
  },
    /**
  *组件加载执行
  */
  attached() { 
    let { boxSize, boxBorderWidth, boxBorderColor, childSize, childHeight, rotate, onPressFun, bold } = this.data
    if (boxSize !== 32) {
      ; !childSize && (childSize = (20 / 32) * boxSize)
      // console.log(boxSize)
        ; !childHeight && (childHeight = (2 / 20) * childSize)
    }
    
    ; !childSize && (childSize = 20)
      ; !childHeight && (childHeight = 2)
    childHeight = bold ? (childHeight + 2) : childHeight
    boxBorderColor && !boxBorderWidth && (boxBorderWidth = 2)
    // console.log(boxBorderWidth)
    this.setData({
      firstChildWidth:childSize,
      firstChildHeight: childHeight,
      lastChildWidth: childHeight,
      lastChildHeight: childSize,
      boxBorderWidth
    })
  },

  /**
   * 组件的方法列表
   */
  methods: {
  //a按钮点击事件
    clickBtn(){
    //组件按钮点击事件,若需要向父组件传递数据或者让父组件监听到相应的操作,通过this.triggerEnent向父组件传递,三个参数,第一个参数是父组件的监听事件名,第二个是传递给父组件的值,第三个参数是触发事件的选项
    let value='click'
    let eventOption={
        bubbles:false,//    默认false,事件是否冒泡
        composed:false,//   默认false,事件是否可以穿越组件边界,为false时,事件将只能在引用组件的节点树上触发,不进入其他任何组件内部
        capturePhase:false,//   默认false,事件是否拥有捕获阶段
    }
      this.triggerEvent('event',value,eventOption)
    },
    //尺寸监听
    getBoxSize(value){
    //value是监听到的值
    console.log(value)
    }
  }
})

父组件使用

接下来看父组件的使用
在index.wxml中

<closeAddReduceBtn class="closeAddReduceBtn" boxBackgroundColor="#999999" rotate="45deg" bindevent="delImg" data-index="{{index}}"/>

将需要的属性直接传递即可。

特别注意的是bindevent,这是bind和组件事件名event的组合,event就是组件里面this.triggerEvent('event',value,eventOption)定义的event,假设我们在组件里面写成this.triggerEvent('getBtn',value,eventOption),那么在父组件就要对应写成bingetBtn

下面看父级组件触发的事件,component组件向父级组件传递的数据,父级组件通过e.detail获取

// 删除图片
  delImg(e){
    let {index}=e.currentTarget.dataset
    let value=e.detail //value是component组件向父组件传递的数据
    console.log(value)
    let { showImgs}=this.data
    showImgs.splice(index,1)
    this.setData({
      showImgs
    })
  },

关键生命周期函数的其他写法以及其他类型生命周期

关键生命周期函数也可以用下面写法

lifetimes: {
  attached: function () {
    // 在组件实例进入页面节点树时执行
   
  },
  detached: function () {
    // 在组件实例被从页面节点树移除时执行
  },
},

即将函数都写在lifetimes中。

还有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。这样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes 定义段中定义

 pageLifetimes: {
  show: function() {
    // 页面被展示
  },
  hide: function() {
    // 页面被隐藏
  },
  resize: function(size) {
    // 页面尺寸变化
  }
}

在 behaviors 中也可以编写生命周期方法,同时不会与其他 behaviors 中的同名生命周期相互覆盖。但要注意,如果一个组件多次直接或间接引用同一个 behavior ,这个 behavior 中的生命周期函数在一个执行时机内只会执行一次。

behaviors :{
      created(){
      },  //在组件实例刚刚被创建时执行
      attached(){
      },//在组件实例进入页面节点树时执行
      ready(){
      },//在组件在视图层布局完成后执行  
      moved(){
      },//在组件实例被移动到节点树另一个位置时执行    
      detached(){
      },//在组件实例被从页面节点树移除时执行   
      error(){
      },//Object Error    每当组件方法抛出错误时执行   
}

配置全局组件

有些组件,我们可能在很多页面都会使用,因此希望只做一次配置即可,只需要在app.json中添加usingComponents配置即可
app.json

{
"pages": [
  "pages/index/index",
  "pages/hmongb/hmongb"
],
"window": {
  "backgroundColor": "#633319",
  "backgroundTextStyle": "light",
  "navigationBarBackgroundColor": "#633319",
  "navigationBarTitleText": "苗文hmongb",
  "navigationBarTextStyle": "white"
},
"tabBar": {
  "selectedColor": "#633319",
  "color": "#898888",
  "list": [
    {
      "iconPath": "./images/index-gray.png",
      "selectedIconPath": "./images/index-active.png",
      "text": "查询",
      "backgroundColor": "#ffffff",
      "pagePath": "pages/index/index"
    },
    {
      "iconPath": "./images/hmongb-gray.png",
      "selectedIconPath": "./images/hmongb-active.png",
      "text": "我的",
      "backgroundColor": "#ffffff",
      "pagePath": "pages/hmongb/hmongb"
    }
  ]
},
  "subpackages": [
    {
      "name": "hmongbPage",
      "root": "hmongbPage",
      "pages": [
        "giveUsMsg/giveUsMsg"
      ]
    }
  ],
"sitemapLocation": "sitemap.json",
"style": "v2",
"usingComponents": {
  "Radios": "../../globalComponents/Radios/Radios",
   "doubleTopBar": "../../globalComponents/doubleTopBar/doubleTopBar",
  "leftScroll": "../../globalComponents/leftScroll/leftScroll",
  "searchTopBar": "../../globalComponents/searchTopBar/searchTopBar",
  "topTitleBar": "../../globalComponents/topTitleBar/topTitleBar"
}
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350