评论

小程序组件化开发

在小程序开发中,很多场景下往往只有数据不同而模板一样,需要进行自定义组件封装,可提高编码效率,和代码复用率。本文将简介两个组件化实现方式。

一、组件实现方式: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组件方式实现,灵活性更高。

参考文献

官方文档

点赞 5
收藏
评论
登录 后发表内容