微信小程序–自定义组件

微信小程序官网介绍!

本文提供给急需使用自定义组件人群,以下是博主个人理解和案例!可以辅助官网来看

介绍:

从小程序基础库版本 1.6.3 开始,小程序支持简洁的组件化编程。所有自定义组件相关特性都需要基础库版本 1.6.3 或更高。
开发者可以将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用;也可以将复杂的页面拆分成多个低耦合的模块,有助于代码维护。自定义组件在使用时与基础组件非常相似。

请添加图片描述

一.自定义组件(创建-使用)

1.创建自定义组件

类似页面,一个自定义组件由json ,wxml,wxss,js 4个文件组成

1、在根目录下自定义一个components文件夹,用来存放自定义的组件。

2、再针对每一个组件创建一个文件夹,用来存放这个组件相关的文件。、

新建components文件夹

在这里插入图片描述

文件分类

在这里插入图片描述

组件新建Components(新建components的才是组件)

在这里插入图片描述
在这里插入图片描述

2.声明组件

在需要引入组件的页面的json文件中,在usingComponents里面写键值对,写组件名和路径

{
    "usingComponents": {
    //引用组件
        "cell": "/components/cell/cell",
        "item": "/components/item/item"
    }
}

3.使用组件

在需要引入组件的页面的wxml文件中,添加组件标签

<item>使用item自定义组件</item>

效果:
在这里插入图片描述

二, 自定义组件Component

生命周期:lifetimes
组件的挂载: attach
数据:data
方法:methods
属性(只读):properties
外部类:externalClasses
选项:options
多个插槽:multipleSlots:true
组件的样式格式: styleIsolation:“isolated”

三,组件的样式

组件对应 wxss 文件的样式,只对组件 wxml 内的节点生效。编写组件样式时,需要注意以下几点:

1,组件和引用组件的页面不能使用 id 选择器(#a)、属性选择器([a])和标签名选择器,请改用 class 选择器。
2,组件和引用组件的页面中使用后代选择器(.a .b)在一些极端情况下会有非预期的表现,如遇,请避免使用。
3,子元素选择器(.a>.b)只能用于 view 组件与其子节点之间,用于其他组件可能导致非预期的情况。
4,继承样式,如 font 、 color ,会从组件外继承到组件内。
5,除继承样式外, app.wxss 中的样式、组件所在页面的的样式对自定义组件无效(除非更改组件样式隔离选项)。
除此以外,组件可以指定它所在节点的默认样式,使用 :host 选择器(需要包含基础库 1.7.2 或更高版本的开发者工具支持)。

1,样式的隔离

组件:cell.js

// components/cell/cell.js
Component({
  // 选项:
  options:{
    // 样式隔离:apply-shared 父影响子,shared父子相互影响, isolated相互隔离
    styleIsolation:"isolated",
    // 允许多个插槽
    multipleSlots:true,
  },
options —— 样式隔离

styleIsolation : " 值 ",

值:
apply-shared :父影响子
shared:父子相互影响
isolated:相互隔离

2,externalClasses ——外部类

  // 通过组件的外部类实现父组件控制子自己的样式
  externalClasses:["cell-class"],

在组件:cell.js 中定义外部类

<view class="cell cell-class">我是cell组件</view>

使用组件

<cell cell-class="mycell"></cell>

在页面设组件样式

.mycell{
  line-height: 120rpx !important;
  color:#F70;
}

四,组件的插槽

1,默认插槽

父组件

<cell>
      <text>插槽内容</text>
</cell>

子组件

<view><slot></slot></view>

2,命名多插槽

父组件com.wxml(页面)

<cell>
    <text slot="pre"> 🚒</text>
    <text slot="next">🥗</text>
</cell>

子组件 cell.js

  // 允许多个插槽
options:{ multipleSlots:true}

子组件 cell.wxml

<view>
    <slot name="pre"></slot>
    <slot name="next"></slot>
</view>

允许多个插槽

options:{ multipleSlots:true}

五,组件的传参

父传子

property

子传参父

triggerEvent

组件 cell.js

  /**
   * 组件的方法列表
   */
  methods: {
    tapHd(){
      this.setData({count:this.data.count+1})
      // 发送一个事件
      this.triggerEvent("cellclick",this.data.count)
    }
  }

组件 cell.wxml 使用插槽

<view class="cell" bindtap="tapHd">
  <text>{{title}}</text>
  <text>{{count}}</text>
</view>

六,自定义组件生命周期

1,组件的生命周期 —— lifetimes

1,创建: created

此时还不能调用 setData

2,挂载: attached
3,卸载: detached

2,页面的生命周期 —— pageLifetimes

1,show:显示
2,hide:后台运行
3,resize:尺寸变化

七,定义组件 并 使用 + 效果图 —— item

props

title:标题
icon :图标
tip :提示
url :跳转连接
open-type : 打开的方式

slot

right
left :插槽

event

click :事件
外部类

itemClass :整体
titleClass :标题

1,组件 item代码:

item.js 代码:

// components/item/item.js
Component({
  options:{
    multipleSlots:true
  },
  externalClasses:["itemclass"],
  /**
   * 组件的属性列表
   */
  properties: {
    // 标题
    title:{
      type:String,
      value:""
    },
    // 显示右侧插槽
    showrslot:{
      type:Boolean,
      value:false,
    },
    // 图标
    icon:{
      type:String,
      value:""
    },
    tip:{
      type:String,
      value:"",
    },
    badge:{
      type:[Boolean,Number],
      value:false
    },
    url:{
      type:String,
      value:""
    },
    openType:{
      type:String,
      value:"navigate"
    }
  },

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

  },

  /**
   * 组件的方法列表
   */
  methods: {
      itemclick(e){
        console.log(e);    
        //发送一个事件 
        this.triggerEvent("itemclick",e.detail)
      }
  }
})

组件 item.json

{
  "component": true,
  "usingComponents": {}
}

组件 item.wxml

<navigator class="item itemclass" url="{{url}}" open-type="{{openType}}" bindtap="itemclick">
  <view class="icon" wx:if="{{icon}}">
    <image src="{{icon}}" mode="aspectFill"></image>
  </view>
  <view class="content">
      <view class="title">
        <view class="title" wx:if="{{title}}">{{title}}</view>
        <slot name="title"  wx:else ></slot>
      </view>
     
      <view class="right" wx:if="{{!showrslot}}">
          <view class="tip">{{tip}}</view>
          <view class="badge" wx:if="{{badge}}">
            <view wx:if="{{badge===true}}" class="dot">                           
            </view>
            <view wx:else  class="redbadeg">   
            {{badge}}                        
            </view>
          </view>
          <view class="arrow"></view>
      </view>
      <slot name="right" wx:else></slot>
  </view>
</navigator>

<!-- 
  icon 图标
  conent 内容
  title 标题
  right 右侧
  tip 提示
  badge 红点
  arrow 箭头
 -->

组件 item.wxss 代码:

/* components/item/item.wxss */
.item{
  line-height: 88rpx;
 
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.icon{
  margin-left: 30rpx;
  margin-right: 30rpx;   
  height: 100%;
  display: flex;
  align-items: center;
}
.icon image{
  width: 60rpx;
  height: 60rpx;
}
.content{
  padding: 0 30rpx;
  border-bottom: 1rpx solid #ccc;
  display: flex;
  flex:1;

}
.title{
  flex:1;
  color:#333;
  font-size: 32rpx;
}
.right{
  display: flex;
  align-items: center;
}
.right .arrow{
  height: 30rpx;
  width: 30rpx;
  border-top:3rpx solid #999;
  border-right: 3rpx solid #999;
  transform: rotate(45deg);
}

.tip{
  color:#999;
  font-size: 24rpx;
}
.dot{
  height: 14rpx;
  width: 14rpx;
  background-color: #f00;
  border-radius: 12rpx;
  margin-left: 15rpx;

}
.redbadeg{
  font-size: 18rpx;
  color:#fff;  
  border-radius: 18rpx;
  background-color: #f00;
  max-height: 30rpx;
  width: 30rpx;
  line-height: 30rpx;
  text-align: center;
  margin-left: 15rpx;
}

2,com页面使用 item组件/ com页面代码:

com.js 代码如下:

// pages/com/com.js
Page({

  /**
   * 页面的初始数据
   */
  data: {

  },
  cellHd(e){
    console.log(e);
    wx.showToast({
      title: '你点击了'+e.detail,
    })
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() {

  }
})

com.json 代码如下:

{
"usingComponents": {
"cell":"/components/cell/cell",
"item":"/components/item/item"
}
}

com.wxml 代码如下:

<item title="支付" icon="/images/icon01.png"></item>
<item title="相册" icon="/images/icon02.png"></item>
<item title="支付" ></item>

<item title="消息" icon="/images/icon02.png"  badge="{{true}}" tip="3条未读"></item>

<item title="消息" icon="/images/icon02.png"  badge="{{12}}" tip="12条未读"></item>

<item title="消息" icon="/images/icon02.png" showrslot="{{true}}">
  <switch checked="true" slot="right"></switch>
</item>

<item>
  <view slot="title">插槽title</view>
</item>

<item title="新闻" icon="/images/icon02.png"  url="/pages/yidian/yidian" open-type="switchTab"> 
</item>
<item title="首页" icon="/images/icon02.png"  url="/pages/home/home" > 
</item>

<item title="消息" icon="/images/icon02.png" showrslot="{{true}}" itemclass="myitem">
  <switch checked="true" slot="right"></switch>
</item>

 


























<!-- <view class="title">自定义组件</view>
<cell bind:cellclick="cellHd"  title="中美两国和平相处" num="{{5}}"></cell>
<cell  bind:cellclick="cellHd" title="阶级不同立场也不同" ></cell> -->


<!-- <cell cell-class="mycell">
  <text slot="pre">💖</text>
  <text slot="next">🥗</text>
  <text>新冠肺炎消失了</text>
  <text>假的</text>
</cell>
<cell>
  <text slot="next">🚒</text>
  <text slot="pre">💥</text>
  <text>工资10</text>
  <text>鸡蛋50</text>
</cell> -->

com.wxss 代码如下:

/* pages/com/com.wxss */
.title{
  line-height: 88rpx;
  background-color: #f0f0f0;
  padding: 0 15rpx;
}
.cell{
  color:red;
}
.mycell{
  line-height: 120rpx !important;
  color:#F70;
}

.myitem{
  line-height: 200rpx !important;
  background-color: #F0f0f0;
 
}

3,效果图:

在这里插入图片描述

八,自定义顶部导航栏

wx.getMenuButtonBoundingClientRect() —— 胶囊的边界
wx.getSystemInfoSync(); —— 系统信息(状态栏的高度)

配置自定义状态栏
在这里插入图片描述

在这里插入图片描述

1,定义组件 nav 并使用 + 效果图

在这里插入图片描述

1, images 图标 文件

两个图标
在这里插入图片描述
back.svg

<svg class="icon" style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="745"><path d="M670.954667 86.826667L269.44 488.362667a32 32 0 0 0-2.090667 42.965333l2.090667 2.282667L670.933333 935.168a8.533333 8.533333 0 0 0 6.037334 2.496h66.368a8.533333 8.533333 0 0 0 6.037333-14.570667L337.28 511.018667 749.397333 98.901333a8.533333 8.533333 0 0 0-6.037333-14.570666h-66.346667a8.533333 8.533333 0 0 0-6.058666 2.496z" fill="#fff" p-id="746"></path></svg>

home.svg

<svg class="icon" style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1408"><path d="M149.333333 960a85.333333 85.333333 0 0 1-85.333333-85.333333V331.221333a85.333333 85.333333 0 0 1 48.64-77.056l362.666667-172.693333a85.333333 85.333333 0 0 1 73.386666 0l362.666667 172.693333A85.333333 85.333333 0 0 1 960 331.221333V874.666667a85.333333 85.333333 0 0 1-85.333333 85.333333H149.333333zM505.386667 138.24l-2.56 1.024-362.666667 172.693333a21.333333 21.333333 0 0 0-11.989333 16.554667L128 331.221333V874.666667a21.333333 21.333333 0 0 0 18.837333 21.184L149.333333 896h192V661.333333a85.333333 85.333333 0 0 1 85.333334-85.333333h170.666666a85.333333 85.333333 0 0 1 85.333334 85.333333v234.666667h192a21.333333 21.333333 0 0 0 21.184-18.837333L896 874.666667V331.221333a21.333333 21.333333 0 0 0-9.792-17.941333l-2.368-1.322667-362.666667-172.693333a21.333333 21.333333 0 0 0-15.786666-1.024zM597.333333 640h-170.666666a21.333333 21.333333 0 0 0-21.184 18.837333L405.333333 661.333333v234.666667h213.333334V661.333333a21.333333 21.333333 0 0 0-18.837334-21.184L597.333333 640z" fill="#fff" p-id="1409"></path></svg>
2,nav 组件代码
nav.js
// components/nav/nav.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    "title":{
      type:"string",
      value:""
    },
    "color":{
      type:"string",
      value:"#fff"
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    statusBarHeight:20,
    barHeight:44,
    pagesLen:0,

  },
  lifetimes:{
    attached(){
      // 获取系统信息
     var info =  wx.getSystemInfoSync();
     console.log(info);
    //  更新状态栏的高度
     this.setData({statusBarHeight:info.statusBarHeight})
    //  胶囊的位置
    const res = wx.getMenuButtonBoundingClientRect()
    console.log(res);
    // 标题栏可以使用的宽度(排除右侧胶囊的位置)
    this.setData({titleWidth:res.left});
    // 标题栏高度
    var barHeight = res.height+(res.top-info.statusBarHeight)*2;
    this.setData({barHeight});

    // 获取当前页
    var pages = getCurrentPages();
    console.log(pages);
    //更新页面的长度
    this.setData({pagesLen:pages.length})
    }
  },

  /**
   * 组件的方法列表
   */
  methods: {
      goBack(){
        wx.navigateBack()
      },
      goHome(){
        wx.navigateBack({
          // 返回历史的长度为总页面数
          delta: this.data.pagesLen,
        })
      }
  }
})

nav.json
{
  "component": true,
  "usingComponents": {}
}
nav.wxml
<!--components/nav/nav.wxml-->
<view class="nav" style="padding-top: {{statusBarHeight}}px; height: {{barHeight}}px;">
  <view class="bar" style="width: {{titleWidth}}px; height: {{barHeight}}px; color: {{color}};">
    <view class="btn">
      <view class="back" wx:if="{{pagesLen>1}}"  bindtap="goBack" ><image src="./images/back.svg" mode="aspectFill"></image></view> 
      <view class="home" bindtap="goHome"><image src="./images/home.svg" mode="aspectFit"></image></view>
    </view>
   
     {{title}} {{pagesLen}}
  </view>
</view>

nav.wxss
/* components/nav/nav.wxss */
.nav{
  background-image: linear-gradient(90deg, rgb(96, 197, 236), rgb(37, 125, 197));
  position: sticky;
}
.nav .bar{
  box-sizing: border-box;
  padding: 0 7px;
  display: flex;
  align-items: center;
   
}
.btn{display: flex;  align-items: center;}
.btn>view{
  height: 40px;
  width: 40px;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
}
.btn image{
  height: 22px;
  width: 22px;
  align-items: center;
}
.btn .back { border-right: 1rpx solid rgba(255,255,255,.5); height: 22px;}
3,navpa 页面代码
navpa.js
// pages/navpa/navpa.js
Page({

  /**
   * 页面的初始数据
   */
  data: {

  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() {

  }
})
navpa.json
{
  "usingComponents": {
    "nav":"/components/nav/nav"
  },
  "navigationStyle":"custom"
}
navpa.wxml
<nav title="你好渐变标题" color="#fff"></nav>
<image src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fup.enterdesk.com%2Fphoto%2F2012-3-2%2Fenterdesk.com-B526ECADD33DBD367676A93E051BA1EC.jpg&refer=http%3A%2F%2Fup.enterdesk.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671158107&t=aaeb716592b0a54dba6dfb997e761a60"></image>
navpa.wxss
/* pages/navpa/navpa.wxss */
/* 空 */

效果图:

在这里插入图片描述
在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐