自定义view里调用onkeydown_微信小程序(3)- 自定义组件

小程序最开始是不支持组件化开发的,支持组件化开发和npm后我觉得用原生开发会更舒服,毕竟坑少,就算有的话也有人踩过。

自定义组件和vue的组件类似,用法略有不同,其实pages里的页面也可以看作是自定义组件。但是位置不一样,所以作用和叫法也不同。一一介绍自定义组件。


1、组件模板和样式

类似于页面,自定义组件拥有自己的 wxml 模板和 wxss 样式。

组件模板

组件模板的写法与页面模板相同。组件模板与组件数据结合后生成的节点树,将被插入到组件的引用位置上。

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

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

向组件传递数据,绑定一个key:value。在组件js的properties里获取。

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


<!-- 组件 js -->
Component({
 properties: {
  propA: String //数据类型
 }
})
// 组件的属性 propA 和 propB 将收到页面传递的数据。页面可以通过 setData 来改变绑定的数据字段。

组件 wxml 的 slot

在组件的 wxml 中可以包含 slot 节点,用于承载组件使用者提供的 wxml 结构。

默认情况下,一个组件的 wxml 中只能有一个 slot 。需要使用多 slot 时,可以在组件 js 中声明启用。

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

此时,可以在这个组件的 wxml 中使用多个 slot ,以不同的name来区分。

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

使用时,用slot属性来将节点插入到不同的 slot 上。

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

组件样式

组件对应 wxss 文件的样式,只对组件wxml内的节点生效。编写组件样式时,需要注意以下几点:

  • 组件和引用组件的页面不能使用id选择器(#a)、属性选择器([a])和标签名选择器,请改用class选择器。
  • 组件和引用组件的页面中使用后代选择器(.a .b)在一些极端情况下会有非预期的表现,如遇,请避免使用。
  • 子元素选择器(.a>.b)只能用于 view 组件与其子节点之间,用于其他组件可能导致非预期的情况。
  • 继承样式,如 fontcolor ,会从组件外继承到组件内。
  • 除继承样式外, app.wxss 中的样式、组件所在页面的的样式对自定义组件无效(除非更改组件样式隔离选项)。

除此以外,组件可以指定它所在节点的默认样式,使用:host选择器

/* 组件 custom-component.wxss */
:host {
  color: yellow;
}

组件样式隔离

默认情况下,自定义组件的样式只受到自定义组件 wxss 的影响。除非以下两种情况:

  • app.wxss 或页面的 wxss 中使用了标签名选择器(或一些其他特殊选择器)来直接指定样式,这些选择器会影响到页面和全部组件。通常情况下这是不推荐的做法。
  • 指定特殊的样式隔离选项 styleIsolation

styleIsolation 选项从基础库版本 2.6.5 开始支持。它支持以下取值:

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

外部样式类

有时,组件希望接受外部传入的样式类。此时可以在 Component 中用 externalClasses 定义段定义若干个外部样式类。

这个特性可以用于实现类似于 view 组件的 hover-class 属性:页面可以提供一个样式类,赋予 viewhover-class ,这个样式类本身写在页面中而非 view 组件的实现中。

注意:在同一个节点上使用普通样式类和外部样式类时,两个类的优先级是未定义的,因此最好避免这种情况。

代码示例:

/* 组件 custom-component.js */
Component({
  externalClasses: ['my-class']
})
<!-- 组件 custom-component.wxml -->
<custom-component class="my-class">这段文本的颜色由组件外的 class 决定</custom-component>

引用页面或父组件的样式

即使启用了样式隔离 isolated ,组件仍然可以在局部引用组件所在页面的样式或父组件的样式。

例如,如果在页面 wxss 中定义了:

.blue-text { color: blue; }

在这个组件中可以使用 ~ 来引用这个类的样式:

<view class="~blue-text"> 这段文本是蓝色的 </view>

如果在一个组件的父组件 wxss 中定义了:

.red-text { color: red; }

在这个组件中可以使用 ^ 来引用这个类的样式:

<view class="^red-text"> 这段文本是红色的 </view>

也可以连续使用多个 ^ 来引用祖先组件中的样式。

注意:如果组件是比较独立、通用的组件,请优先使用外部样式类的方式,而非直接引用父组件或页面的样式。

虚拟化组件节点

默认情况下,自定义组件本身的那个节点是一个“普通”的节点,使用时可以在这个节点上设置 class style 、动画、 flex 布局等,就如同普通的 view 组件节点一样。

<!-- 页面的 WXML --> <view style="display: flex"> <!-- 默认情况下,这是一个普通的节点 --> <custom-component style="color: blue; flex: 1">蓝色、满宽的</custom-component> </view>

但有些时候,自定义组件并不希望这个节点本身可以设置样式、响应 flex 布局等,而是希望自定义组件内部的第一层节点能够响应 flex 布局或者样式由自定义组件本身完全决定。

这种情况下,可以将这个自定义组件设置为“虚拟的”:

Component({   
    options: {     
virtualHost: true 
},   
properties: {     
style: { // 定义 style 属性可以拿到 style 属性上设置的值       
type: String, 
} 
},   
externalClass: ['class'], 
// 可以将 class 设为 externalClass })

这样,可以将 flex 放入自定义组件内:

<!-- 页面的 WXML --> <view style="display: flex"> <!-- 如果设置了 virtualHost ,节点上的样式将失效 --> <custom-component style="color: blue">不是蓝色的</custom-component> </view>


<!-- custom-component.wxml --> <view style="flex: 1">   满宽的   <slot></slot> </view>

需要注意的是,自定义组件节点上的 class style 和动画将不再生效,但仍可以:

  • 将 style 定义成 properties 属性来获取 style 上设置的值;
  • 将 class 定义成 externalClasses 外部样式类使得自定义组件 wxml 可以使用 class 值。

2、Component 构造器

Component构造器可用于定义组件,调用Component构造器时可以指定组件的属性、数据、方法等。

Component({

  behaviors: [],

  properties: {
    myProperty: { // 属性名
      type: String,
      value: ''
    },
    myProperty2: String // 简化的定义方式
  },
  
  data: {}, // 私有数据,可用于模板渲染

  lifetimes: {
    // 生命周期函数,可以为函数,或一个在methods段中定义的方法名
    attached: function () { },
    moved: function () { },
    detached: function () { },
  },

  // 生命周期函数,可以为函数,或一个在methods段中定义的方法名
  attached: function () { }, // 此处attached的声明会被lifetimes字段中的声明覆盖
  ready: function() { },

  pageLifetimes: {
    // 组件所在页面的生命周期函数
    show: function () { },
    hide: function () { },
    resize: function () { },
  },

  methods: {
    onMyButtonTap: function(){
      this.setData({
        // 更新属性和数据的方法与更新页面数据的方法类似
      })
    },
    // 内部方法建议以下划线开头
    _myPrivateMethod: function(){
      // 这里将 data.A[0].B 设为 'myPrivateData'
      this.setData({
        'A[0].B': 'myPrivateData'
      })
    },
    _propertyChange: function(newVal, oldVal) {

    }
  }

})

使用 Component 构造器构造页面

事实上,小程序的页面也可以视为自定义组件。因而,页面也可以使用 Component 构造器构造,拥有与普通组件一样的定义段与实例方法。但此时要求对应 json 文件中包含 usingComponents 定义段。

此时,组件的属性可以用于接收页面的参数,如访问页面 /pages/index/index?paramA=123&paramB=xyz ,如果声明有属性 paramAparamB ,则它们会被赋值为 123xyz

页面的生命周期方法(即 on 开头的方法),应写在 methods 定义段中。

Component({

  properties: {
    paramA: Number,
    paramB: String,
  },

  methods: {
    onLoad: function() {
      this.data.paramA // 页面参数 paramA 的值
      this.data.paramB // 页面参数 paramB 的值
    }
  }

})

使用 Component 构造器来构造页面的一个好处是可以使用 behaviors 来提取所有页面中公用的代码段。

例如,在所有页面被创建和销毁时都要执行同一段代码,就可以把这段代码提取到 behaviors 中。

代码示例:

// page-common-behavior.js
module.exports = Behavior({
  attached: function() {
    // 页面创建时执行
    console.info('Page loaded!')
  },
  detached: function() {
    // 页面销毁时执行
    console.info('Page unloaded!')
  }
})
// 页面 A
var pageCommonBehavior = require('./page-common-behavior')
Component({
  behaviors: [pageCommonBehavior],
  data: { /* ... */ },
  methods: { /* ... */ },
})
// 页面 B
var pageCommonBehavior = require('./page-common-behavior')
Component({
  behaviors: [pageCommonBehavior],
  data: { /* ... */ },
  methods: { /* ... */ },
})

3、组件间通信与事件

组件间通信

组件间的基本通信方式有以下几种。

  • WXML 数据绑定:用于父组件向子组件的指定属性设置数据,仅能设置 JSON 兼容数据。
  • 事件:用于子组件向父组件传递数据,可以传递任意数据。
  • 如果以上两种方式不足以满足需要,父组件还可以通过 this.selectComponent 方法获取子组件实例对象,这样就可以直接访问组件的任意数据和方法。

监听事件

事件系统是组件间通信的主要方式之一。自定义组件可以触发任意的事件,引用组件的页面可以监听这些事件。关于事件的基本概念和用法,参见 事件 。

代码示例:

<!-- 当自定义组件触发“myevent”事件时,调用“onMyEvent”方法 -->
<component-tag-name bindmyevent="onMyEvent" />
<!-- 或者可以写成 -->
<component-tag-name bind:myevent="onMyEvent" />
Page({
  onMyEvent: function(e){
    e.detail // 自定义组件触发事件时提供的detail对象
  }
})

触发事件

自定义组件触发事件时,需要使用 triggerEvent 方法,指定事件名、detail对象和事件选项:

代码示例:

<!-- 在自定义组件中 -->
<button bindtap="onTap">点击这个按钮将触发“myevent”事件</button>
Component({
  properties: {},
  methods: {
    onTap: function(){
      var myEventDetail = {} // detail对象,提供给事件监听函数
      var myEventOption = {} // 触发事件的选项
      this.triggerEvent('myevent', myEventDetail, myEventOption)
    }
  }

d7bba81d5521b17d5c790c6fcfbb52d3.png

获取组件实例

可在父组件里调用 this.selectComponent ,获取子组件的实例对象。(插件的自定义组件将返回 null

调用时需要传入一个匹配选择器 selector,如:this.selectComponent(".my-component")

代码示例:

// 父组件
Page({
  data: {},
  getChildComponent: function () {
    const child = this.selectComponent('.my-component');
    console.log(child)
  }
})

在上例中,父组件将会获取 classmy-component 的子组件实例对象,即子组件的 this

若需要自定义 selectComponent 返回的数据,可使用内置 behavior: wx://component-export

// 自定义组件 my-component 内部
Component({
  behaviors: ['wx://component-export'],
  export() {
    return { myField: 'myValue' }
  }
}) 
<!-- 使用自定义组件时 -->
<my-component id="the-id" />

// 父组件调用
const child = this.selectComponent('#the-id') // 等于 { myField: 'myValue' }

在上例中,父组件获取idthe-id的子组件实例的时候,得到的是对象{ myField: 'myValue' }


4、组件生命周期

组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。

其中,最重要的生命周期是 created attached detached ,包含一个组件实例生命流程的最主要时间点。

  • 组件实例刚刚被创建好时, created 生命周期被触发。此时,组件数据 this.data 就是在 Component 构造器中定义的数据 data此时还不能调用 setData 通常情况下,这个生命周期只应该用于给组件 this 添加一些自定义属性字段。
  • 在组件完全初始化完毕、进入页面节点树后, attached 生命周期被触发。此时, this.data 已被初始化为组件的当前值。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。
  • 在组件离开页面节点树后, detached 生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则 detached 会被触发。
Component({
  lifetimes: {
    attached: function() {
      // 在组件实例进入页面节点树时执行
    },
    detached: function() {
      // 在组件实例被从页面节点树移除时执行
    },
  },
  // 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
  attached: function() {
    // 在组件实例进入页面节点树时执行
  },
  detached: function() {
    // 在组件实例被从页面节点树移除时执行
  },
  // ...
})

在 behaviors 中也可以编写生命周期方法,同时不会与其他 behaviors 中的同名生命周期相互覆盖。但要注意,如果一个组件多次直接或间接引用同一个 behavior ,这个 behavior 中的生命周期函数在一个执行时机内只会执行一次。

可用的全部生命周期如下表所示。

ff3f5235e7320ff1c631c0333edf68c3.png

组件所在页面的生命周期

还有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。这样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes 定义段中定义。其中可用的生命周期包括:

0e60924a0b2fbcfcf25061ae532a33d8.png
Component({
  pageLifetimes: {
    show: function() {
      // 页面被展示
    },
    hide: function() {
      // 页面被隐藏
    },
    resize: function(size) {
      // 页面尺寸变化
    }
  }
})

这块的东西太细了,基本了解知道了这四块写项目就没啥问题了。

如果有一些特殊需求,可以再来自定义组件这边看一下文档。

我看可以出视频了,以后就可以用视频记录了 哈哈哈哈

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值