import wepy from 'wepy'; // 声明一个App小程序实例 export default class MyAPP extends wepy.app { } // 声明一个Page页面实例 export default class IndexPage extends wepy.page { } // 声明一个Component组件实例 export default class MyComponent extends wepy.component { }
- App小程序实例中主要包含config配置对象、globalData全局数据对象,小程序生命周期函数、以及其他自定义方法与属性。
- 在Page页面实例中,可以通过
this.$parent
来访问App实例。 - 由于Page页面实际上继承自Component组件。除扩展了页面所特有的
config
配置以及特有的页面生命周期函数之外,其它属性和方法与Component一致。
组件
- 注意:WePY中的methods属性只能声明页面wxml标签的bind、catch事件,不能声明自定义方法,这与Vue中的用法是不一致的。
- 原生小程序支持js模块化,无法实现组件化的松耦合与复用的效果。WePY中实现了小程序的组件化开发,组件的所有业务与功能在组件本身实现。
- WePY中的组件都是静态组件,是以组件ID作为唯一标识的,每一个ID都对应一个组件实例,当页面引入两个相同ID的组件时,这两个组件共用同一个实例与数据,当其中一个组件数据变化时,另外一个也会一起变化。避免这个问题,则需要分配多个组件ID和实例。
<template> <view class="child1"> <child></child> </view> <view class="child2"> <anotherchild></anotherchild> </view> </template> <script> import wepy from 'wepy'; import Child from '../components/child'; export default class Index extends wepy.page { components = { //为两个相同组件的不同实例分配不同的组件ID,从而避免数据同步变化的问题 child: Child, anotherchild: Child }; } </script>
- 注意:在WePY中,不能将驼峰式命名转换成短横杆式命名(比如将
childCom
转换成child-com
),与Vue中的习惯不同。
计算属性:
data = { a: 1 } // 计算属性aPlus,在脚本中可通过this.aPlus来引用,在模板中可通过{{ aPlus }}来插值 computed = { aPlus () { return this.a + 1 } }
props传值:
父子组件之间传值的一种机制,包括静态传值与动态传值。
1.静态传值
静态传值为父组件向子组件传递常量数据,因此只能传递String字符串类型。
2.动态传值
动态传值是指父组件向子组件传递动态数据内容,父子组件数据完全独立互不干扰。但可以通过使用.sync
修饰符来达到父组件数据绑定至子组件的效果,也可以通过设置子组件props的twoWay: true
来达到子组件数据绑定至父组件的效果。那如果既使用.sync
修饰符,同时子组件props
中添加的twoWay: true
时,就可以实现数据的双向绑定了。
- 注意:下文示例中的
twoWay
为true
时,表示子组件向父组件单向动态传值,而twoWay
为false
(默认值,可不写)时,则表示子组件不向父组件传值。这是与Vue不一致的地方。
//parent.wpy
<child :title="parentTitle" :syncTitle.sync="parentTitle" :twoWayTitle="parentTitle"></child> data = { parentTitle: 'p-title' };
// child.wpy
props = { // 静态传值 title: String, // 父向子单向动态传值 syncTitle: { type: String, default: 'null' }, twoWayTitle: { type: String, default: 'nothing', twoWay: true } }; onLoad () { console.log(this.title); // p-title console.log(this.syncTitle); // p-title console.log(this.twoWayTitle); // p-title this.title = 'c-title'; console.log(this.$parent.parentTitle); // p-title. this.twoWayTitle = 'two-way-title'; this.$apply(); console.log(this.$parent.parentTitle); // two-way-title. --- twoWay为true时,子组件props中的属性值改变时,会同时改变父组件对应的值 this.$parent.parentTitle = 'p-title-changed'; this.$parent.$apply(); console.log(this.title); // 'c-title'; console.log(this.syncTitle); // 'p-title-changed' --- 有.sync修饰符的props属性值,当在父组件中改变时,会同时改变子组件对应的值。 }
组件通信与交互
wepy.component
基类提供$broadcast
、$emit
、$invoke
三个方法用于组件之间的通信和交互。
this.$emit('some-event', 1, 2, 3, 4);
用于监听组件之间的通信与交互事件的事件处理函数需要写在组件和页面的events
对象中:
import wepy from 'wepy' export default class Com extends wepy.component { components = {}; data = {}; methods = {}; // events对象中所声明的函数为用于监听组件之间的通信与交互事件的事件处理函数 events = { 'some-event': (p1, p2, p3, $event) => { console.log(`${this.$name} receive ${$event.name} from ${$event.source.$name}`); } }; // Other properties }
$broadcast
$broadcast
事件是由父组件发起,所有子组件都会收到此广播事件,除非事件被手动取消。事件广播的顺序为广度优先搜索顺序。如果页面Page_Index
发起一个$broadcast
事件,那么按先后顺序依次接收到该事件的组件为:ComA、ComB、ComC、ComD、ComE、ComF、ComG、ComH。如下图:
$emit
$emit
与$broadcast
正好相反,事件发起组件的所有祖先组件会依次接收到$emit
事件。如果组件ComE发起一个$emit
事件,那么接收到事件的先后顺序为:组件ComA、页面Page_Index。如下图:
$invoke
$invoke
是一个页面或组件对另一个组件中的方法的直接调用,通过传入组件路径找到相应的组件,然后再调用其方法。
比如,想在页面Page_Index
中调用组件ComA的某个方法:(该事件只传给ComA,而不是广播)
this.$invoke('ComA', 'someMethod', 'someArgs');
如果想在组件ComA中调用组件ComG的某个方法:(不存在父子关系的两个组件)
this.$invoke('./../ComB/ComG', 'someMethod', 'someArgs');
$apply : 组件发起脏检查。
正常流程下,改变数据后,组件会在流程结束时自动触发脏检查。 在异步或者回调流程中改变数据时,需要手动调用$apply
方法。
this.userName = 'Gcaufy'; this.$apply();
$nextTick: 组件数据绑定完成后的回调事件。在不传入function时,返回一个promise对象。
this.userName = 'Gcaufy'; this.$nextTick(function () { console.log('UI updated'); });
this.userName = 'Gcaufy'; this.$nextTick().then(function () { console.log('UI updated'); });
自定义事件处理函数
可以通过使用.user
修饰符为自定义组件绑定事件,如:@customEvent.user="myFn"
其中,@
表示事件修饰符,customEvent
表示事件名称,.user
表示事件后缀。
目前总共有三种事件后缀:
-
.default
: 绑定小程序冒泡型事件,如bindtap
(.default
后缀可省略不写); -
.stop
: 绑定小程序捕获型事件,如catchtap
; -
.user
: 绑定用户自定义组件事件,通过$emit
触发。注意,如果用了自定义事件,则events中对应的监听函数不会再执行。 -
// index.wpy <template> <child @childFn.user="parentFn"></child> </template> <script> import wepy from 'wepy' import Child from '../components/child' export default class Index extends wepy.page { components = { child: Child } methods = { parentFn (num, evt) { console.log('parent received emit event, number is: ' + num) } } } </script>
// child.wpy <template> <view @tap="tap">Click me</view> </template> <script> import wepy from 'wepy' export default class Child extends wepy.component { methods = { tap () { console.log('child is clicked') this.$emit('childFn', 100) } } } </script>
slot组件内容分发插槽
首先在子组件template
模板部分中声明slot
标签作为内容插槽,同时必须在其name
属性中指定插槽名称,还可设置默认的标签内容;然后在引入了该带有插槽的子组件的父组件template
模板部分中声明用于“插拔”的内容分发标签。这些父组件中的内容分发标签必须具有slot
属性,并且其值为子组件中对应的插槽名称name。
- 注意:父组件中一旦声明了对应于子组件插槽的内容分发标签,即便没有内容,子组件插槽中的默认内容也不会显示出来,只有删除了父组件中对应的内容分发标签,才能显示出来。
子组件
<view class="panel"> <slot name="title">默认标题</slot> <slot name="content">默认内容</slot> </view>
父组件
<panel> <view slot="title">新的标题</view> <view slot="content"> <text>新的内容</text> </view>