zhaobinglong / myBlog

https://zhaobinglong.github.io/myBlog/
MIT License
7 stars 0 forks source link

微信小程序之组件化 #109

Open zhaobinglong opened 3 years ago

zhaobinglong commented 3 years ago

新建自定义组件

类似于页面,一个自定义组件由 json wxml wxss js 4个文件组成。要编写一个自定义组件,首先需要在 json 文件中进行自定义组件声明(将 component 字段设为 true 可将这一组文件设为自定义组件)

// xx.json
{
  "component": true
}

// xx.js, 使用 Component() 来注册组件,并提供组件的属性定义、内部数据和自定义方法。
Component({
  properties: {
    // 这里定义了innerText属性,属性值可以在组件使用时指定
    innerText: {
      type: String,
      value: 'default value',
    }
  },
  data: {
    // 这里是一些组件内部数据
    someData: {}
  },
  methods: {
    // 这里是一个自定义方法
    customMethod: function(){}
  }
})
zhaobinglong commented 3 years ago

组件结合slot

在组件模板中可以提供一个 节点,用于承载组件引用时提供的子节点。

<!-- 组件模板 -->
<view class="wrapper">
  <view>这里是组件的内部节点</view>
  <slot></slot>
</view>

<!-- 引用组件的页面模板 -->
<view>
  <component-tag-name>
    <!-- 这部分内容将被放置在组件 <slot> 的位置上 -->
    <view>这里是插入到组件slot中的内容</view>
  </component-tag-name>
</view>

开启支持多个slot

Component({
  options: {
    multipleSlots: true // 在组件定义时的选项中启用多slot支持
  },
  properties: { /* ... */ },
  methods: { /* ... */ }
})

<!-- 组件模板 -->
<view class="wrapper">
  <slot name="before"></slot>
  <view>这里是组件的内部细节</view>
  <slot name="after"></slot>
</view>
zhaobinglong commented 3 years ago

组件与页面的样式隔离

Component({
  options: {
    styleIsolation: 'isolated'
  }
})

isolated 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(一般情况下的默认值); apply-shared 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面; shared 表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件。(这个选项在插件中不可用。)

zhaobinglong commented 3 years ago

子组件和父组件通信

<!-- 在自定义组件中 -->
<button bindtap="onTap">点击这个按钮将触发“myevent”事件</button>

Component({
  properties: {},
  methods: {
    onTap: function(){
      var myEventDetail = {} // detail对象,提供给事件监听函数
      var myEventOption = {} // 触发事件的选项
      this.triggerEvent('myevent', myEventDetail, myEventOption)
    }
  }
})

父组件和子组件通信

// 父组件
Page({
  data: {},
  getChildComponent: function () {
    // 父组件获取到子组件的实例,可以调用子组件的数据和方法
    const child = this.selectComponent('.my-component');
    console.log(child)
  }
})
zhaobinglong commented 3 years ago

组件自己的生命周期

Component({
  // 组件的实例有六个生命周期函数
  lifetimes: {
    attached: function() {
      // 在组件实例进入页面节点树时执行
    },
    detached: function() {
      // 在组件实例被从页面节点树移除时执行
    },
    ready
    moved
    detached
    error
  },

组件内部感知页面的生命周期

Component({
  pageLifetimes: {
    show: function() {
      // 页面被展示
    },
    hide: function() {
      // 页面被隐藏
    },
    resize: function(size) {
      // 页面尺寸变化
    }
  }
})
zhaobinglong commented 3 years ago

behaviors(Vue中的mixin)

// my-behavior.js
module.exports = Behavior({
  behaviors: [],
  properties: {
    myBehaviorProperty: {
      type: String
    }
  },
  data: {
    myBehaviorData: {}
  },
  attached: function(){},
  methods: {
    myBehaviorMethod: function(){}
  }
})

// 组件中使用
var myBehavior = require('my-behavior')
Component({
  behaviors: [myBehavior],
zhaobinglong commented 3 years ago

数据监听器observers(Vue中的watch)

Component({
  attached: function() {
    this.setData({
      numberA: 1,
      numberB: 2,
    })
  },
  observers: {
    'numberA, numberB': function(numberA, numberB) {
      // 在 numberA 或者 numberB 被设置时,执行这个函数
      this.setData({
        sum: numberA + numberB
      })
    }
  }
})
在开发者工具中预览效果
zhaobinglong commented 3 years ago

组件的单元测试

现在市面上流行的测试框架均可使用,只要它能兼顾 nodejs 端和 dom 环境。因为我们需要依赖到 nodejs 的一些库来完善测试环境,同时 dom 环境也是必须的,因为我们需要建成完整的 dom 树结构,才能更好的模拟自定义组件的运行。例如可以选用 mocha + jsdom 的组合,亦可选用 jest

小程序的运行环境比较特殊,不同于常见的浏览器环境,它采用的是双线程的架构。而在进行单元测试时,我们并不需要用到这样复杂的架构带来的利好,我们进行的是功能测试而无需苛求性能、安全等因素,因此我们提供了一个测试工具集以支持自定义组件在 nodejs 单线程中也能运行起来。

npm i --save-dev miniprogram-simulate

// /test/components/index.test.js
const simulate = require('miniprogram-simulate')

test('components/index', () => {
    const id = simulate.load('/components/index') // 此处必须传入绝对路径
    const comp = simulate.render(id) // 渲染成自定义组件树实例

    const parent = document.createElement('parent-wrapper') // 创建父亲节点
    comp.attach(parent) // attach 到父亲节点上,此时会触发自定义组件的 attached 钩子

    const view = comp.querySelector('.index') // 获取子组件 view
    expect(view.dom.innerHTML).toBe('index.properties') // 测试渲染结果
    expect(window.getComputedStyle(view.dom).color).toBe('green') // 测试渲染结果
})

参考

https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/unit-test.html