一、组件实现方式:template模板和component构造器
除了component,小程序中还有另一种组件化你的方式template模板
区别:
1、template主要是展示,方法则需要在调用的页面中定义。简单来说,如果只是展示,使用template就足够了
2、而component组件则有自己的业务逻辑,可以看做一个独立的page页面。如果涉及到的业务逻辑交互比较多,那就最好使用component组件了。
二、template模板
1、模板定义
建议单独创建template目录,在template目录中创建管理模板文件。
由于模板只有wxml、wxss文件,一个template的模板文件和样式文件只需要命名相同即可,方法则需要在调用的页面中定义
模板文件(wxml):用name区分多个模板
<template name="packModule">
<view class="packModule">packModule</view>
</template>
模板文件(wxss):自定义模板的样式文件(略),实例中模块相关样式都统一集中在module.wxss中
2、页面引用:(如首页引用)
index.wxml:
<!--导入模板-->
<import src="./modules/pack.wxml"/>
<!--嵌入模板-->
<view class="moduleWrap" wx:for="{{moduleInfoList}}" wx:for-item="moduleInfo" wx:key="index">
<!--自由容器模块 里面还有子模块-->
<template is="packModule" data="{{moduleInfo}}" wx-if="{{moduleInfo.style == 5}}"></template>
<view>
index.wxss:
@import "../../libs/templates/module.wxss";
备注:
一个模板文件中可引用多个template,每个template均以name进行区分,页面调用的时候也是以name指向对应的template;
template模板没有配置文件(.json)和业务逻辑文件(.js),所以template模板中的变量引用和业务逻辑事件都需要在引用页面的js文件中进行定义;
三、Component组件:
1. 组件创建:
新建component目录——创建子目录——新建Component(如示例组件:dialog组件)
示例dialog组件也由4个文件构成,与page文件类型相同,但是js文件和json文件与页面有所不同。
dialog.wxml:
<view class="dialog" wx:if="{{ isShow }}">
<!-- 遮罩层 -->
<view class="dialog_mask" catchtouchmove="_catchTouch"></view>
<!-- 内容 -->
<view class="container" catchtouchmove="_catchTouch">
<view class="title" wx:if="{{title}}">{{title}}</view>
<view class="content" wx:if="{{content}}">
{{content}}
</view>
<view class="footer">
<view class="btn cancel_btn" wx:if="{{showCancelButton}}" bindtap="hide" style='background-color:{{globalColor}};'>{{cancelButton}}</view>
<view class="btn comfirm_btn" bindtap="comfirm" style='background-color:{{globalColor}};'>{{confirmButton}}</view>
</view>
</view>
</view>
dialog.json:
{
"component": true,
"usingComponents": {}
}
dialog.wxss:(组件对应 wxss 文件的样式,只对组件wxml内的节点生效)
/* components/dialog/dialog.wxss */
.dialog {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
position: fixed;
top:0;
z-index: 9999;
}
...
dialog.js:
/*
* dialog 模态对话框
* Props
* 通过事件调用组件
* globalColor:全局色
* Event
* show 模态对话框 @param {Object} 配置参数
* hide 模态对话框
* Example
* 1、页面中引用dialog:(示例index页面)
* 1-1:index.json中声明组件引用
* {
* "usingComponents": {
* "dialog": "../../components/dialog/dialog"
* }
* 1-2:index.wxml引用模板
* <dialog id='dialog' global-color="{{globalColor}}"></toast>
* 1-3:index页面所引用js文件中,获取组件实例
* onReady: function () {
* //获得组件
* this.dialog = this.selectComponent("#dialog");
* }
* 2、根据业务条件进行调用:
* 2-1、页面中调用:
* this.dialog.show({
* title: "提交成功",
* content: "描述信息",
* cancelButton: "取 消",
* showCancelButton:false,//是否显示取消按钮,可缺省,默认不显示
* confirmButton: '确 定',
* callback: function () {}//确定按钮回调函数,可缺省,默认只关闭对话框
* });
* 2-1、页面组件中调用:
* getCurrentPages()[getCurrentPages().length - 1].dialog.show(...);//传参同上
* 备注:不直接在组件ready中获取dialog组件,会产生多个组件实例,故直接调用页面已有组件实例方法
*/
Component({
/**
* 组件的属性列表
*/
properties: {
'globalColor': String
},
/**
* 组件的初始数据
*/
data: {
isShow: false,
title: '标题',// 弹窗标题
content: "", // 弹窗内容
cancelButton: '取 消',
showCancelButton:false,//是否显示"取消"按钮
confirmButton: '确 定',
callback: null //回调函数
},
/**
* 组件的方法列表
*/
methods: {
//隐藏信息提示
hide() {
this.setData({
isShow: !this.data.isShow
})
},
// 阻止页面滚动
_catchTouch: function () {
return;
},
//展示信息提示
show(options) {
this.setData({
isShow: !this.data.isShow,
callback:null
});
let _this = this;
// 通过options参数配置
if (options) {
this.setData(options);
}
},
// 确定回调
comfirm(){
this.hide();
this.data.callback && this.data.callback();//执行各dialog的回调逻辑
}
}
})
2、页面引用:
index.json:(需在json配置文件中进行配置开启使用组件)
{
"usingComponents": {
"dialog": "/components/dialog/dialog"
}
}
index.wxml:(模板文件中引用)
<!-- 自定义dialog组件 -->
<dialog id='dialog' global-color="{{globalColor}}"></dialog>
四、注意点:
1、component组件中扩展自定义节点:
在组件模板中可以提供一个 <slot> 节点,用于承载组件引用时提供的子节点。
默认情况下,一个组件的wxml中只能有一个slot。需要使用多slot时,可以在组件js中声明启用,以不同的 name 来区分。
Component({
options: {
multipleSlots: true // 在组件定义时的选项中启用多slot支持
}
})
2、component组件样式注意点:
组件对应 wxss 文件的样式,只对组件wxml内的节点生效。
2-1、组件和引用组件的页面不能使用id选择器(#a)、属性选择器([a])和标签名选择器,请改用class选择器。
2-2、组件和引用组件的页面中使用后代选择器(.a .b)在一些极端情况下会有非预期的表现,如遇,请避免使用。
2-3、子元素选择器(.a>.b)只能用于 view 组件与其子节点之间,用于其他组件可能导致非预期的情况。
2-4、继承样式,如 font 、 color ,会从组件外继承到组件内。
2-5、除继承样式外, app.wxss 中的样式、组件所在页面的的样式对自定义组件无效(除非更改组件样式隔离选项)。
#a { } /* 在组件中不能使用 */
[a] { } /* 在组件中不能使用 */
button { } /* 在组件中不能使用 */
.a > .b { } /* 除非 .a 是 view 组件节点,否则不一定会生效 */
五、组件间通信与事件:
1、父组件(调用页面)向子组件传值通讯:
通过properties向自定义组件传递数据
2、子组件向父组件(调用页面)传值通讯:
1、监听事件
自定义组件可以触发任意的事件,引用组件的页面可以监听这些事件
<!-- 当自定义组件触发“myevent”事件时,调用“onMyEvent”方法 -->
<component-tag-name bindmyevent="onMyEvent" name="{{name}}" />
Page({
data:{
name:"test"
},
onMyEvent: function(e){
e.detail // 自定义组件触发事件时提供的detail对象
}
})
2、触发事件
自定义组件触发事件时,需要使用 triggerEvent 方法,指定事件名、detail对象和事件选项:
<!-- 在自定义组件中 -->
<view>{{name}}</view>
<button bindtap="onTap">点击这个按钮将触发“myevent”事件</button>
Component({
properties: {
name: {
type: String,
value: ''
}
},
methods: {
onTap: function(){
var myEventDetail = {} // detail对象,提供给事件监听函数
var myEventOption = {} // 触发事件的选项
this.triggerEvent('myevent', myEventDetail, myEventOption)
}
}
})
总结
自定义组件,可以理解为一个自定义的标签,页面的一个片段,可以分为template方式和component组件方式实现;如果是简单的内容展示,逻辑单一,使用template方式即可,但如果每一个组件都有自己的业务逻辑,各自独立,建议使用component组件方式实现,灵活性更高。