微信小程序之:wepy框架

1、介绍

WePY 是 腾讯 参考了Vue 等框架对原生小程序进行再次封装的框架,更贴近于 MVVM 架构模式, 并支持ES6/7的一些新特性。

2、使用

npm install -g wepy-cli //全局安装或更新WePY命令行工具(wepy脚手架): wepy-cli

wepy -v //查看wepy-cli版本

wepy init standard <projectName> //新建wepy小程序项目,1.7.0之前的版本使用:wepy new myproject,安装项目翻译一下即可

wepy list //查看项目模板

cd <projectName> //切换至项目目录

npm install //安装依赖

wepy build --watch //开启实时编译

3、规范

①代码规范

  wepy和原生标签一样

  自定义组件名尽量避开原生组件名、wepy的辅助标签repeat

  方法名、变量名尽量使用驼峰命名

  文件后缀为.wpy

  支持ES6/ES7的一些新特性

  继承了wx对象方法,wepy中没有wx对象,尽量不要用到此方法,打包时容易报错

②数据绑定

//原生小程序
this.setData({xxx:xxx});
//wepy
data={aaa:\'\'}
this.aaa = \'aaa\';
//wepy 在异步函数中更新数据的时候,必须手动调用$apply方法,才会触发脏数据检查流程的运行
this.$apply();

③事件绑定以及时间传参

<view @tap="click"></view> //​​​​​ 原 bindtap="click"(省略了.default后缀 )绑定小程序冒泡型事件
<view @tap.stop="click"></view> //​​​​​ 原catchtap="click"  绑定小程序捕获型事件,如catchtap
<view @tap.capture="click"></view> //​​​​​ 原 capture-bind:tap="click"
<view @tap.capture.stop="click"></view> //​​​​​ 原 capture-catch:tap="click"
<!--事件传参-->
<view @tap="click({{index}})"></view> //​​​​​ 原bindtap="click" data-index={{index}}

④框架默认对小程序的API提供了Promise处理,可以直接调用async/await直接开发

// 原生代码:
wx.request({
    url: \'xxx\',
    success: function (data) {
        console.log(data);
    }
});

// WePY 使用方式, 需要开启 Promise 支持,参考开发规范章节
wepy.request(\'xxxx\').then((d) => console.log(d));

// async/await 的使用方式, 需要开启 Promise 和 async/await 支持,参考 WIKI
async function request () {
   let d = await wepy.request(\'xxxxx\');
   console.log(d);
}
//需要开启Promise的解释
//1、进入项目目录,安装polyfill
npm install wepy-async-function --save
//2、在app.wpy中导入polyfill
import \'wepy-async-function\';
//3、在app.wpy中使用promiss
constructor () { super(); this.use(\'promisify\'); }
//4、判断是否引入成功
onLaunch() {
    console.log(\'on launch\');
    let mypro = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(123);
        }, 2000);
    });
    mypro.then((r)=>{
        console.log(r);
    })
}
//重启编译
//打印出内容即为成功

⑤computed计算属性,类型{ [ key:string ] : function },有返回值,绑定数据使用,

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

⑥watcher监听,类型{ [ key:string ] : function },监听任何属性更新,处理数据专用。

data={ aaa:\'xxx\' };
  // 监听器函数名必须跟需要被监听的data对象中的属性同名,
  // 其参数中的newValue为属性改变后的新值,oldValue为改变前的旧值
// 每当监听属性aaa改变一次,该函数就调用一次 watch={ aaa(newValue,oldValue){ console.log(`data的aaa由${oldValue}变为${newValue}`) } }

⑦wxs

  等待学习

⑧interceptor拦截器

  可以对原生api进行请求拦截,具体方法是配置api的config、fail、success、complete回调函数。

//app.wpy
constructor () {
//在super()是不允许的
    super()
    //拦截request请求
    this.intercept(\'request\',{
        //发出请求时的回调函数
        config(res){
            //对所有请求附加token
            res.token = token;
            return res;
        }    
        //请求成功后的回调函数
        success(res){
            return res;
        }
        //请求失败后的回调函数
        fail(res){
            return res;
        }
        //请求完成后的回调函数
        complete(res){
            return res;
        }
    });
}

4、项目目录结构

原生小程序:app(app.jsapp.jsonapp.wxss),page(page.jspage.jsonpage.wxmlpage.wxss),文件必须同名。

WePY中则使用了单文件模式:app.wpypage.wpy

一个.wpy文件可分为三大部分,各自对应于一个标签:

  1. 脚本<script>部分,又可分为两个部分:

    逻辑部分,除了config对象之外的部分,对应于原生的.js文件

    配置部分,即config对象,对应于原生的.json文件

  1. 结构<template>部分,对应于原生的.wxml文件

  2. 样式<style>部分,对应于原生的.wxss文件

①components组件:

import wepy from \'wepy\';

export default class MyComponent extends wepy.component {
    props = {}//接收父组件传来的参数
    customData = {}  // 自定义数据
    customFunction () {}  //自定义方法
    onLoad () {}  // 在Page和Component共用的生命周期函数
    data = {};  // 页面所需数据均需在这里声明,可用于模板数据绑定
    components = {};  // 声明页面中所引用的组件,或声明组件中所引用的子组件
    mixins = [];  // 声明页面所引用的Mixin实例
    computed = {};  // 声明计算属性(详见后文介绍)
    watch = {};  // 声明数据watcher(详见后文介绍)
    methods = {};  // 声明页面wxml中标签的事件处理函数。注意,此处只用于声明页面wxml中标签的bind、catch事件,自定义方法需以自定义方法的方式声明
    events = {};  // WePY组件事件处理函数对象,存放响应组件之间通过$broadcast、$emit、$invoke所传递的事件的函数
}
/** 与page不同的是component不存在:
    onShow () {}  // 只在Page中存在的页面生命周期函数
    config = {};  // 只在Page实例中存在的配置数据,对应于原生的page.json文件,类似于app.wpy中的config
    onReady() {}  //  只在Page中存在的页面生命周期函数
**/

**无法实现组件化的松耦合与复用

(如,模板A中绑定一个bindtap="myclick",模板B中同样绑定一样bindtap="myclick",那么就会影响同一个页面事件、数据)

  a、引用组件

    

//引入组件文件
import Child from \'../components/child\';
export default class Index extends wepy.component {
    //声明组件,分配组件id为child,需要注意的是,WePY中的组件都是静态组件,是以组件ID作为唯一标识的,
每一个ID都对应一个组件实例,当页面引入两个相同ID的组件时,这两个组件共用同一个实例与数据,当其中一个组件数据变化时,另外一个也会一起变化。 components = { //为两个相同组件的不同实例分配不同的组件ID,从而避免数据同步变化的问题 child: Child, }; }
//在html中使用组件
<child></child>

②页面page.wpy

Page页面实际上继承自Component组件,即Page也是组件。

除扩展了页面所特有的config配置以及特有的页面生命周期函数之外,其它属性和方法与Component一致:

import wepy from \'wepy\';

export default class MyPage extends wepy.page {
    customData = {}  // 自定义数据

    customFunction () {}  //自定义方法

    onLoad () {}  // 在Page和Component共用的生命周期函数

    onUnload() {}  // 监听页面卸载

    onReady() {}  //  只在Page中存在的页面生命周期函数

    onShow () {}  // 只在Page中存在的页面生命周期函数,当小程序启动,或从后台进入前台显示

    onHide() {}  // 只在Page中存在的页面生命周期函数,当小程序从前台进入后台

    config = {};  // 只在Page实例中存在的配置数据,对应于原生的page.json文件,类似于app.wpy中的config

    data = {};  // 页面所需数据均需在这里声明,可用于模板数据绑定

    components = {};  // 声明页面中所引用的组件,或声明组件中所引用的子组件

    mixins = [];  // 声明页面所引用的Mixin实例

    computed = {};  // 声明计算属性

    watch = {};  // 声明数据watcher

    methods = {};  // 声明页面wxml中标签的事件处理函数。注意,此处只用于声明页面wxml中标签的bind、catch事件,自定义方法需以自定义方法的方式声明

    events = {};  // WePY组件事件处理函数对象,存放响应组件之间通过$broadcast、$emit、$invoke所传递的事件的函数

    onPullDownRefresh(){}  // 监听用户下拉动作

    onReachBottom(){}  // 页面上拉触底事件的处理函数

    onShareAppMessage(){}  // 用户点击右上角分享

    onPageScroll(){}  // 页面滚动

    onTabItemTap(){}  //  当前是 tab 页时,点击 tab 时触发 
}

③状态管理store(redux)

④app.wpy:小程序入口

继承自wepy.app类;包含config配置对象、globalData对象、自定方法属性、小程序生命周期函数;

在page页面中可以使用this.$parent调用实例

<script>
import wepy from \'wepy\';
export default class extends wepy.app {
    config = {
        pages:[// pages定义当前小程序所有页面路径,让微信客户端知道当前你的小程序页面定义在哪个目录
            \'pages/index\',
            \'pages/mine\'
        ],
        window:{//window定义小程序所有页面的顶部背景颜色,文字颜色定义等。
            "backgroundTextStyle": "light",
            "navigationBarBackgroundColor": "#fff",
            "navigationBarTitleText": "顶部标题",
            "navigationBarTextStyle": "black"
        },
        tabBar: {
            selectedColor: \'#ea9100\',//底部导航字体选中时的颜色
            list: [
                   {
                     pagePath: \'pages/index\',//导航页面路径(必须在pages中定义)
                     text: \'首页\',//导航名
                     iconPath: \'img/index.png\',//未选中的导航icon
                     selectedIconPath: \'img/index1.png\'//选中时的导航icon
                   },
                   {
                     pagePath: \'pages/mine\',
                     text: \'我的\',
                     iconPath: \'img/mine.png\',
                     selectedIconPath: \'img/mine1.png\'
                    }
            ]
       },
    };
    onLaunch() {//初始化
        console.log(this);
    }

    onShow(){}//当小程序启动,或从后台进入前台显示
    onHide(){}//当小程序从前台进入后台
}
</script>

<style >
/** less **/
</style>