微信小程序自定义组件

一,自定义组件的使用步骤

  • 首先在我们的根目录创建一个components文件夹,专门用来存放我们自定义的组件
    在这里插入图片描述
  • 比如在item中,我们写好了一个顶部栏组件,我们想要在pages页面下的com文件中去使用这个组件,那么我们该怎么样去做呢?那么我们就需要来到com.json文件中将item组件给引入进来
    在这里插入图片描述
    当完成这两步的时候,其实你已经成功的引入进来了一个组件,只不过这个组件为空,没有编写内容,接下来我就教大家如何去写!
(1)组件的通信(父传子)
  • 先来看一下代码,在父组件中
<cell title="今天吃大餐">我是父组件</cell>
  • 在子组件中
<view>{{title}}</view> //今天吃大餐
  • 子组件的js文件
  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"
    }
  },
  • 在item.js文件的properties属性中,我们接收到了父组件传递过来的title

父组件向子组件传递值的时候是通过properties属性的,在item组件的js文件写法跟平时有些不同,我们会将所有的配置对象,例如data,methods,properties,都写在options方法中
在这里插入图片描述

  • properties,相当于我们所学vue中的props,是父组件向子组件传递数据的桥梁
    在这里插入图片描述
2.子传父(triggerEvent)
  • 父组件向子组件传递了一个值,
  • 子组件接收该值之后会向父组件抛出一个反馈(命令)
  • 父组件去执行子组件的命令
  • 在子组件中
<view class="cell" bindtap="tapHd">
  <text>{{title}}</text>
  <text>{{count}}</text>
</view>
// components/cell/cell.js
Component({
  // 选项:
  options:{
    // 样式隔离:apply-shared 父影响子,shared父子相互影响, isolated相互隔离
    styleIsolation:"isolated",
    // 允许多个插槽
    multipleSlots:true,
    
  },
  // 通过组件的外部类实现父组件控制子自己的样式
  externalClasses:["cell-class"],

  /**
   * 组件的属性列表
   */
  properties: {
    title:{
      type:String,
      value:""
    },
    num:{
      // 定了类型
      type:Number,
      //定义默认值
      value:1
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
     count:1 
  },
  lifetimes:{
    // 当组件的生命周期被挂载时候
     attached(){
       console.log(this.data)
        // cout的值为父组件传递的num值
        this.setData({count:this.data.num})
      }
  },

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

  • 在父组件中
<cell bind:cellclick="clickHd"></cell>
// components/cell/cell.js
Component({
  // 选项:
  options:{
    // 样式隔离:apply-shared 父影响子,shared父子相互影响, isolated相互隔离
    styleIsolation:"isolated",
    // 允许多个插槽
    multipleSlots:true,
    
  },
  // 通过组件的外部类实现父组件控制子自己的样式
  externalClasses:["cell-class"],

  /**
   * 组件的属性列表
   */
  properties: {
    title:{
      type:String,
      value:""
    },
    num:{
      // 定了类型
      type:Number,
      //定义默认值
      value:1
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
     count:1 
  },
  lifetimes:{
    // 当组件的生命周期被挂载时候
     attached(){
       console.log(this.data)
        // cout的值为父组件传递的num值
        this.setData({count:this.data.num})
      }
  },

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

3.样式隔离
  • 因为组件具有很强的复用性,那么他们的样式是不应该互相干扰的,所以当styleIsolation为isolated时,各自的样式互相独立
  options:{
    // 样式隔离:apply-shared 父影响子,shared父子相互影响, isolated相互隔离
    styleIsolation:"isolated",
    // 允许多个插槽
    multipleSlots:true,
    
  },
3.定义外部类
  • externalClass:[“cell-class”]

在这里插入图片描述

<view cell-class='mycell1'>
  我是cell组件
</view> 
 <view cell-class='mycell2'>
  我是cell组件
</view> 
.mycell1{
  color: #f70;
  background-color: seagreen;
  line-height: 88rpx;
}
.mycell2{
  color: 'black';
  background-color: sienna;
  line-height: 88rpx;
}

这样我们就能够分别定义组件的样式了

4.插槽
  • 跟vue中的使用方式是一模一样的,直接看代码
  • 在父组件中
<cell>我在这里</cell>
  • 在子组件中
<view>父组件插件来的内容都放在slot里面
  <slot></slot>
<view>
5.具名插槽
  • 在父组件中
<cell cell-class="mycell">
<text>胡萝卜</text>
<text slot="first">第一</text>
<text slot="second">第二</text>

</cell>
  • 在子组件中
    在cell.js文件中开启多命名插槽
    在这里插入图片描述
<view>
  <slot name="first"></slot>
  <slot name="second"></slot>
</view>

三,案例

1.下面这张页面就可以用组件来实现

在这里插入图片描述

  1. 在components文件夹下,新建一个item文件
    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.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.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;
}

  • 在父组件中
    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.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.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;
 
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值