小程序组件化、自定义组件 、自定义组件练习,组件与页面互相传值,插槽(slot)、 component构造器
如何创建自定义组件?
文档地址:https://developers.weixin.qq.com/miniprogram/dev/reference/api/Component.html
其实和页面是一样一样的
在页面中如何引入自定义组件?
在当前页面的json文件中注册组件
组件名:“相对路径/绝对路径”
在wxml中使用就可以了
如果组件中间不需要写上内容的话,也可以使用单标签
补充一下,在自定义组件的json文件中
component:true,不能写成false或删除,否则它就不是组件了
小结一下:
在定义组件名称的时候不要用特殊符号,有可能不支持(不支持驼峰,也就是大写字母,可以用中划线和下划线将两个字母分隔)
如果在多个文件中会使用同一个自定义组件,在每个页面的json文件中注册显得有些繁琐了,我们可以直接在app.json文件中注册一个全局的自定义组件;
自定义组件和页面的样式不会互相影响,也就是自定义组件的的样式是独立的
小程序js调用是App()、页面调用的是Page()、组件调用的是Component()
是在js中设置,不是在json中设置
页面向组件传值:properties
Component({ properties: { min: { type: Number, value: 0 }, min: { type: Number, value: 0, observer: function(newVal, oldVal) { // 属性值变化时执行 } }, lastLeaf: { // 这个属性可以是 Number 、 String 、 Boolean 三种类型中的一种 type: Number, optionalTypes: [String, Object], value: 0 } } })
wxml中
<custom-comp min="1" max="5" />
此时,由于自定义组件的对应属性被规定为 Number 类型, min 和 max 会被赋值为 1 和 5 ,而非 "1" 和 "5" ,即:
this.data.min === 1 // true
this.data.max === 5 // true
页面向组件传递class样式:externalClasses
同样的在组件js中设置
Component({ externalClasses: ['my-class'] })
<!-- 组件 custom-component.wxml --> <custom-component class="my-class">这段文本的颜色由组件外的 class 决定</custom-component>
组件内
<view class="my-class">哈哈哈</view>
组件向外界传递事件(自定义事件)
假如说,一个组件是一个按钮,点击这个按钮让页面里的数据+1
组件里的button
在组件js中的methods中定义一个方法,这个方法使用triggerEvent创建一个自定义事件,第一个参数是自定义事件的名称,第二个参数是,需要传递的参数,第三个参数是一些配置数据,一般很少用到
在页面的组件里监听这个自定义事件,然后调用页面里定义的事件
在event的detail中可以拿到自定义事件传来的数据
自定义组件练习:编写一个tabbar组件:(并且练习组件向页面传值 利用自定义事件)
创建一个组件
组件的wxml
<view class="tab-control"> <block wx:for="{{titles}}" wx:for-item="title_item" wx:for-index="title_index" wx:key="*this"> <view class="tab-item {{currentIndex == title_index ? 'active' : ''}}" bind:tap="handleItemClick" data-index="{{title_index}}"> <text>{{title_item}}</text> </view> </block> </view>
组件的wxss
.tab-control{ display: flex; height:88rpx; line-height: 88rpx; background: orange; } .tab-item{ flex: 1; text-align: center; } .active text{ color:red; border-bottom: 6rpx solid red; padding: 16rpx 10rpx; }
组件的js
// components/w-tab-control/w-tab-control.js Component({ /** * 组件的属性列表 */ properties: { titles:{ type:Array, value:[] }, }, /** * 组件的初始数据 */ data: { currentIndex:0 }, lifetimes: { // 生命周期函数,可以为函数,或一个在methods段中定义的方法名 attached: function () { console.log(this.properties.titles) }, moved: function () { }, detached: function () { }, }, /** * 组件的方法列表 */ methods: { handleItemClick(event){ console.log(event) console.log(event.currentTarget.dataset.index) this.setData({ currentIndex: event.currentTarget.dataset.index }) // 自定义事件通知外部页面 我点击的index 以及内容 this.triggerEvent('itemClick', { index: event.currentTarget.dataset.index, title: this.properties.titles[event.currentTarget.dataset.index] }) } } })
外部页面
外部页面.json
{ "usingComponents": { "w-tab-control":"/components/w-tab-control/w-tab-control" } }
外部页面的wxml
<!-- 自定义组件练习 --> <w-tab-control titles="{{['衣服','裤子','鞋子','帽子']}}" bind:itemClick="tabcontrolClick"/>
外部页面的js
// pages/home/home.js Page({ /** * 页面的初始数据 */ data: { }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { }, /** * 生命周期函数--监听页面初次渲染完成 */ onReady: function () { }, /** * 生命周期函数--监听页面显示 */ onShow: function () { }, /** * 生命周期函数--监听页面隐藏 */ onHide: function () { }, /** * 生命周期函数--监听页面卸载 */ onUnload: function () { }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh: function () { }, /** * 页面上拉触底事件的处理函数 */ onReachBottom: function () { }, /** * 用户点击右上角分享 */ onShareAppMessage: function () { }, // 接收自定义事件的方法 tabcontrolClick(e){ console.log(e) console.log(e.detail.index) console.log(e.detail.title) } })
最后效果是,点击tabbar对应的项的文字变红以及下面多个红色的边框,并且页面可以监听到点击的tabbar的index以及title
上面是组件内触发页面的改变,想页面传值,那么页面应该如何改变组件内的值呢?
加入说有个my-sel组件,里面有个counter初始值为0
我们在页面有一个button,点击这个buton,使组件内的counter+1
首先我们需要给这个组件绑定一个方法,在这个方法内我们可以通过一个api拿到页面内的某一个组件对象,这样我们就可以通过组件.setData方法改变组件内的值了:
页面内wxml
<button size="mini" bind:tap="handleIncreamentCpn">修改组件内的数据</button> <my-sel id="sel-id"/>
页面内js(这里是获取到组件对象,直接通过setData的方法改变组件内的值的,这样虽然可以,但是不推荐这样做,推荐组件内的方法改变组件内的值,这是一种规范)
handleIncreamentCpn(e) { var mySel = this.selectComponent("#sel-id"); console.log(mySel); mySel.setData({ counter:mySel.data.counter +1 }) }
this.selectComponent(.class/#id) 可以根据id或class获取页面内的某一个组件对象,获取到组件对象后就可以直接更改组件内的值或者调用里面的方法了
下面我们通过调用组件内的方法来改变组件内的值,这样是规范
我们先在组件内的methods中声明一个方法,来改变组件内counter的值
increament(num){ this.setData({ counter:this.data.counter+num }) }
然后我们在页面内的事件汇总调用此组件对象中的这个方法,从而改变组件内的值:
handleIncreamentCpn(e) { var mySel = this.selectComponent("#sel-id"); mySel.increament(2); }
插槽 slot
插槽分为单插槽的使用和多插槽的使用
现在我们来看一下单插槽如何使用:
先建个插槽组件
在插槽的wxml中:
<view>我是组件的头部</view> <slot/> <view>我是组件的底部</view>
在页面汇总就可以使用这个组件插入不同类型的内容了
<!-- 插入个按钮 --> <my-sel id="sel-id"/> <my-slot> <button size="mini">我是单个插槽</button> </my-slot> <!-- 插入个文本 --> <my-slot> <text>我是插槽插入的文本</text> </my-slot> <!-- 插入图片 --> <my-slot> <image src="http://kexiepingtaieposter.hoohui.cn//registFile/fa5df7c9-445d-4b58-97c4-ad8b86a92241/Z0134_2020022293115.png"></image> </my-slot> <!-- 插入滑块 --> <my-slot> <slider value="60"></slider> </my-slot>
下面来介绍多个插槽都而使用:
需要注意两点:
1、多插槽需要给每个slot插槽命名(加name属性)
2、使用多插槽时,注意在组件的component对象中(组件js中)加上options----》multipleSlots:true, 说明我们要使用的是多插槽
组件wxml
<view>我是组件的头部</view> <slot name="slot1"/> <slot name="slot2"/> <slot name="slot3"/> <view>我是组件的底部</view>
组件js
Component({ options:{ multipleSlots:true, }, }
页面汇总插入内容
<my-slot> <button size="mini" slot="slot1">插槽一</button> <button size="mini" slot="slot2">插槽二</button> <button size="mini" slot="slot3">插槽三</button> </my-slot>
component构造器
properties:页面向组件传一些值,里面可以定义一个observe(newval,oldval)方法,来监听属性都额变化
data:初始化数据
methods:定义一些组件内的方法
options:对组件进行一些配置;比如styleIsolation:“shared”,控制组件样式的共享方式,multipleSlot:true,使用多插槽
组件的生命周期:
组件的生命周期分为两种
1、监听页面的声明周期
pageLifetimes: { // 组件所在页面的生命周期函数 show: function () { },//监听组件在页面显示出来的声明周期 hide: function () { },//监听组件在页面中退出的生命周期函数 resize: function () { },//监听页面尺寸改变的生命周期函数 很少用 },
2、监听组件本身的声明周期
lifetimes: { // 生命周期函数,可以为函数,或一个在methods段中定义的方法名 created:function(){},//组件被创建出来的术后 attached: function () { },//组件被添加到页面 ready:function(){},//组件被渲染出来 moved: function () { },//组件从一个节点移动到另一个节点 很少用 detached: function () { },//移除组件 添加组件相对应 },
。