05 小程序自定义组件

1.小程序自定义组件的意义

       小程序允许我们使用自定义组件方式来来构建画面,主要难点在于父向子组件传递数据,子向父组件传递数据和组件插槽功能,实现点击标题数据也发生变化。且所谓的自定义组件,也是由json,wxml,wxss,js四个部分组成

       开发步骤:创建组件→声明组件→使用组件

1.1 自定义组件components→Tabs

第一步:创建自定义组件分为几个步骤:

  • 首先创建pages同级文件components,在components下面创建Tabs文件夹,其实此后也就认为该Tabs文件夹为自定义组件了。
  • 其次右击Tabs选择新建component,输入Tabs回车,即可自动生成相应的Tabs.js,Tabs.json,Tabs.wxml,Tabs.wxss
  • 看效果,此时打开Tabs.js与其他js文件差异:

image

image

第二步:声明自定义组件,说白了就是立个flag,哪个页面用就在

哪个json中声明

{

"usingComponents": {

"Tabs":"../../components/Tabs/Tabs"

}

} 例如我们在demo17.json中添加,usingComponet里面是键值对:

image

第三步:使用组件

      我们在demo17.wxml中使用<Tabs>00</Tabs>没有显示00,但显示了其自定义组件的里面的信息。

image


1.2 自定义组件实战-emmet写法


注意,设为 Flex 布局以后,子元素的floatclearvertical-align属性将失效。参见:https://www.cnblogs.com/huihuizhang/p/7998902.html

需要注意的是:tabs.wxml中如果这么写,就写死了,这样就没办法把同样的结构放在不同的页面中,我们需要把标题数据,也就是首页,原创,分类,关于抽离出来,放在tabs.js文件中,我们先尝试把它放在组件内部数据中,稍后再由它(组件内部数据)改成父向子传递数据:

<view class="tabs">

<view class="tabs_title">

<view class="title_item">首页</view>

<view class="title_item">原创</view>

<view class="title_item">分类</view>

<view class="title_item">关于</view>

</view>

<view class="tabs_content">内容</view>

</view>

第一步案例:自定义组件的样式案例:

Tabs.js代码

// components/Tabs/Tabs.js

Component({

/**

   * 组件的属性列表

   */

  properties: {

/*接受父向子传递数据 */

},

/**

   * 组件的初始数据

   */

  data: {

    tabs:[{

      id:0,

      name:"首页",

      isActive:true

},

{

      id:1,

      name:"原创",

      isActive:false

},

{

      id:2,

      name:"分类",

      isActive:false

},

{

      id:0,

      name:"关于",

      isActive:false

},

    ]

},

/**

   * 组件的方法列表

   * 在page页面js中,存放事件回调函数的时候,存放在data同级下

   * 在组件页面js中,存放事件回调函数的时候,必须放在methods中

   */

  methods: {

hanldeItemTap(e){

// console.log("点击我试试");

// 1. 绑定点击事件,需要在methods中绑定

console.log(e)

// 2. 获取被点击的索引

const {index}= e.currentTarget.dataset;

// const {index}=e.currentTarget.dataset

// 3. 获取原数组

let {tabs}=this.data;//此处涉及解构思想,复杂类型进行结构时候,复制了一份变量引用而已,它与let tabs=this.data.tabs意思一样

//当然最严谨的做法是重新拷贝一个数组,如下:

// let tabs=JSON.prase(JSON.stringify(this.data.tabs));

// 4. 对数组循环,给每个循环项,选中属性改为false,且给当前的索引项添加激活选中效果即可,因有解构,类似于this.data.tabs.forEach一样

tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);

this.setData({

tabs

})

}

}

})

Tabs.wxss文件代码:

/* components/Tabs/Tabs.wxss */

.tabs{

border: 1rpx blue solid;

}

.tabs_title{

display: flex;/*伸缩盒子*/

padding: 10rpx;

}

.title_item{

flex: 1;

display: flex;/*伸缩盒子*/

justify-content: center;/*垂直对齐*/

align-items: center;/*水平对齐*/

}

.active{/*激活选中效果*/

color:red;

border-bottom: 10rpx solid currentColor;

}

.tabs_content{

border: 1rpx solid yellow;

}

Tabs.wxml代码如下:

<!--components/Tabs/Tabs.wxml-->

<view class="tabs">

<view class="tabs_title">

<!--

    <view class="title_item">首页</view>

    <view class="title_item">原创</view>

    <view class="title_item">分类</view>

    <view class="title_item">关于</view>

  -->

<view wx:for="{{tabs}}" wx:key="id" class="title_item {{item.isActive? 'active':''}}"

bindtap="hanldeItemTap"

data-index='{{index}}'

    >{{item.name}}</view>

</view>

<view class="tabs_content">内容</view>

</view>

demo17.WXML代码:

<!--pages/demo17/demo17.wxml-->

<Tabs></Tabs>



第二步:抽离自定义组件内部Tabs.js下面Componet下面的data里面tabs数据抽离到demo17里面,这样才能实现一个自定义组件多处使用,这就存在了父向子组件传值的问题,最为简单的处理方式是:属性值传递:

image

具体实现代码如下:

demo17.html

<!--pages/demo17/demo17.wxml-->

<!--

  1.父组件(页面)传递数据通过标签属性

  2.子组件进行接收

-->

<!--下面代表意思是,我向子组件Tabs传递了一个属性:属性名aaa 属性值123-->

<Tabs tabs="{{tabs}}"></Tabs>


Tabs.wxml

<!--components/Tabs/Tabs.wxml-->

<view class="tabs">

<view class="tabs_title">

<!--

    <view class="title_item">首页</view>

    <view class="title_item">原创</view>

    <view class="title_item">分类</view>

    <view class="title_item">关于</view>

  -->

<view wx:for="{{tabs}}" wx:key="id" class="title_item {{item.isActive? 'active':''}}"

bindtap="hanldeItemTap"

data-index='{{index}}'

    >{{item.name}}</view>

</view>

<view class="tabs_content">内容</view>

</view>


Tabs.js

// components/Tabs/Tabs.js

Component({

/**

   * 组件的属性列表

   */

  properties: {

/*接受父向子传递数据 */

// 从demo17.WXML数据

// aaa:{

//   // type:表示要接收的数据类型

//   type:String,

//   value:''//表示默认值,传123,就123,没有为空

// }

    tabs:{

      type:Array,

      value:[]

}

},

/**

   * 组件的初始数据

   */

  data: {

},

/**

   * 组件的方法列表

   * 在page页面js中,存放事件回调函数的时候,存放在data同级下

   * 在组件页面js中,存放事件回调函数的时候,必须放在methods中

   */

  methods: {

hanldeItemTap(e){

// console.log("点击我试试");

// 1. 绑定点击事件,需要在methods中绑定

console.log(e)

// 2. 获取被点击的索引

const {index}= e.currentTarget.dataset;

// const {index}=e.currentTarget.dataset

// 3. 获取原数组

let {tabs}=this.data;//此处涉及解构思想,复杂类型进行结构时候,复制了一份变量引用而已,它与let tabs=this.data.tabs意思一样

//当然最严谨的做法是重新拷贝一个数组,如下:

// let tabs=JSON.prase(JSON.stringify(this.data.tabs));

// 4. 对数组循环,给每个循环项,选中属性改为false,且给当前的索引项添加激活选中效果即可,因有解构,类似于this.data.tabs.forEach一样

tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);

this.setData({

tabs

})

}

}

})

Demo17.js

// pages/demo17/demo17.js

Page({

/**

   * 页面的初始数据

   */

  data: {

    tabs:[{

      id:0,

      name:"首页",

      isActive:true

},

{

      id:1,

      name:"原创",

      isActive:false

},

{

      id:2,

      name:"分类",

      isActive:false

},

{

      id:0,

      name:"关于",

      isActive:false

},

    ]

},


image

第三步:我们进行代码优化上图可知:当我们tab.js的properties接受父数据tabs:{  }(父传子),当我们点击标题内容,关于时,应该会触发点击事件,而此时data数据为空的。因此

  methods: {

hanldeItemTap(e){

// console.log("点击我试试");

// 1. 绑定点击事件,需要在methods中绑定

console.log(e)

// 2. 获取被点击的索引

const {index}= e.currentTarget.dataset;下一步将出错,因为data为空,

let tabs也就错误了,一句话:isActive值没有改变

// const {index}=e.currentTarget.dataset

// 3. 获取原数组

let {tabs}=this.data;//此处涉及解构思想,复杂类型进行结构时候,复制了一份变量引用而已,它与let tabs=this.data.tabs意思一样

//当然最严谨的做法是重新拷贝一个数组,如下:

// let tabs=JSON.prase(JSON.stringify(this.data.tabs));

// 4. 对数组循环,给每个循环项,选中属性改为false,且给当前的索引项添加激活选中效果即可,因有解构,类似于this.data.tabs.forEach一样

tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);

this.setData({

tabs

})

}

}

总结一句话,就是当我们点击标签后,激活事件应该改变,如下图就没有改变,这一步操作就是子向父传数据:

image






原文地址:https://www.cnblogs.com/rango0550/p/13860399.html