快速入门 WePY 小程序

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

一、WePY介绍

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

二、WePY 使用

1、WePY的安装或更新都通过npm进行:

npm install -g wepy-cli  //全局安装或更新WePY命令行工具(wepy脚手架): wepy-cli
wepy -v //查看wepy-cli版本
wepy init standard  //新建wepy小程序项目,1.7.0之前的版本使用:wepy new myproject
wepy list //查看项目模板
cd  //切换至项目目录
npm  install //安装依赖
wepy build --watch //开启实时编译

git base here:

(1)全局安装或更新 wepy-cli:

快速入门 WePY 小程序_第1张图片

(2)查看 wepy-cli 版本:

快速入门 WePY 小程序_第2张图片

(3)创建 wepy 小程序项目:

快速入门 WePY 小程序_第3张图片

(4)切换至项目目录,安装依赖:

快速入门 WePY 小程序_第4张图片

(5)开启实时编译

快速入门 WePY 小程序_第5张图片

2、代码高亮WebStorm/PhpStorm(其他工具参见wepy官网代码高亮)

(1)打开Settings,搜索Plugins,搜索Vue.js插件并安装。

(2) 打开Settings,搜索File Types,找到Vue.js Template,在Registered Patterns添加*.wpy,即可高亮。

3、代码优化

(1)代码规范

  • wepy标签和原生一样
  • 自定义组件命名应避开:原生组件名(input、button、view、repeat等)、WePY的辅助标签
  • 变量/方法名尽量使用驼峰式命名,避免使用$开头($开头的标识符是WePY内建属性/方法,可在js中以this.的方式直接使用,具体请参考API文档)
  • app、pages、components文件名的后缀为.wpy,外链的文件可以是其它后缀。 具体请参考wpy文件说明。
  • 支持ES6/7的一些新特性,框架在ES6(ECMAScript 6)下开发(默认使用babel编译),因此也需要使用ES6开发小程序,ES6中有大量的语法糖可以让我们的代码更加简洁高效。
  • wepy继承了wx对象的方法,建议在wepy框架开发中不要用到wx对象的方法,虽然运行时效果是一样,但是打包时会cli报错(wepy中没有wx对象)wepy中组件中使用的是class,vue中使用的的是对象。

(2)数据绑定

小程序页面渲染层和JS逻辑层分开的,setData操作实际就是JS逻辑层与页面渲染层之间的通信,在同一次运行周期内多次执行setData操作时,通信的次数是一次还是多次取决于API本身的设计。WePY使用脏数据检查对setData进行封装,在函数运行周期结束时执行脏数据检查,一来可以不用关心页面多次setData是否会有性能上的问题,二来可以更加简洁去修改数据实现绑定,不用重复去写setData方法。

//原生小程序
this.setData({title: 'this is title'});//通过Page提供的setData方法来绑定数据

//wepy
this.title = 'this is title';


//wepy 在异步函数中更新数据的时候,必须手动调用$apply方法,才会触发脏数据检查流程的运行
setTimeout(() => {
    this.title = 'this is title';
    this.$apply();
}, 3000)


//保留setData方法,但不建议使用setData执行绑定,修复传入undefined的bug,并且修改入参支持: 
this.setData(target, value) 
this.setData(object)

(3)事件绑定以及传参优化

 //​​​​​ 原 bindtap="click"(省略了.default后缀 )绑定小程序冒泡型事件
 //​​​​​ 原catchtap="click"  绑定小程序捕获型事件,如catchtap
 //​​​​​ 原 capture-bind:tap="click"
 //​​​​​ 原 capture-catch:tap="click"

 //​​​​​ 原bindtap="click" data-index={{index}}

(4)框架默认对小程序提供的API全都进行了 Promise 处理,甚至可以直接使用async/await等新特性进行开发,同时修复了一些原生API的缺陷(如:wx.request的并发问题等)

// 原生代码:

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);
}

(5)computed 计算属性computed计算属性(类型{ [key: string]: Function }),是一个有返回值的函数,可直接被当作绑定数据来使用,类似于data属性。需要注意的是,只要是组件中有任何数据发生了改变,那么所有计算属性就都会被重新计算。

  data = {
      a: 1
  }

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

(6)watcher 监听器

通过监听器watcher(类型{ [key: string]: Function })能够监听到任何属性的更新。监听器适用于当属性改变时需要进行某些额外处理的情形。

  data = {
      num: 1
  }

  // 监听器函数名必须跟需要被监听的data对象中的属性num同名,
  // 其参数中的newValue为属性改变后的新值,oldValue为改变前的旧值
  watch = {
      num (newValue, oldValue) {
          console.log(`num value: ${oldValue} -> ${newValue}`)
      }
  }

  // 每当被监听的属性num改变一次,对应的同名监听器函数num()就被自动调用执行一次
  onLoad () {
      setInterval(() => {
          this.num++;
          this.$apply();
      }, 1000)
  }

(7)WXS (WeiXin Script)

WePY 从1.7.x 版本开始支持 wxs 语法,但语法与原生 wxs 稍有出入

a.wxs是基于原生的wxs去实现的,只是通过编译把现在的语法编译为原生语法

②wxs必须是外链文件。并且后缀为.wxs

③wxs引入后只能在template中使用,不能在script中使用

/**
project
└── src
    ├── wxs
    |   └── mywxs.wxs      wxs 文件 
    ├── pages
    |   └── index.wpy      页面
    └──app.wpy           
**/

// mywxs.wxs

module.exports = {
  text: 'This is from wxs',
  filter: function (num) {
    return num.toFixed(2);
  }
};

// index.wpy



(8)interceptor 拦截器

可以使用WePY提供的全局拦截器对原生API的请求进行拦截。具体方法是配置API的config、fail、success、complete回调函数。参考示例:

import wepy from 'wepy';

export default class extends wepy.app {
    constructor () {
        // this is not allowed before super()
        super();
        // 拦截request请求
        this.intercept('request', {
            // 发出请求时的回调函数
            config (p) {
                // 对所有request请求中的OBJECT参数对象统一附加时间戳属性
                p.timestamp = +new Date();
                console.log('config request: ', p);
                // 必须返回OBJECT参数对象,否则无法发送请求到服务端
                return p;
            },

            // 请求成功后的回调函数
            success (p) {
                // 可以在这里对收到的响应数据对象进行加工处理
                console.log('request success: ', p);
                // 必须返回响应数据对象,否则后续无法对响应数据进行处理
                return p;
            },

            //请求失败后的回调函数
            fail (p) {
                console.log('request fail: ', p);
                // 必须返回响应数据对象,否则后续无法对响应数据进行处理
                return p;
            },

            // 请求完成时的回调函数(请求成功或失败都会被执行)
            complete (p) {
                console.log('request complete: ', p);
            }
        });
    }
}

三、WePY项目的目录结构

dist目录为WePY通过build指令生成的目录,除额外增加的npm目录外,其目录结构与原生小程序的目录结构类似。

快速入门 WePY 小程序_第6张图片

原生小程序:app(app.jsapp.jsonapp.wxss),page(page.jspage.jsonpage.wxmlpage.wxss),文件必须同名。WePY中则使用了单文件模式:app.wpypage.wpy

快速入门 WePY 小程序_第7张图片 ==> 快速入门 WePY 小程序_第8张图片

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

  1. 脚本//lang值:babel(默认、TypeScript

    主要对目录的以下几点分析(其他目录文件详解类似于https://my.oschina.net/wangnian/blog/2050375中做的分析):

    1、src文件夹

    (1)components组件:

    组件实例继承自wepy.component类,除了不需要config配置以及页面特有的一些生命周期函数之外,其属性与页面属性大致相同:

    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事件,自定义方法需以自定义方法的方式声明,不能放在methods中,会报错
        events = {};  // WePY组件事件处理函数对象,存放响应组件之间通过$broadcast、$emit、$invoke所传递的事件的函数
    }
    /** 与page不同的是component不存在:
        onShow () {}  // 只在Page中存在的页面生命周期函数
        config = {};  // 只在Page实例中存在的配置数据,对应于原生的page.json文件,类似于app.wpy中的config
        onReady() {}  //  只在Page中存在的页面生命周期函数
    **/

    原生小程序支持js模块化,但彼此独立,业务代码与交互事件仍需在页面处理。无法实现组件化的松耦合与复用(如,模板A中绑定一个bindtap="myclick",模板B中同样绑定一样bindtap="myclick",那么就会影响同一个页面事件、数据)

    WePY组件的所有业务与功能在组件本身实现,组件与组件之间彼此隔离(上述例子在WePY的组件化开发过程中,A组件只会影响到A所绑定的myclick,B也如此)

    // 原生代码: