快速入门
1,项目创建和使用
安装wepy,一下都是通过npm安装
npm install wepy-cli -g
2,在开发目录生成开发DEMO。
wepy new project
3,开发实时编译
wepy build --watch
4,项目目录结构
dist
node_modules
src
components
com_a.wpy
com_b.wpy
pages
index.wpy
page2.wpy
app.wpy
package.json
5,开发使用说明
第一,使用微信开发者工具新建项目,本地开发选择dist目录
第二,微信开发者工具-->项目-->关闭ES6转ES5
第三,本地项目根目录运行,wepy build --watch ,开启实时编译
6,代码规范
第一,变量和方法命名尽量使用驼峰式命名,避免使用$开头,以$开头的变量和方法为框架内部变量和方法,可以使用,使用前请参考【API文档】
第二,入口,页面,组件的命名后缀为.wpy,外联的文件可以是其他后缀。
第三,使用ES6语法开发,框架在ES6下开发,因此需要使用ES6开发小程序,ES6中有许多的语法糖,可以使我们的代码更加的简洁高效。
第四,使用Promise,框架默认对小程序提供的API进行了Promise处理,甚至可以直接使用async/await等新特性进行开发
7,主要解决问题
第一,开发模式转换,对原有的小程序开发模式进行封装,更贴近MVVM框架开发模式,框架在开发过程中参考了一些现在的框架的特性,并且融入其中,一下是使用wepy前后的demo对比图
官方DEMO代码:
//index.js
//获取应用实例
var app = getApp()
Page({
data: {
motto: 'Hello World',
userInfo: {}
},
//事件处理函数
bindViewTap: function() {
console.log('button clicked')
},
onLoad: function () {
console.log('onLoad')
}
})
基于wepy的实现:
import wepy from 'wepy';
export default class Index extends wepy.page {
data = {
motto: 'Hello World',单文件userInfo: {}
};
methods = {
bindViewTap () {
console.log('button clicked');
}
};
onLoad() {
console.log('onLoad');
};
}
第二,支持组件化的开发。
第三,支持加载外部npm包,在编译过程中,会递归的遍历代码中的require,然后将相应的依赖从node_modules中拷贝出来,并修改require为相对路径,从而实现对外部npm包的支。
第四,单文件模式,使得目录结构更加清晰。官方目录结构要求app必须有三个文件:app.json,app.js,app.wxss;页面有四个文件,index.json,index.js, index.wxml,index.wxss,而且文件必须同名
8,默认使用babel编译,支持ES6/7的一些新特性。用户可以通过wepyrc配置文件,配置自己熟悉的babel环境进行开发,默认开启使用了一些新的
特性,比如Promise,async/await等等。
9,针对原生API进行优化。对现在API进行promise处理,同时修复一些现有API的缺陷,比如wx.request并发问题。
原有代码
onLoad = function () {
var self = this;
wx.login({
success: function (data) {
wx.getUserInfo({
success: function (userinfo) {
self.setData({userInfo: userinfo});
}
});
}
});
}
使用wepy之后
async onLoad() {
await wx.login();
this.userInfo = await wx.getUserInfo();
}
进阶说明
1,.wepyrc配置文件说明
执行wepy new demo 之后会生成类似配置文件。
{
"wpyExt": ".wpy",
"sass": {},
"less": {},
"babel": {}
}
wpyExt:缺省值为.wpy IDE默认情况下不会对此文件类型高亮,此时可以修改所有文件后缀为.vue(因为与Vue高亮规则一样),然后将次选项修改为.vue,就能解决部分IDE高亮显示问题。
sass:sass编译配置,参见这里。
less:less编译配置,参见这里。
babel:babel编译配置,参见这里。
wpy文件说明
1,wpy文件的编译过程
一个.wpy文件分为三部分。
样式:<style></style>对应原有的wxss
模板:<template></template>对应原有的wxml
代码:<script></script>对应原有的js
其中入口文件app.wpy不需要template。所以编译时会被忽略。这三个标签都支持type和src属性,type决定了其代码编译过程,src决定是否外联代码,存在src属性且有效时,忽略内联代码。示例代码如下:
<style type="less" src="page1.less"></style>
<template type="wxml" src="page1.wxml"></template>
<script>
// some code
</script>
标签对应 type
值如下表所示:
标签 | type默认值 | type支持值 |
---|---|---|
style | css | css ,less ,sass(待完成) |
template | wxml | wxml ,xml ,html(待完成) |
script | js | js ,TypeScript(待完成) |
script说明
程序入口app.wpy
<style type="less">
/** less **/
</style>
<script>
import wepy from 'wepy';
export default class extends wepy.app {
config = {
"pages":[
"pages/index/index"
],
"window":{
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle": "black"
}
};
onLaunch() {
console.log(this);
}
}
</script>
入口app.wpy继承自wepy.app,其中包括一个config属性个全局属性,方法和事件。其中config属性对应原有的app.json,编译时会根据config属性生成app.json,如果需要修改config中的内容,请使用系统提供的api。
页面index.wpy
<style type="less">
/** less **/
</style>
<template type="wxml">
<view>
</view>
<component id="counter1" path="counter"></component>
</template>
<script>
import wepy form 'wepy';
import Counter from '../components/counter';
export default class Index extends wepy.page {
config = {};
components = {counter1: Counter};
data = {};
methods = {};
events = {};
onLoad() {};
// Other properties
}
</script>
页面入口继承自wepy.page,主要属性说明如下。
属性 | 说明 |
---|---|
config | 页面config,相当于原来的index.json,同app.wpy 中的config |
components | 页面引入的组件列表 |
data | 页面需要渲染的数据 |
methods | wmxl的事件捕捉,如bindtap ,bindchange |
events | 组件之间通过broadcast ,emit 传递的事件 |
其它 | 如onLoad ,onReady 等小程序事件以及其它自定义方法与属性 |
组件com.wpy
<style type="less">
/** less **/
</style>
<template type="wxml">
<view> </view>
</template>
<script>
import wepy form 'wepy';
export default class Com extends wepy.component {
components = {};
data = {};
methods = {};
events = {};
// Other properties
}
</script>
组件入口继承自wepy.conponent,属性与页面属性一样,除了不需要config和一些页面特有的小程序事件。
组件
小程序支持js模块化引用,也支持wxml模板,但彼此独立,业务代码与交互事件仍然需要在页面处理,无法实现组件化的松耦合和复用效果。
组件引用,
当页面或者组件需要引入子组件时,需要在页面或者script中的components给组件分配唯一id,并且在template中添加<component>标签,
组件交互
wepy.component基类包括三个方法,$broadcast,$emit,$invoke。因此,任一页面或者任一组件都可以调用上述方法实现通信与交互。如:
$this.$emit('some-event', 1, 2, 3, 4);
组件的事件监听需要放在events属性下,如:
import wepy form 'wepy';
export default class Com extends wepy.component {
components = {};
data = {};
methods = {};
events = {
'some-event': ($event, ...args) {
console.log(`${this.name} receive ${$event.name} from ${$event.source.name}`);
}
};
// Other properties
}
1,$broadcast
$broadcast是由父组件发起,所有子组件都会受到此广播事件,除非事件被手动取消。事件广播的顺序为广度优先搜索顺序,如上图,如果Page_Index
发起一个$broadcast
事件,那么接收到事件的先后顺序为:A, B, C, D, E, F, G, H。如下图:
2,$emit
$emit与$broadcast正好相反。事件发起组件的父组件会一次接收到$emit事件。如上图,如果E发起一个$emit
事件,那么接收到事件的先后顺序为:A, Page_Index。如下图:
3,$invoke
$invoke是一个组件对另一个组件的直接调用,通过传入组件路径找到相应组件。然后在调用其方法。如果想在page_Index中,调用组件A的相关方法,this.$invoke('comA', 'someMethod', 'someArgs'),如果想在组件A中调用组件G的某个方法:this.$invoke('./../ComB/ComG', 'someMethod', 'someArgs');
数据绑定
小程序通过page提供的setData方法去绑定数据,如:this.setData({title:'this is title'}); 由于小程序架构问题,页面渲染和js逻辑层分开,所以setData操作就是js逻辑层和页面渲染层的通信,那么在同一运行周期内多次执行setData操作,那么通信的次数一一次还是多次?这取决于API本身的设计。
wepy数据绑定方式
wepy使用脏数据检查对setData进行封装,在函数运行周期结束时执行脏数据检查,一来可以不用关心页面多次setData是否会有性能上的问题,二来可以更加简洁的去修改数据,实现绑定。不用重复去写setData方法。代码如下:
this.title = 'this is title';
但需注意,在函数运行周期之外的函数里去修改数据需要手动调用
$apply
方法。如:
setTimeout(() => {
this.title = 'this is title';
this.$apply();
}, 3000);
其它优化细节
1,wx.repuire接受参数的修改
点这里查看官方文档
// 官方
wx.request({
url: 'xxx',
success: function (data) {
console.log(data);
}
});
// wepy 使用方式
// request 接口从只接收Object变为可接收String
wx.request('xxxx').then((d) => console.log(d));
2,优化事件传递参数
// 官方
<view id="tapTest" data-hi="WeChat" bindtap="tapName"> Click me! </view>
Page({
tapName: function(event) {
console.log(event.currentTarget.hi)// output: WeChat
}
});
// wepy 建议传参方式
<view id="tapTest" data-wepy-params="1-wepy-something" bindtap="tapName"> Click me! </view>
events: {
tapName (event, id, title, other) {
console.log(id, title, other)// output: 1, wepy, something
}
}
3,改变数据绑定方式
保留setData方法,但不建议使用setData执行绑定,字符传入undefined的bug,并且修改入参支持。
this.setData(target, value);
this.setData(object)
// 官方
<view> {{ message }} </view>
onLoad: function () {
this.setData({message: 'hello world'});
}
// wepy
<view> {{ message }} </view>
onLoad () {
this.message = 'hello world';
}
4,组件代替模板和模块,
// 官方
<!-- item.wxml -->
<template name="item">
<text>{{text}}</text>
</template>
<!-- index.wxml -->
<import src="item.wxml"/>
<template is="item" data="{{text: 'forbar'}}"/>
<!-- index.js -->
var item = require('item.js')
// wepy
<!-- /components/item.wpy -->
<text>{{text}}</text>
<!-- index.wpy -->
<template>
<component id="item"></component>
</template>
<script>
import wepy from 'wepy';
import Item from '../components/item';
export default class Index extends wepy.page {
components = { Item }
}
</script>
API
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
name | String | - | 事件名称 |
source | wepy.component | - | 事件来源 |
type | String | - | emit 或者 broadcast |
方法 | 参数 | 返回值 | 说明 |
---|---|---|---|
destroy | - | - | 在 emit 或者 broadcast 过程中,调用destroy方法将会停止事件传播。 |
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
isComponent | Boolean | true | 是否是组件,如果是页面,此值为false |
prefix | String | '' | 组件前缀,组件前缀+组件方法属性才是在小程序中真实存在的方法或属性。 |
$root | wepy.page | - | 根组件,一般都是页面 |
$parent | wepy.component | - | 父组件 |
$wxpage | Page | - | 小程序Page对象 |
$coms | List(wepy.component) | {} | 子组件列表 |
方法 | 参数 | 返回值 | 说明 |
---|---|---|---|
init | - | - | 组件初始化。 |
getWxPage | - | Page | 返回小程序Page对象。 |
$getComponent | path(String) | wepy.component | 通过组件路径返回组件对象。 |
$invoke | com(String/wepy.component), method(String), [args] | - | 调用其它组件方法 |
$broadcast | evtName(String), [args] | - | broadcast事件。 |
$emit | evtName(String), [args] | - | emit事件。 |
$apply | fn(Function) | - | 准备执行脏数据检查。 |
$digest | - | - | 脏检查。 |
wepy.page
方法 | 参数 | 返回值 | 说明 |
---|---|---|---|
init | - | - | 页面始化。 |
wepy.app
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
$wxapp | App | - | 小程序getApp() |
init | - | - | 应用始化包括对原生API的改造与优化 |