你与小程序开发的距离有多远?

你与小程序开发的距离有多远

2017年1月9日凌晨。小程序正式发布。css

对焦10年前iPhone的发布时间,产品之神张小龙显然是想让这一天具备十分重要的历史意义。小程序发布以后,它终于揭开了最终面目,咱们不得不认可,这一天,一定是一个新时代的开端。html

做为一个第一批小程序的开发者,从小程序内测之初经过开发工具破解版开始尝试小程序,见证了小程序官方文档的每一次更新,踩太小程序的大多数坑,也见证了好几个小程序社区的逐步发展,到最终把本身的小程序过审上线,这个过程对我而言,收获良多。前端

为了对这段时间的收获作一个总结,也但愿能将本身的经验分享给你们,因此有了这篇文章,让想要开发小程序的小伙伴们对比一下本身掌握的知识,距离开发一个成熟的小程序,到底还差多少。也让想要学习小程序的朋友,有一个大的方向。vue

1、小程序开发工具为新手朋友提供了什么样的便利?

2016这一全年来,前端开发发生了很重要的变化,好比ES6的全面普及,react的持续火热,vue的爆发式增加,全部人都知道学习这些东西很重要,可是为何不少不少的新手朋友们每每只能了解皮毛而难以真正掌握呢?react

那就是由于构建工具的门槛过高。 es6

不少人在学习别人的代码的时候,会很惊讶的发现,为何别人的代码,和浏览器能识别的样子,差距那么大?其实全都是构建工具的功劳。不管是ES6,仍是react,组件化,模块化,这些东西通通都会经过构建工具,最终变成浏览器能识别的样子,也就是咱们最初学习时所知道的那个简单样子,一个页面,包括css,html,js,image等web

对于大多数团队来讲,只要公司中有大神能搭建一个成熟的开发环境,对于这些知识的学习实际上是容易不少的,这也是为何,不少人在进入某个团队的时候成长速度会变得更快的缘由所在。可是对于一个刚入门的新手来讲,想要搭建一个能用的构建工具是很是困难的。json

而对于这个门槛,小程序的开发工具,则完美的帮你们解决了这个问题。咱们不须要额外搭建任何开发环境,只须要下载《微信web开发工具》,就能够看着小程序的文档开始写demo了。redux

因此若是你想要低成本的学习ES6,体验组件化的开发模式,小程序应该算是一个不错的选择。小程序

2、 须要什么样的基础知识

熟悉文档

因为小程序是中文文档,因此我相信对大多数人来讲,学习成本很是低。咱们须要实现什么效果,须要用到什么组件和api,这些基础的东西就在文档里,咱们只须要熟悉他们便可,若是你连文档都不熟悉,真的谈不上开发小程序了,可是小程序文档确实足够简单以至于对大多数人来讲,过一遍就知道应该怎么玩了。

须要对html,css的知识有足够的熟悉程度

小程序的组件,仍然是基于html与css的知识来完成,咱们只须要对html与css足够熟悉,就可以很轻松的完成小程序的布局。诸如文档流,包含块,BFC,定位系统,怪异盒模型,弹性盒模型等等知识,都可以用获得。

须要对JavaScript足够熟悉

和网页应用同样,在小程序里,全部的功能都由js完成。而因为三方插件的匮乏,对于js的封装能力和对数据的处理能力就会要求高一点。而且须要你对模块化有必定的认知。

须要有控制数据就能改变UI的思惟

没有接触过类MVC模式框架的朋友,每每对于这个思惟转变有必定程度上的难以接受。因此常常看到有人在学习angular和react时处处询问如何把jQuery引入进来,其实在99%的场景下,咱们都再也不须要获取到DOM节点,只须要操做数据和方法就能完成全部的事情,咱们须要有这样一个心理准备。

2、开发小程序,咱们面临着什么样的挑战

若是你只是想要写一个demo,看着官方文档把一些组件,api体验一下,那是没有什么挑战的。可是若是咱们想要开发一个成熟健全的小程序,那么面临的挑战就不少。

好比:
如何保存登陆状态,UI状态等?
为了给用户节约流量,应该如何规划缓存机制?
不支持webview,咱们如何展现html文章?
如何应对三方插件匮乏的情况?
没有提供明确的组件机制,咱们应该如何处理组件?
不支持promise,咱们如何处理异步?
小程序体积限制为1024k,咱们应该如何优化代码与处理静态资源?
具体功能应该如何实现等等... ...

固然,并非每个小程序都要考虑全部的问题,这里我从我本身开发的小程序的角度,跟你们分享一下,我遇到了哪些问题,如何解决,用了什么样的方案。

如何保存各类轻量缓存数据以及状态值

假如在一个简单的学习demo中,咱们想要改变一个矩形的宽高,并把结果保存起来,只须要设定一个全局变量便可。这样咱们就能够在任何地方知道这个矩形改变以后的宽高了,可是咱们知道,为了防止变量污染,以及在多人开发中出现命名冲突等问题,咱们的原则上是不能有全局变量的。那么若是不用全局变量,咱们应该怎么作?

若是学习过react的同窗,应该会对redux有所耳闻。redux就可以解决这个问题。可是redux对于小程序而言,因为功能过于强大,反而不太适合。所以,尝试本身造一个简单的轮子来解决这个问题。

小程序中,咱们可使用es6的模块化规范,来建立模块,引入模块等,若是对于模块化的开发思惟还不太熟悉,建议先学习一下。

建立一个叫state.js的文件,该文件就是一个独立的模块,专门用来处理轻量的数据缓存

首先建立一个state对象,准备将数据以json的格式存起来

let states = {} // 存储变量复制代码

分别提供一个获取数据的方法,一个获取states所有数据的方法

function get (name) {
    if(states[name]) { return states[name] }
    return ''
}

function getStates () {
    return states
}复制代码

再提供一个保存数据的方法,咱们知道若是只保存一个key-value的数据很简单,可是咱们想要实现react中,setState一样功能的话,则须要作一些特殊的处理。

function set (options, target) {
    let keys = Object.keys(options)
    let o = target ? target : states
    keys.map( item => {
        if(typeof o[item] == 'undefined') {
            o[item] = options[item]
        } 
        else {
            if(utils.type(o[item]) == 'object') {
                set(options[item], o[item])
            } else {
                o[item] = options[item]
            }
        }
        return item
    })
}复制代码

对外提供访问的接口,这个模块就算完成了。

module.exports = {
    get: get,
    getStates: getStates,
    set: set
}复制代码

在别的模块中,使用方式以下

// 先引用
import state from './utils/state'

// 保存一个值
state.set('single', { c: 1, d: 2 })
// 查看一下single中的数据
state.get('single')
// 只修改single中的c值
state.set({
  single: { c: 20 }
})
// 修改完成以后再查看一下结果,这也是set方法的厉害之处,这对于咱们保存提供了极大的便利复制代码

虽然这个模块代码简单,可是state可以存储足够多的数据,它提供了全局变量给咱们带来的便利,也避免了全局变量的弊端,甚至还给组件之间的交互提供了可能。若是你没有意识到这个模块的重要性,那么你还得多写几个demo细细的体会一下。

上面的state模块还须要什么重要的拓展吗?

咱们试想一下,若是咱们想要修改一个皮肤设置项,或者咱们要切换白天/黑夜模式的外观,咱们应该怎么作?为何个人按钮一改变,全局的皮肤就能当即作出响应?

这个时候,咱们须要掌握js设计模式中,一个极为重要的模式, 订阅-通知模式,或者叫作观察者模式,监听者模式均可以。在一个app中,若是咱们想要作好缓存和用户体验,就会大量用到它。

在修改皮肤这个例子中,咱们改变了按钮的状态值,这个状态改变值触发了一个事件,这个事件完成了对皮肤的修改。固然在此以前,咱们还得将这个事件,与这个状态值绑定起来。

绑定事件 -> 点击按钮状态值改变 -> 触发事件 -> 皮肤修改完成

所以,该模式的原理也大概以下,咱们首先须要将对应的事件保存起来与变量值的key,这个过程就叫作绑定,相似事件绑定。在状态值改变时,咱们就发送一个通知,告诉咱们的模块,状态值改变了,应该执行事件了,因而事件执行。

声明一个存储数据的数组

let events = [] // 存储事件复制代码

每个绑定,都会以对象的形式,保存在数组中

events = [{
    name: 'changeToNight',
    handler: changeFn,
    page: targetPage
}]复制代码

添加一个绑定事件

function bind (name, notification, targetPage) {
    if (name && notification) {
        if (!targetPage) {
            console.error('bind error: 没有绑定页面对象')
            return;
        } 
        events.push({
            name: name,
            handler: notification,
            page: targetPage
        })
    } else {
        console.error('bind error: no name or handler')
    }
}复制代码

添加一个通知事件

function dispatch (name, value) {
    if(!value) {
        value = get(name)
    }
    else {
        set({
            [name]: value
        })
    }
    if(!events.length) { return }

    events.map( (item, i) => {
        if(item.name == name) {
            item.handler(value)
        }
    })
}复制代码

简单的实现了一下,若是你们想要将该模式运用的更加自如,还须要专门花精力去研究他。我这里只是简单的暂时了一种实现方式。

如何解决html文章的展现

因为小程序中不支持html标签,它有本身的一套标签组件,所以咱们在使用时,并不能直接把html文章显示出来。为了可以解决这个问题,咱们须要将html标签转换为小程序支持的标签。

有一个叫作html2json.js的组件。它遍历html的标签结构,并根据便利结果将标签内容以json的数据形式保存起来,咱们就能够经过该json数据生成对应的小程序标签。

固然若是是咱们本身作的话还比较麻烦,好在有大神在第一时间提供了一个叫作wxParse的三方插件。你们能够去搜索使用一下。

因为该插件功能太齐全,不少个人小程序用不上,因此就根据上面我说的思路本身实现了一个轻量级的,恰好够本身用。

如何考虑缓存机制

上面的state组件,可以在必定程度上缓存一些轻量的数据。可是该组件的生命周期短暂,在小程序退出以后数据就会消失,并且对于数据量比较大的状况,也不适合用state组件来缓存。

每个小程序有10M的本地缓存空间。并且小程序也提供了缓存和清除缓存的api,所以这不是咱们的难点,咱们的难点在于,如何分清哪些数据应该缓存,每一种数据应该缓存多久?如何更新?服务器数据若是更新了应该如何同步本地缓存?

缓存策略作得好很差,在很大程度上会决定你小程序的总体质量。固然这里我就不详细展开解读了,涉及到不少东西,一时半会儿感受说不清楚了,你们只要考虑清楚了上面的几个问题,相信都可以结合本身的实际状况,弄出一个合理的方案。

如何处理组件以及组件的数据传递,组件的交互等

小程序并无提供明确的组件机制。可是咱们知道,在小程序里,一个页面能够由xx.wxml, xx.wxjs, xx.wxss, xx.json组成,这是一个基本结构。并且小程序提供了js的模块引入,wxml的模板引入,这就为咱们自定义组件创造了可能。

+ component
   + rect
      - rect.wxml
      - rect.wxss
      - rect.js   

+ pages
   + index
      - index.wxml
      - index.wxss
      - index.js复制代码

咱们建立了一个rect组件,并但愿咱们本身可以自定义矩形的颜色,点击以后,还会再修改一次颜色

一切从简,rect组件中代码

// rect.wxml
<template name="rect">
  <view class="single-rect" bindtap="changeColor" style="background-color: {{rectColor}}"></view>  
</template>

// rect.wxss
.single-rect {
  width: 100px;
  height: 100px;
  background-color: red;
}

// rect.js
module.exports = {
  changeColor: function (_this) {
    _this.setData({
      rectColor: 'orange'
    })
  }
}复制代码

index页面中引入该组件

// index.wxml
<import src="../../component/rect/rect.wxml" />
<template is="rect" data="{{rectColor}}"></template>

// index.wxss
@import "../../component/rect/rect.wxss";

// index.js
import rect from '../../component/rect/rect'

Page({
    data: {},
    onLoad: function () {
        console.log(rect)
    },
    changeColor: function () {
        rect.changeColor(this)
    }
})复制代码

这个例子演示了组件的建立与使用,其中包含了数据传递。固然看上去有点麻烦,所以咱们能够经过构建工具来简化这个过程。这里就很少说了,在不增长额外构建的状况下,这样使用是彻底没有问题的。至于不一样组件之间的交互,就得经过上面的state组件来完成。

如何使用Promise

Promise的重要性不言而喻,这里就再也不介绍promise了,若是不明白的同窗能够去其余文章里学习一下。可是小程序通过几回改变,已经决定取消对Promise的支持,在实际应用中,promise几乎无处不在使用。所以,咱们须要本身引入一个polyfill来支持promise。

小程序对于接口的返回结果进行了一层统一的封装,可是咱们并不想使用这样的结果,这个结果会致使代码量的增长,所以咱们能够经过promise的过滤设置,只返回咱们想要的东西便可。

若是可以准确理解resolve与reject,那么咱们就可以随意的定制过滤规则了。

function wxPromise (cb) {
    return function (result = {}) {
        return new Promise ((resolve, reject) => {
            result.success = _res => {
                if(_res.statusCode) {
                    /(2|3)\d+/.test(_res.statusCode) ? resolve(_res.data) : reject(_res.data)
                } else {
                    resolve(_res)
                }
            }
            result.fail = (...args) => {
                reject(...args)
            }
            cb(result)
        })
    }
}复制代码

固然还有许多具体功能的具体实现方案,好比如何实现加载更多下拉刷新,如何实现图片懒加载,如何实现k线图的绘制,若是实现本地数据同步刷新等等等,因为时间关系,就不一一介绍了,之后有时间再跟你们分享吧。

本文主要目的是但愿给你们提供一个学习方向,所以不少知识点都是一笔带过,并未详细讲解,须要你们去其余地方加深学习

ps,姗姗来迟,由我独立开发的《老虎淘股》小程序终于过审发布了。[撒花],欢迎你们搜索体验,多提意见~ ~

相关文章
相关标签/搜索