# 自定义组件

自定义组件,和vue中自定义组件类似,都是封装公共组件,减少代码开发量。

自定义组件 (opens new window)

# 1、创建自定义组件

  • 新建自定义组件的文件 必须包含 .wxml .wxss .js .json
  • 定义组件.json文件必须定义 "component": true,才可以
  • 其他组件使用必须在.json文件内进行 注册引入,然后才能在页面中使用组件标签
  • 在组件wxss中不应使用ID选择器、属性选择器和标签名选择器
  • 因为 WXML 节点标签名只能是小写字母、中划线和下划线的组合,所以自定义组件的标签名也只能包含这些字符。
├── components               # 业务公共组件
│   ├── PictureView          # PictureView组件
│   │   ├── index.js         # 页面逻辑处理
│   │   ├── index.json       # 页面配置
│   │   ├── index.wxml       # html
│   │   ├── index.wxss       # css
│   │   └── index.less       # less/sass

# 2、组件的引用

组件引用必须在.json中进行注册才能使用

// .json
{
  "navigationBarTitleText": "首页",
  "usingComponents": {
    "picture-view": "../../components/picture-view/index"
  }
}

# 3、组件之间传值

<view class="index">
  <picture-view url="hello world"></picture-view>
</view>
// components/picture/index.js
Component({
  /**
   * 组件的属性列表
   * 父组件传入的值,相当于prop
   */
  properties: {
    url: {
      type: String,
      value: 'default value'
    }
  },
  // 声明周期
  lifetimes: {
    // 页面已经创建好,执行一些初始化操作,如果获取数据、设置数据
    attached: function() {
      console.log(this.data.url); // hello world
    }
  }
})

# 4、组件事件触发

子组件触发数据

<view class="picture">
  <button bindtap="onTap">触发自定义“myevent”事件</button>
</view>
// components/picture/index.js
Component({
  /**
   * 组件的属性列表
   * 父组件传入的值,相当于prop
   */
  properties: {
    url: {
      type: String,
      value: 'default value'
    }
  },
  // 声明周期
  lifetimes: {
    // 页面已经创建好,执行一些初始化操作,如果获取数据、设置数据
    attached: function() {
      console.log(this.data.url); // hello world
    }
  },
  
  /**
   * 组件的方法列表
   */
  methods: {
    // 提交自定义事件
    onTap: function(){
      const params = {
        type: 1
      }
      this.triggerEvent('myevent', params)
    }
  }
})

父组件接收

<view class="index">
  <picture-view url="hello world" bind:myevent="onMyEvent"></picture-view>
</view>
// 父组件.js

// 接收组件自定义事件
onMyEvent(e) {
  console.log(e.detail); // e.detail 传入的参数 {type: 1}
}

# 5、组件的声明周期

组件重要的生命周期是 created  attached  detached

  • created 在组件实例刚刚被创建时执行, 此时还不能调用 setData,也不能获取properties
  • attached 页面已经创建好,执行一些初始化操作,如果获取数据、设置数据。
  • detached在组件离开页面触发。

以前低版本声明周期都是直接定义在最外层的,自小程序基础库版本 2.2.3 起,组件的的生命周期也可以在 lifetimes 字段内进行声明(这是推荐的方式,其优先级最高)。

// components/picture/index.js
Component({
  /**
   * 组件的属性列表
   * 父组件传入的值,相当于prop
   */
  properties: {
    url: {
      type: String,
      value: 'default value'
    }
  },

  /**
   * 私有数据-组件的初始数据
   */
  data: {
    currentId: '123'
  },
  
  // 组件声明周期
  // 自小程序基础库版本 2.2.3 起,组件的的生命周期也可以在 lifetimes 字段内进行声明(这是推荐的方式,其优先级最高)。
  lifetimes: {
    // 在组件实例刚刚被创建时执行, 此时还不能调用 setData
    created: function() {
      console.log(this.data); // 获取data数据,但properties数据还不能获取
    },
    // 页面已经创建好,执行一些初始化操作,如果获取数据、设置数据
    attached: function() {
      console.log(this.data); // 获取data数据
      this.setData({
        currentId: '456'
      })
    },
    detached: function() {
      // 在组件实例被从页面节点树移除时执行
    }
  }
})

# 6、behaviors

behaviors相当于vue的mixins的混入

# 7、事件监听

observers数据监听器可以用于监听和响应任何属性和数据字段的变化,可以监听变量,对象,数组的变化。相当于vue中的watch和computed的结合。

observers数据监听 (opens new window)

// components/picture/index.js
Component({
  /**
   * 组件的属性列表
   * 父组件传入的值,相当于prop
   */
  properties: {
    url: {
      type: String,
      value: 'default value'
    }
  },

  /**
   * 私有数据-组件的初始数据
   */
  data: {
    currentId: '123',
    msg: 'hello world'
  },
  
  // 组件声明周期
  // 自小程序基础库版本 2.2.3 起,组件的的生命周期也可以在 lifetimes 字段内进行声明(这是推荐的方式,其优先级最高)。
  lifetimes: {
    // 在组件实例刚刚被创建时执行, 此时还不能调用 setData
    created: function() {
      console.log(this.data); // 获取data数据,但properties数据还不能获取
    },
    // 页面已经创建好,执行一些初始化操作,如果获取数据、设置数据
    attached: function() {
      console.log(this.data); // 获取data数据
      this.setData({
        currentId: '456'
      })
    },
    detached: function() {
      // 在组件实例被从页面节点树移除时执行
    }
  },
   
  // 数据监听
  observers: {
    'numberA, numberB': function(numberA, numberB) {
      // 在 numberA 或者 numberB 被设置时,执行这个函数
      this.setData({
        sum: numberA + numberB
      })
    }
  }
})

# 8、组件的使用

子组件:

.wxml

<!--components/picture-view/index.wxml-->
<view class="picture">
  <image src="{{url}}"></image>
  <button bindtap="onTap">触发自定义“myevent”事件</button>
</view>

.js

// components/picture/index.js
Component({
  /**
   * 组件的属性列表
   * 父组件传入的值,相当于prop
   */
  properties: {
    url: {
      type: String,
      value: 'default value'
    }
  },

  /**
   * 私有数据-组件的初始数据
   */
  data: {
    currentId: '123',
    msg: 'hello world',
    student: {
      age: 18,
      name: 'lihua'
    }
  },
  
  // 组件声明周期
  // 自小程序基础库版本 2.2.3 起,组件的的生命周期也可以在 lifetimes 字段内进行声明(这是推荐的方式,其优先级最高)。
  lifetimes: {
    // 在组件实例刚刚被创建时执行, 此时还不能调用 setData
    created: function() {
      console.log(this.data); // 获取data数据,但properties数据还不能获取
    },
    // 页面已经创建好,执行一些初始化操作,如果获取数据、设置数据
    attached: function() {
      console.log(this.data); // 获取data数据
      this.setData({
        currentId: '456'
      })
    },
    detached: function() {
      // 在组件实例被从页面节点树移除时执行
    },
  },

  /**
   * 组件的方法列表
   */
  methods: {
    // 提交自定义事件
    onTap: function(){
      const params = {
        type: 1
      }
      this.triggerEvent('myevent', params)
    }
  },
  
  // 数据监听
  observers: {
    'currentId': function(currentId) {
      console.log(currentId); // 456
    }
  }
})

.json

{
  "component": true,
  "usingComponents": {}
}

父组件:

.wxml

<picture-view url="{{childUrl}}" bind:myevent="onMyEvent"></picture-view>

.js

// index.js
Page({
  data: {
    childUrl: '../../assets/images/图层-1.jpg'
  },
  // 组件自定义事件
  onMyEvent(e) {
    console.log(e.detail); // e.detail 传入的参数
  }
})

.json

{
  "navigationBarTitleText": "首页",
  "usingComponents": {
    "picture-view": "../../components/picture-view/index"
  }
}