- Published on
粗略总结一下小程序以及框架
- Authors
- Name
- lcorz
小程序开发
市面上现在的主流小程序写法大致有4种 ( 微信自己的原生写法, 腾讯的wepy框架, 美团的mpvue框架, 京东的taro ) 当然 还有一些小型框架比如 ( Tina.js, weweb )
这里主要就是粗略讲一下这几种写法
四者的开发文档:
原生开发小程序文档:点此进入
wepy 开发文档:点此进入
mpvue 开发文档:点此进入
taro 开发文档:点此进入
四者的简单对比及介绍:
以下用一份表格来简单概括四个的区别:
原生小程序 | wepy | mpvue | taro | |
---|---|---|---|---|
开发团队 | 微信 | 腾讯 | 美团 | 京东 |
语法风格 | 小程序开发规范 | 类vue规范 | vue规范 | react标准, 支持jsx |
组件规范 | 自定义组件规范 | 自定义组件规范 | vue组件规范 | react组件规范 |
样式规范 | wxss | less/sass/stylus/postcss/ | less/sass/postcss/ | less/sass/postcss/ |
上手成本 | 全新学习 | 熟悉vue且学习wepy | 熟悉vue | 熟悉react |
构建工具 | 无构建工具 | 框架内置构建工具 | webpack | webpack |
集中数据管理 | 不支持 | redux or mobx | vuex | redux or mobx |
标签 | 小程序标签 | 小程序标签 | html + 小程序 | 小程序标签 |
脚手架 | 无 | wepy-cli | vue-cli | taro-cli |
小程序支持的是 WXML + WXSS + JS 这样的组合,所以,后者几个框架都是将文件构建到 dist 目录,转换为小程序支持的文件类型,然后将微信开发者工具指向 dist 目录下,进行调试开发,并且框架都提供了热更新。
小程序自身除了css(增加了rpx)以外其他的都有自己的一套框架和api, 所以需要一定的学习成本 基本上刚写的时候就是在抱着文档写, 条条框框还是有很多的, 但是自带的api也是很给力, 感受到了功能支持上的空前的友好, 可以拿手机上的数据啊, 调用个这个功能那个功能的... 随着时间推进功能上也越来越完善一些了
最早出现框架的是wepy, 最初的想法就是解决小程序npm资源引用,以及组件化开发的问题, 居作者描述起初其实是一个个人项目在腾讯内部推广但是没人用, 后来挂在github上火了, 后被腾讯搬到了Tencent 域下, wepy框架文件以wpy结尾, 所以大多数编辑器还要配置一下才能支持文件的高亮和提示, 在使用过程中因为框架本身的一些特性 还是要学习一下.(star about 15.6k | time -> 2018.12.17 )
而后出现的是mpvue, 由美团在vue.js 的基础上修改了 runtime 和 compiler 实现, 使小程序开发拥有了开发vue的体验, 受限于小程序的限制还是有一些功能并不能完全与vue一致, 但是大体上还是会让小程序开发过程趋近于平常书写网页. (star about 14.9k | time -> 2018.12.17)
Taro 是一套遵循 React 语法规范的 多端开发 解决方案(包括Web、React-Native、小程序), 由京东的凹凸实验室开发, 知乎还有因此展开的谁是最强奥特曼的讨论... 它采用与 React 一致的组件化思想,组件生命周期与 React 保持一致,同时支持使用 JSX 语法, Taro这个框架在我写这篇文章的时候观察好评还是比较多的, 因为没有用过所以对它的坑不是太了解, 不知道它的这种多端支持能不能真的都兼顾的很好...( star about 12.4k | time -> 2018.12.17)
为什么会有小程序框架:
开发小程序最大的阻碍一直都不是如何采用 Vue 或者 React 的语法上手,而是:
- API 设计混乱
- 模板语法弱, 小程序的字符串模板仿的是 Vue,但是没有提供 Vue 那么多的语法糖, 当实现一些比较复杂的处理时,写起来就非常麻烦,虽然提供了 wxs 作为补充,但是使用体验还是非常糟糕
- 没有组件复用逻辑的能力( 这个现在有了 )
以及与前端社区脱节:
- 不能使用 npm
- 不能自由选择预编译器(babel / postcss / ...)
小程序的框架也算是应运而生...
以下提供少量不同点 详情还是参照官方文档
1.开发方式上:
原生开发: 原生开发的话, 需要全新去学习小程序的书写方式, 包括标签, 生命周期等等, 但是不支持 npm 包. 不支持 css 预处理器.
wepy: 开发者需要熟悉 vue 和 wepy 两种语法, 需要一定的学习成本, 支持 npm 包,支持 css 预处理器;
mpvue: 开发者需要熟悉 vue 即可,但是并不是所有的方法都支持, 支持 npm 包,支持 css 预处理器;
taro: 开发者需要熟悉 react 即可, 同上也不是所有的方法都支持, 支持 npm 包,支持 css 预处理器;
2.应用状态管理上:
原生开发: 没有提供原生的应用状态管理方式,但是可以将 Redux or Mobx 引入到项目中。 小程序原生提供了一种声明使用全局变量,写法为:
app.js 中配置变量
//App.js
App({
BASE_URL: 'http://www.baidu.com',
onLaunch: function () {
console.log('App Launch')
},
onShow: function () {
console.log('App Show')
},
onHide: function () {
console.log('App Hide')
}
})
通过全局函数 getApp() 可以获取全局的应用实例,然后调用配置常量 /pages/index/index index.js测试
Page({
onLoad:function(options){
var app = getApp(); // Get the app instance.
console.log(app.BASE_URL);
}
})
wepy: 可以将 Redux or Mobx 引入到项目中( 脚手架中默认集成redux需要的话可选 )。
mpvue: 可以直接使用 vuex 做应用状态管理
taro: 可以将 Redux引入到项目中。
3.开发方面:
生命周期
原生开发: 小程序自带一些生命周期 比如 created 阶段的onLoad
onShow
页面完成onReady
页面隐藏onHide
页面销毁 onUnload
之类的可以满足我们在小程序的各种交互阶段使用。
wepy: wepy生命周期基本与原生小程序相同,再此基础上糅合了一些vue的特性, 例如 computed watch ; 对于wepy中的methods属性,因为与Vue中的使用习惯不一致,非常容易造成误解,这里需要特别强调一下:wepy中的methods属性只能声明页面wxml标签的bind、catch事件,不能声明自定义方法,这与Vue中的用法是不一致的。
mpvue: mpvue 除了 Vue 本身的生命周期外,还兼容了小程序生命周期,这部分生命周期钩子的来源于微信小程序的 Page, 除特殊情况外,官方不建议使用小程序的生命周期钩子。
taro: taro 则与react生命周期完全一致
列表循环
原生开发: 原生小程序采用 wx:for
的方式循环列表 key使用 wx:key
的方式绑定
<view wx:for="{{totalTime}}" wx:key="{{index}}" class='indicator-content'>{{item}}</view>
wepy: 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>
或者使用微信提供的block组件
<block wx:for="{{imgArr}}" wx:key="index">
<swiper-item class="item" data-movieId="{{item.id}}" @tap="showMovieDetail">
<image class="img" src="{{item.img || item.image}}"></image>
</swiper-item>
</block>
mpvue: 使用v-for与vue一致,只是需要注意一点,嵌套列表渲染,必须指定不同的索引
<!-- 在这种嵌套循环的时候, index 和 itemIndex 这种索引是必须指定,且别名不能相同,正确的写法如下 -->
<template>
<ul v-for="(card, index) in list" :key="index">
<li v-for="(item, itemIndex) in card" :key="itemIndex">
{{item.value}}
</li>
</ul>
</template>
taro: 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>
})
wepy和taro对request进行了二次封装
wepy
// 原生代码:
wx.request({
url: 'xxx',
data: {
foo: 'foo',
bar: 10
},
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);
}
taro
Taro.request({
url: 'http://localhost:8080/test',
data: {
foo: 'foo',
bar: 10
},
header: {
'content-type': 'application/json'
}
}).then(res => console.log(res.data))
需要注意的点
原生开发: 原生开发其实要没什么特别需要注意的 注意文档就行了基本上让做的不让做的都写的比较清楚 毕竟就是个崭新的东西 没什么东西可以做比较 照着文档的规范写一般没啥坑 就是限制特别多 所以有时候以写网页的思维感觉处处都是坑
wepy:
- props传值的时候不能单独传递对象内的属性
<child :msg="msg.text"></child>
- events只定义组件间交互的方法。methods只定义事件方法例如bind,catch, 自定义方法与methods平级。
- 使用的是 Angular 的脏检查设计,而不是使用的 Vue 的 getter, setter 等,最初的想法就是利用脏检查去绕过性能不是很好的 setData。所有异步里如果涉及到页面状态的变更 都需要执行
this.$apply()
触发脏值检测, 否则页面状态不会发生变化 - wepy中的事件可传递一些基本类型的参数,但是需使用双括号。否则获取到的参数是字符串类型。
<view @tap="toggleType({{true}})">
- 如果你需要props传递的数据跟随父组件数据变化,要使用sync修饰符。
- wepy中使用 wx:if,只阻止视图渲染,不会阻止组件初始化。 如在子组件onLoad 生命周期或者计算属性中使用了一些父级传递过来的动态数据,就会报错。
- 组件component 没有 onLoad 等页面事件
mpvue:
- 因为mpvue在一定层面上相当于fork了vue去实现效果 所以维护起来可能相对复杂 现在github上有一些老bug没有人去解决 (或者说找不到好的办法解决)
- 在页面跳转的时候 前一个页面不会被销毁 所以在页面onUnload的时候要手动重置下页面数据(这个挺坑的其实)
- slot暂时只可以传递固定内容,父组件那边传递变量,子组件中无法进行渲染
- 有一些vue中的东西并不能直接使用 例如filter 以及在templete中使用复杂的运算
- 新增的页面 有时候会找不到 需要手动 npm run dev 一下
- 避免在created的时候做事情 所有页面里面的created生命周期函数 都会在小程序加载的时候, 一次性执行,而不是每进入一个页面执行一次
- 小程序的onLoad、onReady比created、mounted执行的早, 虽然官方建议不要用小程序的生命周期 但是目前用下来也没发现用了有什么问题
- 图片相对路径无法加载, 可以把图片放在根目录下的static文件下
taro:
- process.env.TARO_ENV可以帮助我们判断当前的编译环境,从而做一些特殊处理,目前它的取值有 weapp 、swan 、 alipay 、 h5 、 rn 五个
- WePY里的模板,或者说是wxml,用的都是小程序里原生的组件,就是小程序文档里的各种组件;而Taro里使用的每个组件,都需要从@tarojs/components里引入,包括View,Text等基础组件(这种做其实是为了转换多端做准备)事件处理上
- 不支持使用this.props.children这个特性
- 不能使用无状态组件
- 不支持通过props传入组件
- 不能在JSX参数中使用匿名函数
- 不能在包含 JSX 元素的 map 循环中使用 if 表达式
- 不能使用 Array.map 之外的方法操作 JSX 数组
- 暂不支持在 render() 之外的方法定义 JSX
- 不允许在 JSX 参数(props)中传入 JSX 元素
- 不能在 JSX 参数中使用对象展开符
other 在小程序中使用axios的时候 会出现请求报错的情况 主要是浏览器环境和小程序环境不同 需要使用adapter 进行适配
axios.defaults.adapter = function (res) {
return new Promise((resolve, reject) => {
wx.request({....})
})
}