小程序第三方框架对比 ( wepy / mpvue / taro )

    |     2020年3月27日   |   web前端技术, 移动端   |     0 条评论   |    1186

手机 Web、React Native、微信小程序、支付宝小程序、快应用都是流量入口。业务要多端同时有表现时,为每一端各写一套成本很高,于是出现了只写一套代码再编译到多端的方案。当前常用的三类转译框架是 WePY、mpvue、Taro。

选择并不只看 star。语法是 Vue 还是 React、生命周期怎么映射、列表和事件怎么写、request 和状态管理怎么接,都会直接影响迁移成本和踩坑面。本文按这几块做对照,原文链接保留在文末。

20200327094033

框架 语法 多端 状态管理
WePY 类 Vue(腾讯) 小程序为主 脚手架可集成 Redux / MobX
mpvue Vue.js(美团) H5 + 微信小程序复用 Vuex
Taro React / JSX(京东凹凸) 小程序 / H5 / RN Redux

一、小程序开发的痛点

原生小程序开发常见的几处难受:

  • 频繁调用 setData,过程中页面跳闪
  • 组件化支持很弱,几乎没有
  • 不能直接用 less、scss 等预编译器
  • request 并发次数有限制

二、为什么用第三方框架

  • 熟悉 Vue 或 React 即可上手,学习成本低
  • 一套代码可编译到微信、支付宝、H5、RN(支付宝小程序当时仍不完善)
  • 组件化开发,隔离、嵌套、通信更好做
  • 能用第三方 npm 包
  • 可支持 Promise,少写回调
  • Generator / Class / Async Function 等能提升效率
  • 补生命周期、做性能优化等
  • 样式编译器 Scss/Less,以及 Babel / TypeScript

三、WePY / mpvue / Taro 对照

另外还有一个叫 nanchi 的基于 React 的转译框架,当时没来得及研究,本文不比较。

WePY

腾讯开源,类 Vue 语法。支持父子组件、组件通信、computed、watcher、props、slot,以及 Mixin、拦截器等。2016 年 12 月(小程序刚推出)发第一版,当时已发到 52 个版本,最新 1.7.2。文档:https://tencent.github.io/wepy/document.html

mpvue

美团开源,用 Vue.js 开发微信小程序,开发体验接近完整 Vue,并给 H5 和小程序代码复用。发布后几天拿到 2.7k star,当时约 13.7k。文档:http://mpvue.com/mpvue/#-html

Taro

京东凹凸实验室开源,用 React 开发小程序:组件化、生命周期与 React 一致,支持 JSX。因为用了 React,除 H5、小程序外还可以编译为 React Native。文档:https://taro.aotu.io/

╬в╨┼╜╪═╝_20200327094550

1055667-20181017200144824-1272624771

四、生命周期

同为 Vue 规范的 mpvue 和 WePY,生命周期和方法并不完全相同。

WePY

生命周期基本与原生小程序相同,再糅合部分 Vue 特性。特别容易误解的是 methods:WePY 里它只能声明页面 wxml 标签的 bind、catch 事件,不能声明自定义方法,这和 Vue 不一致。

import wepy from 'wepy';



export default class MyPage extends wepy.page {

// export default class MyComponent extends wepy.component {

    customData = {}  // 自定义数据



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



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



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



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



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



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



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



    computed = {};  // 声明计算属性(详见后文介绍)



    watch = {};  // 声明数据watcher(详见后文介绍)



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



    events = {};  // 声明组件之间的事件处理函数

}

mpvue

除 Vue 本身生命周期外,还兼容了小程序生命周期,这部分钩子来源于微信小程序的 Page。除特殊情况外,不建议使用小程序生命周期钩子。

1Vue

 3 beforeCreate

 4 created

 5 beforeMount

 6 mounted

 7 beforeUpdate

 8 updated

 9 activated

10 deactivated

11 beforeDestroy

12 destroyed

13 app 部分

15 onLaunch,初始化

16 onShow,当小程序启动,或从后台进入前台显示

17 onHide,当小程序从前台进入后台

18 page 部分

20 onLoad,监听页面加载

21 onShow,监听页面显示

22 onReady,监听页面初次渲染完成

23 onHide,监听页面隐藏

24 onUnload,监听页面卸载

25 onPullDownRefresh,监听用户下拉动作

26 onReachBottom,页面上拉触底事件的处理函数

27 onShareAppMessage,用户点击右上角分享

28 onPageScroll,页面滚动

29 onTabItemTap, 当前是 tab 页时,点击 tab 时触发 (mpvue 0.0.16 支持)

简单示例:

new Vue({

  data: {

    a: 1

  },

  created () {

    // `this` 指向 vm 实例

    console.log('a is: ' + this.a)

  },

  onShow () {

    // `this` 指向 vm 实例

    console.log('a is: ' + this.a, '小程序触发的 onshow')

  }

})

// => "a is: 1"

Taro 与 React 生命周期完全相同

class Clock extends Component {

  constructor (props) {

    super(props)

    this.state = { date: new Date() }

  }



  componentDidMount() {



  }



  componentWillUnmount() {



  }



  render () {

    return (

      <View>

        <Text>Hello, world!</Text>

        <Text>现在的时间是 {this.state.date.toLocaleTimeString()}.</Text>

      </View>

    )

  }

}

五、列表渲染

三者写法不同。

WePY 循环渲染组件时(类似 wx:for 渲染原生 wxml),必须用辅助标签 :

<template>

    <!-- 注意,使用for属性,而不是使用wx:for属性 -->

    <repeat for="{{list}}" key="index" index="index" item="item">

        <!-- 插入<script>脚本部分所声明的child组件,同时传入item -->

        <child :item="item"></child>

    </repeat>

</template>



<script>

    import wepy from 'wepy';

    // 引入child组件文件

    import Child from '../components/child';



    export default class Index extends wepy.component {

        components = {

            // 声明页面中要使用到的Child组件的ID为child

            child: Child

        }



        data = {

            list: [{id: 1, title: 'title1'}, {id: 2, title: 'title2'}]

        }

    }

</script>

mpvue 用 v-for,与 Vue 一致;嵌套列表必须指定不同的索引:

<!-- 在这种嵌套循环的时候, index 和 itemIndex 这种索引是必须指定,且别名不能相同,正确的写法如下 -->

<template>

    <ul v-for="(card, index) in list">

        <li v-for="(item, itemIndex) in card">

            {{item.value}}

        </li>

    </ul>

</template>

Taro 列表循环基本与 React 相同。React 里 JSX 会编成 JS,每个元素经 createElement 变成对象,所以下面这种写法 React 也能渲染:

const list = this.state.list.map(l => {

  if (l.selected) {

    return <li>{l.text}</li>

  }

}).filter(React.isValidElement)

但 Taro 会把 JSX 编成微信小程序模板字符串,不能把 map 生成的模板当数组再处理。需要时先处理数组,再用处理好的数组调用 map:

const list = this.state.list

  .filter(l => l.selected)

  .map(l => {

    return <li>{l.text}</li>

  })

六、事件处理

mpvue 目前全支持小程序事件处理器:引入 Vue 虚拟 DOM 后,模板里绑定的事件挂到 vnode 上,compiler 在 wxml 上绑定小程序事件并做映射。真实点击时 runtime 的 handleProxy 按事件类型分发到 vnode,和 Vue 在 Web 上一样,因此能无损支持,并顺带支持自定义事件和 $emit。

// 事件映射表,左侧为 WEB 事件,右侧为 小程序 对应事件

{

    click: 'tap',

    touchstart: 'touchstart',

    touchmove: 'touchmove',

    touchcancel: 'touchcancel',

    touchend: 'touchend',

    tap: 'tap',

    longtap: 'longtap',

    input: 'input',

    change: 'change',

    submit: 'submit',

    blur: 'blur',

    focus: 'focus',

    reset: 'reset',

    confirm: 'confirm',

    columnchange: 'columnchange',

    linechange: 'linechange',

    error: 'error',

    scrolltoupper: 'scrolltoupper',

    scrolltolower: 'scrolltolower',

    scroll: 'scroll'

}

官方文档里的踩坑注意:

  • 列表里没有的原生事件也可把 bind 改成 @,例如 @regionchange。该事件的 type 有 begin 和 end,handleProxy 区分不了,需要同时监听事件名和类型:

  • bind 和 catch 同时绑定时,能力限制下只会触发 bind,catch 不会触发
  • .stop 会阻止冒泡,但同时绑了非冒泡事件时,可能导致该元素上的 catchEventName 失效
  • .prevent 基本可以去掉,小程序没有多少默认行为(submit 也不会跳页)
  • .capture 支持 1.0.9;.self 没有可判断标识;.once 做不到,因为没有 removeEventListener
  • 键值修饰符在小程序里没有键盘,用不上

WePY 事件绑定区别于 Vue,按原生事件做了语法优化:

  • 绑定:bindtap="click" 换成 @tap="click"
  • 取消冒泡:catchtap="click" 换成 @tap.stop="click"
  • 捕获:capture-bind:tap="click" 换成 @tap.capture="click"
  • 中断捕获:capture-catch:tap="click" 换成 @tap.capture.stop="click"

Taro 元素事件和 DOM 很像,但有两点不同:属性名用驼峰,而不是小写;JSX 里传入的是函数,不是字符串。传统微信模板:

<button onclick="activateLasers">

  Activate Lasers

</button>

Taro 里稍有不同:

<button onClick={this.activateLasers}>

  Activate Lasers

</button>

另外不能用 catchEvent 阻止冒泡,必须明确调用 stopPropagation。

七、request 请求

wepy对wx.request做了接受参数的修改,值得一提的是它提供了针对全局的intercapter拦截器
// 原生代码:



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

}

拦截器:

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

            }

        });

    }

}

Taro 对 request 做了二次封装,可用 Taro.request(OBJECT) 发起请求,并支持 Promise 化。

1055667-20181018120017403-1425410190

import Taro from '@tarojs/taro'



Taro.request({

  url: 'http://localhost:8080/test',

  data: {

    foo: 'foo',

    bar: 10

  },

  header: {

    'content-type': 'application/json'

  }

})

  .then(res => console.log(res.data))

mpvue 没有对 request 做特殊优化,与原生相同,需要的话自己封装。

八、状态管理与如何选择

  • WePY 可引用 Redux 和 MobX,脚手架已集成 Redux,按需选择
  • mpvue 使用 Vuex
  • Taro 使用 Redux

怎么选:

  • 只做微信小程序:按自己擅长选 mpvue 或 Taro
  • 老项目迁小程序且原本是 Vue:建议 mpvue 或 WePY
  • 老项目是 React 且部分迁小程序:建议 Taro
  • 新项目要同时支持微信和支付宝:当时更建议原生,因为框架转支付宝支持不好、出问题难定位;小 demo 可以尝鲜。支付宝视图层与微信接近,手动替换方法和全局替换属性/文件名(如 wxml→axml)大约四比一工时;人手够则一端一队更好

原文:https://www.cnblogs.com/Smiled/p/9806781.html

一句话总结:WePY / mpvue 走 Vue 习惯,Taro 走 React;列表、事件和 request 的差异比 star 数更决定能不能落地。

转载请注明来源:小程序第三方框架对比 ( wepy / mpvue / taro )
本文链接地址:https://ai.zhousir.top/?p=2504
回复 取消