wepy 小程序开发(组件)

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 {
}
  1. App小程序实例中主要包含config配置对象globalData全局数据对象小程序生命周期函数、以及其余自定义方法与属性
  2. 在Page页面实例中,能够经过this.$parent来访问App实例。
  3. 因为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中的习惯不一样。

 

计算属性:promise

data = {
      a: 1
  }

  // 计算属性aPlus,在脚本中可经过this.aPlus来引用,在模板中可经过{{ aPlus }}来插值
  computed = {
      aPlus () {
          return this.a + 1
      }
  }

 

props传值:app

父子组件之间传值的一种机制,包括静态传值与动态传值。异步

1.静态传值模块化

静态传值为父组件向子组件传递常量数据,所以只能传递String字符串类型函数

2.动态传值组件化

动态传值是指父组件向子组件传递动态数据内容,父子组件数据彻底独立互不干扰。但能够经过使用.sync修饰符来达到父组件数据绑定至子组件的效果,也能够经过设置子组件props的twoWay: true来达到子组件数据绑定至父组件的效果。那若是既使用.sync修饰符,同时子组件props中添加的twoWay: true时,就能够实现数据的双向绑定了。this

  • 注意:下文示例中的twoWaytrue时,表示子组件向父组件单向动态传值,而twoWayfalse(默认值,可不写)时,则表示子组件不向父组件传值。这是与Vue不一致的地方。

//parent.wpyspa

<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>