微信小程序-自定义组件

十年河东,十年河西,莫欺少年穷

学无止境,精益求精

1、首先我们创建一个基本的小晨旭组件【/Components/Tabs/Tabs】,如下

Tabs.js

// pages/Components/Tabs/Tabs.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {

  },

  /**
   * 组件的初始数据
   */
  data: {
    tabs: [{
        id: 0,
        name: "首页",
        isactive: true
      },
      {
        id: 1,
        name: "原创",
        isactive: false
      },
      {
        id: 2,
        name: "分类",
        isactive: false
      },
      {
        id: 3,
        name: "关于",
        isactive: false
      }
    ]
  },

  /**
   * 组件的方法列表
   */
  methods: {
    tabitemchange: function (e) {
      const {
        index
      } = e.currentTarget.dataset;
      let list = this.data.tabs;
      list.forEach((v, i) => {
        console.log(v);
        console.log(i);
        i == index ? v.isactive = true : v.isactive = false;
      });
      this.setData({
        tabs: list
      });
    }
  }
})

Tabs.wxss

/* pages/Components/Tabs/Tabs.wxss */
.tabs{

}
.tabs_title{
  display: flex;
  padding:10rpx;
}
.tabs_item{
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
}
.active{
  color:red;
  border-bottom:4rpx solid red;
}
.tabs_content{}

Tabs.wxml ,注:tabitemchange 点击方法传参为:data-index 及 wx:for 中 item 的索引

<view class="tabs">
  <view class="tabs_title">
    <view 
    class="tabs_item {{item.isactive?'active':''}}" 
    wx:for="{{tabs}}" 
    wx:key="id"
    bindtap="tabitemchange"
    data-index="{{index}}"
    wx:for-index="index"
    wx:for-item="item"
    >
    {{item.name}}
  </view>
    <!-- <view class="tabs_item active" bindtap="tabitemchange">首页</view>
    <view class="tabs_item">原创</view>
    <view class="tabs_item">分类</view>
    <view class="tabs_item">关于</view> -->
  </view>
  <view class="tabs_content">内容</view>
</view>

在page页面中,引用该组件,如下

demo17.json

{
  "usingComponents": {"Tabs":"../Components/Tabs/Tabs"}
}

demo17.wxml

<Tabs> 
  
</Tabs>

这样,demo17的页面展示如下

 

 

 以上我们就简单构建了一个组件。

在上述构造中,父组件为页面demo17.wxml ,子组件为tabs.wxml,那么组件之间怎么进行传值呢?

父向子传值

首先演示下父向子传值的简易demo,如下

在父组件中,自定义一个属性叫:fatherData

<!--pages/demo17/demo17.wxml-->
<Tabs fatherData="请叫我爸爸"> 
</Tabs>

在子组件的属性中,创建 对象fatherData ,并声明 Type 属性为字符串,value 默认为空值

// pages/Components/Tabs/Tabs.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    fatherData:{
      type:String,
      value:""
    }
  },

最后,在Tabs.wxml中添加如下代码

  <view>
  我接受到的值为:{{fatherData}}
</view>

保存,并查看效果

 

这样,父传子就简单的完成了。

现在,我们传递变量给子组件,在demo17.js 中创建tabs数组如下:

// pages/demo17/demo17.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    tabs: [{
      id: 0,
      name: "首页",
      isactive: true
    },
    {
      id: 1,
      name: "原创",
      isactive: false
    },
    {
      id: 2,
      name: "分类",
      isactive: false
    },
    {
      id: 3,
      name: "关于",
      isactive: false
    }
  ]
  },
})

然后在demo17.wxml 中修改如下:

<!--pages/demo17/demo17.wxml-->
<Tabs tabs="{{tabs}}"> 
</Tabs>

最后,在子组件Tab.js中申明要接收的tabs的类型及默认值

// pages/Components/Tabs/Tabs.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    tabs:{
      type:Array,
      value:[]
    }
  },

此时保存,并查看页面效果,和之前一样

 

但是,此时,子组件的tabitemchange 点击事件就有问题了,如下:

// pages/Components/Tabs/Tabs.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    tabs:{
      type:Array,
      value:[]
    }
  },

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

  /**
   * 组件的方法列表
   */
  methods: {
    tabitemchange: function (e) {
      const {
        index
      } = e.currentTarget.dataset;
      let list = this.data.tabs;
      list.forEach((v, i) => {
        console.log(v);
        console.log(i);
        i == index ? v.isactive = true : v.isactive = false;
      });
      this.setData({
        tabs: list
      });
    }
  }
})
View Code

 

 此时,子组件的data 中并没有tabs 变量,因此 this.setData({}) 不生效,也不报错

现在,tabs 变量是父组件传递过来的,那么,我们真正要修改的是父组件的tabs变量,这时,就需要子向父传值了,可参考:https://www.bilibili.com/video/BV1nE41117BQ?p=40

子向父传值

 子向父传值时,需要使用  this.triggerEvent("itemChange",index); 绑定一个触发事件,并传递 index 变量

因此,在tabs.js 中 我们修改如下:

// pages/Components/Tabs/Tabs.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    tabs:{
      type:Array,
      value:[]
    }
  },

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

  /**
   * 组件的方法列表
   */
  methods: {
    tabitemchange: function (e) {
      const  index= e.currentTarget.dataset.index;
      this.triggerEvent("itemChange",index);
    }
  }
})

在父组件中,我们接受这个触发事件,如下:

<!--pages/demo17/demo17.wxml-->
<Tabs tabs="{{tabs}}" binditemChange="itemChange"> 
</Tabs>

在父组件中,定义itemChange方法

// pages/demo17/demo17.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    tabs: [{
      id: 0,
      name: "首页",
      isactive: true
    },
    {
      id: 1,
      name: "原创",
      isactive: false
    },
    {
      id: 2,
      name: "分类",
      isactive: false
    },
    {
      id: 3,
      name: "关于",
      isactive: false
    }
  ]
  },
  itemChange:function(e){
    console.log(e)
    const  index= e.detail; //传递过来的值 一般都放在 e.detail 中
    let list = this.data.tabs;
    list.forEach((v, i) => {
      i == index ? v.isactive = true : v.isactive = false;
    });
    this.setData({
      tabs: list
    });
  }
})

这样,父组件就可以根据自个的需求,进行导航条的定义了。

最后,我们根据条目的切换,显示的内容变成动态的,这时,我们需要使用一个标签,插槽

插槽---Slot

首先在子组件中,内容部分,用插槽替代,如下

  <view class="tabs_content">
    <slot></slot>
  </view>

在父组件中,填充插槽

<!--pages/demo17/demo17.wxml-->
<Tabs tabs="{{tabs}}" binditemChange="itemChange"> 
  <view>
    我要替代插槽
  </view>
</Tabs>

效果如下

 

 最后,我们将我要替代插槽改成变量,即可完成内容的动态化

<!--pages/demo17/demo17.wxml-->
<Tabs tabs="{{tabs}}" binditemChange="itemChange"> 
 <block wx:if="{{tabs[0].isactive}}">首页被选中</block>
 <block wx:elif="{{tabs[1].isactive}}">原创被选中</block>
 <block wx:elif="{{tabs[2].isactive}}">分类被选中</block>
 <block wx:else="{{tabs[3].isactive}}">关于被选中</block>
</Tabs>

效果

 

 @天才卧龙的博客

posted @ 2021-11-02 20:14  天才卧龙  阅读(251)  评论(0编辑  收藏  举报