文章转自 https://www.cnblogs.com/Smiled/p/9806781.htmlcss
众所周知现在市面上端的形态多种多样,手机Web、ReactNative、微信小程序, 支付宝小程序, 快应用等,每一端都是巨大的流量入口,当业务要求同时在不一样的端都要求有所表现的时候,针对不一样的端去编写多套代码的成本显然很是高,这时候只编写一套代码就可以适配到多端的能力就显得极为须要。但面对目前市面上成熟的小程序第三方框架如何针对本身的需求进行选择也是一个麻烦事,本文针对当前市面上的三大转译框架进行一个综合对比,但愿能对你们的技术选择有所帮助,若有哪里不妥的地方但愿指正;html
在这里我经过对目前已开源的三种经常使用小程序框架作一个综合对比, 还有一个叫nanchi的基于react的小程序转译框架,因为没来的及研究暂不作比较;前端
腾讯团队开源的一款类vue语法规范的小程序框架,借鉴了Vue的语法风格和功能特性,支持了Vue的诸多特征,好比父子组件、组件之间的通讯、computed属性计算、wathcer监听器、props传值、slot槽分发,还有不少高级的特征支持:Mixin混合、拦截器等;WePY发布的第一个版本是2016年12月份,也就是小程序刚刚推出的时候,到目前为止,WePY已经发布了52个版本, 最新版本为1.7.2; vue
美团团队开源的一款使用 Vue.js 开发微信小程序的前端框架。使用此框架,开发者将获得完整的 Vue.js 开发体验,同时为 H5 和小程序提供了代码复用的能力。mpvue在发布后的几天间得到2.7k的star,上升速度飞起,截至目前为止已经有13.7k的star;node
京东凹凸实验室开源的一款使用 React.js 开发微信小程序的前端框架。它采用与 React 一致的组件化思想,组件生命周期与 React 保持一致,同时支持使用 JSX 语法,让代码具备更丰富的表现力,使用 Taro 进行开发能够得到和 React 一致的开发体验。,同时由于使用了react的缘由因此除了能编译h5, 小程序外还能够编译为ReactNative;react
滴滴的 mpx https://github.com/didi/mpxgit
同为vue规范的mpvue和wepy的生命周期和各类方法不尽相同github
wepy生命周期基本与原生小程序相同,再此基础上糅合了一些vue的特性; 对于WePY中的methods属性,由于与Vue中的使用习惯不一致,很是容易形成误解,这里须要特别强调一下:WePY中的methods属性只能声明页面wxml标签的bind、catch事件,不能声明自定义方法,这与Vue中的用法是不一致的。 vuex
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 = {}; // 声明组件之间的事件处理函数 }
mpvuenpm
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"
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当须要循环渲染WePY组件时(相似于经过wx:for
循环渲染原生的wxml标签),必须使用WePY定义的辅助标签<repeat>
<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 的执行,每个 JSX 元素,其实会经过 createElement
函数建立成一个 JavaScript 对象(React Element),所以实际上你能够这样写代码 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.js 的虚拟 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' }
踩坑注意(官方文档):
@regionchange
,同时这个事件也很是特殊,它的 event type 有 begin 和 end 两个,致使咱们没法在handleProxy
中区分究竟是什么事件,因此你在监听此类事件的时候同时监听事件名和事件类型既 <map @regionchange="functionName" @end="functionName" @begin="functionName"><map>
.stop
的使用会阻止冒泡,可是同时绑定了一个非冒泡事件,会致使该元素上的 catchEventName 失效!.prevent
能够直接干掉,由于小程序里没有什么默认事件,好比submit并不会跳转页面.capture
支持 1.0.9
.self
没有能够判断的标识.once
也不能作,由于小程序没有 removeEventListener, 虽然能够直接在 handleProxy 中处理,但很是的不优雅,违背了原意,暂不考虑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 元素的很类似。可是有一点语法上的不一样:
Taro 事件绑定属性的命名采用驼峰式写法,而不是小写。 若是采用 JSX 的语法你须要传入一个函数做为事件处理函数,而不是一个字符串 (DOM 元素的写法)。 例如,传统的微信小程序模板:
<button onclick="activateLasers"> Activate Lasers </button>
Taro 中稍稍有点不一样:
<button onClick={this.activateLasers}> Activate Lasers </button>
在 Taro 中另外一个不一样是你不能使用 catchEvent
的方式阻止事件冒泡。你必须明确的使用 stopPropagation
。例如,阻止事件冒泡你能够这样写:
class Toggle extends React.Component { constructor (props) { super(props) this.state = {isToggleOn: true} } onClick = (e) => { e.stopPropagation() this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })) } render () { return ( <button onClick={this.onClick}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button> ) } }
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
化使用。
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和Mbox,目前wepy的脚手架内已经集成了redux,选择须要便可;
mpVue使用vuex
taro使用Redux
时刻前端新鲜技术推送,按期前端精品文章分享,欢迎关注公众号前端小苑。