Published on

粗略总结一下小程序以及框架

Authors
  • avatar
    Name
    lcorz
    Twitter

小程序开发

市面上现在的主流小程序写法大致有4种 ( 微信自己的原生写法, 腾讯的wepy框架, 美团的mpvue框架, 京东的taro ) 当然 还有一些小型框架比如 ( Tina.js, weweb )

这里主要就是粗略讲一下这几种写法

四者的开发文档:

原生开发小程序文档:点此进入

wepy 开发文档:点此进入

mpvue 开发文档:点此进入

taro 开发文档:点此进入

四者的简单对比及介绍:

以下用一份表格来简单概括四个的区别:

原生小程序wepympvuetaro
开发团队微信腾讯美团京东
语法风格小程序开发规范类vue规范vue规范react标准, 支持jsx
组件规范自定义组件规范自定义组件规范vue组件规范react组件规范
样式规范wxssless/sass/stylus/postcss/less/sass/postcss/less/sass/postcss/
上手成本全新学习熟悉vue且学习wepy熟悉vue熟悉react
构建工具无构建工具框架内置构建工具webpackwebpack
集中数据管理不支持redux or mobxvuexredux or mobx
标签小程序标签小程序标签html + 小程序小程序标签
脚手架wepy-clivue-clitaro-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({....})
  })
}