微信小程序开发(2):小程序基本介绍

作者:叶小钗 

www.cnblogs.com/yexiaochai/p/9374374.html


前言


前面我们研究了下微信小程序的执行流程,因为拿不到源码,只能算我们的猜想,我们需要更加了解小程序还需要做具体的项目,于是我们将原来那套还算复杂的业务拿出来:


【组件化开发】前端进阶篇之如何编写可维护可升级的代码(https://www.cnblogs.com/yexiaochai/p/4876099.html)(有些晦涩有些乱,但是对于整体了解小程序结构有帮助)


我们用小程序实现这里的代码,看看是个什么样的体验,另外我这里想保证代码最大程度重用,为后续一端代码四端运行做前驱探索。



页面复杂度还是比较高的,包括了:


① 弹出层

② 页面跳转

③ 缓存

④ 数据请求

⑤ 列表页、滚动分页

⑥ ……


我相信完成了这个例子,我们对小程序业务代码怎么写会有比较好的了解,于是让我们开始今天的代码吧。


小程序的布局


为什么不使用HTML&CSS


微信小程序这种平台型的超越Hybrid系统诞生还是有一些客观条件的,其中一个就是移动端的应用相对来说简单的多,想想PC负责的布局,如果要使用小程序实现,那么复杂度会提高很多。


小程序代码编写逻辑层依旧使用JS完成,但是结构层以及样式层推出了:


① WXML,Weixin Markup Language,是微信设计的一套标签语言,与HTML类似,做过React&Vue的同学会非常熟悉

② WXSS,WeiXin Style Sheets,是一套样式语言,用于定义样式,与CSS类似,一般认为是CSS的子集


因为小程序中UI组件都是Native实现,所以小程序直接手起刀落压根放弃让我们使用HTML容器,这样做我觉得有个好处是:


为了更好的限制,我之前也在做Hybrid乃至前端框架,一般来说我会限制到View级别的实习,要求必须按照我的规则做,但是因为入口为index.html文件,我甚至将全局控制器App的实例化放到了main.js里面,只提供了建议的做法,事实上HTML还是太过灵活,有些同事逐渐根本不按照我们的规则玩,他觉得他的做法更好,但是这样一来便会破坏了项目的总体性,后续的工程性的优化或者监控可能就不能帮助他了,从某个角度来说,我是认可小程序的做法的。


我们之前在这里研究过自定义标签的做法:从DOM操作看Vue&React的前端组件化,顺带补齐React的demo


<article class="cm-page page-list" id="main">

    <div class="js_sort_wrapper sort-bar-wrapper">

        <mySortBar :entity="sortEntity"></mySortBar>

    </div>

    <myList :entity="listEntity" :sort="sort"></myList>

</article>


从这个文章以及小程序的实现可以看出基本的概念:


① 标签的出现根本不是做标签用,而是为了让JS捕捉执行相关逻辑,最后生成真正的标签

② 为了做更好的限制,小程序根本不提供入口index.html文件了,所以这里的标签是用作JS做模板解析后生成Native能识别的代码,更具体点说是,Native实现了一个组件,组件有很多规则,可以使用JS去调用,正如我们这里的header组件调用逻辑(JS会设置Native的Header组件展示),这里如果不太清晰可以参考下这个文章:浅谈Hybrid技术的设计与实现第二弹


当然,小程序底层具体是不是这么做,我们不得而知,如果有小程序的同事,可以指导下:),至此,我觉得可以从技术层面说明为什么不直接使用HTML&CSS了:更好的业务限制 + 方便JS解析模板被Native执行。


小程序组件


我们之前做Hybrid应用的时候,事实上只提供了一个真正具有结构的组件Header,其他loading类的提示组件都比较简单,而我们看看小程序提供了哪些组件呢:


容器类组件


view&scroll-view&swiper等作为容器组件存在,这里官方有基本介绍,我们这里看看其中一个即可:



这里官方给了一个demo进行说明:


<view class="section">

  <view class="section__title">flex-direction: row</view>

  <view class="flex-wrp" style="flex-direction:row;">

    <view class="flex-item bc_green">1</view>

    <view class="flex-item bc_red">2</view>

    <view class="flex-item bc_blue">3</view>

  </view>

</view>

<view class="section">

  <view class="section__title">flex-direction: column</view>

  <view class="flex-wrp" style="height: 300px;flex-direction:column;">

    <view class="flex-item bc_green">1</view>

    <view class="flex-item bc_red">2</view>

    <view class="flex-item bc_blue">3</view>

  </view>

</view>


@import "../lib/weui.wxss";


.page-section{

  margin-bottom: 20rpx;

}

.flex-wrp {display: flex;}

.bc_green {background: green;width:100px; height: 100px;}

.bc_red {background: red;width:100px; height: 100px;}

.bc_blue {background: blue;width:100px; height: 100px;}



可以将这个标签理解为div类组件。


swipe


一般来说,Native提供的轮播图体验要好得多,所以这里也提供了一个Native的组件:


<view class="container">

  <view class="page-body">

    <view class="page-section page-section-spacing swiper">

      <swiper

        indicator-dots="{{indicatorDots}}" autoplay="{{autoplay}}" circular="{{circular}}" vertical="{{vertical}}"

        interval="{{interval}}" duration="{{duration}}" previous-margin="{{previousMargin}}px" next-margin="{{nextMargin}}px">

        <block wx:for="{{background}}" wx:key="*this">

          <swiper-item>

            <view class="swiper-item {{item}}"></view>

          </swiper-item>

        </block>

      </swiper>

    </view>

    <view class="page-section" style="margin-top: 40rpx;margin-bottom: 0;">

      <view class="weui-cells weui-cells_after-title">

        <view class="weui-cell weui-cell_switch">

          <view class="weui-cell__bd">指示点</view>

          <view class="weui-cell__ft">

            <switch checked="{{indicatorDots}}" bindchange="changeProperty" data-property-name="indicatorDots" />

          </view>

        </view>

        <view class="weui-cell weui-cell_switch">

          <view class="weui-cell__bd">自动播放</view>

          <view class="weui-cell__ft">

            <switch checked="{{autoplay}}" bindchange="changeProperty" data-property-name="autoplay" />

          </view>

        </view>

        <view class="weui-cell weui-cell_switch">

          <view class="weui-cell__bd">衔接滑动</view>

          <view class="weui-cell__ft">

            <switch checked="{{circular}}" bindchange="changeProperty" data-property-name="circular" />

          </view>

        </view>

        <view class="weui-cell weui-cell_switch">

          <view class="weui-cell__bd">竖向</view>

          <view class="weui-cell__ft">

            <switch checked="{{vertical}}" bindchange="changeProperty" data-property-name="vertical" />

          </view>

        </view>

      </view>

    </view>


    <view class="page-section page-section-spacing">

      <view class="page-section-title">

        <text>幻灯片切换时长(ms)</text>

        <text class="info">{{duration}}</text>

      </view>

      <slider value="{{duration}}" min="500" max="2000" bindchange="changeProperty" data-property-name="duration" />

      <view class="page-section-title">

        <text>自动播放间隔时长(ms)</text>

        <text class="info">{{interval}}</text>

      </view>

      <slider value="{{interval}}" min="2000" max="10000" bindchange="changeProperty" data-property-name="interval" />

      <view class="page-section-title">

        <text>前边距(px)</text>

        <text class="info">{{previousMargin}}</text>

      </view>

      <slider value="{{previousMargin}}" min="0" max="50" bindchange="changeProperty" data-property-name="previousMargin" />

      <view class="page-section-title">

        <text>后边距(px)</text>

        <text class="info">{{nextMargin}}</text>

      </view>

      <slider value="{{nextMargin}}" min="0" max="50" bindchange="changeProperty" data-property-name="nextMargin" />

    </view>

  </view>

</view>


Page({

  data: {

    background: ['demo-text-1', 'demo-text-2', 'demo-text-3'],

    indicatorDots: true,

    vertical: false,

    autoplay: false,

    circular: false,

    interval: 2000,

    duration: 500,

    previousMargin: 0,

    nextMargin: 0

  },

  changeProperty: function (e) {

    var propertyName = e.currentTarget.dataset.propertyName

    var newData = {}

    newData[propertyName] = e.detail.value

    this.setData(newData)

  },

  changeIndicatorDots: function (e) {

    this.setData({

      indicatorDots: !this.data.indicatorDots

    })

  },

  changeAutoplay: function (e) {

    this.setData({

      autoplay: !this.data.autoplay

    })

  },

  intervalChange: function (e) {

    this.setData({

      interval: e.detail.value

    })

  },

  durationChange: function (e) {

    this.setData({

      duration: e.detail.value

    })

  }

})


有demo有代码,还是比较清晰。


movable-area


提供一个可以移动的区域,暂时没想到应用场景……


icon


图标,小程序这边还扩展了一下,给了很多默认的图标样式,能满足基本需求


text


文本


rich-text


富文本,用于展示文章,支持HTML,这里的nodes属性建议使用数组,类型,还不如系统自己解析js算了,因为不会有人像这样写代码(nodes看上去很蠢):


Page({

  data: {

    html: '<div class="div_class" style="line-height: 60px; color: red;">Hello&nbsp;World!</div><script>console.log(1)</script>',

    nodes: [{

      name: 'div',

      attrs: {

        class: 'div_class',

        style: 'line-height: 60px; color: red;'

      },

      children: [{

        type: 'text',

        text: 'Hello&nbsp;World!'

      }]

    }]

  },

  tap() {

    console.log('tap')

  }

})


progress


进度条


button


按钮


checkbox


选择框


form


表单相关


input


输入框,小程序的数据流动是单向的,每次数据更新,动态调用setData改变数据便会触发view更新,底层实现便不知道了;文本框值改变js需要自己去获取


label


与html一致,用以点击文字操作控件,主要用于文本框


picker&picker-view


用于级联操作


navigator&function-page-navigator


页面链接,这个组件感觉不利于跳转收口,建议少用


其他组件请大家直接到这里来看demo,非常清晰:


https://developers.weixin.qq.com/miniprogram/dev/component/map.html#map


总结


可以看出,小程序Native层是将常用的HTML标签分别都实现了一次,使用这些组件可以拼接处任何复杂的组件。至于样式方面,WXSS与CSS大同小异,其中主要区别是小程序没有使用px而是使用的rpx,这个类似于rem的实现,为了解决移动端的适配问题而存在,总而言之,你在iPhone6设计搞上是多少px就写成多少rpx就行,其余系统会帮你完成适配工作,这块透明做的很好,后续样式我们直接上实例即可。


小程序的生命周期


我们这里上一张图:



这张图不但真实反映了Page的生命周期,也将我们之前的猜想做了一个证明,解读这张图大概是这个意思(未必正确,如有错误请指出):


Native层在载入小程序时候,起了两个线程一个的view Thread一个是AppService Thread,我这边理解下来应该就是程序逻辑执行与页面渲染分离,也许是想优化性能,这里更具体一点的解释是(带有猜测了):微信会开一个webview来执行我们的JS逻辑,然后会开一个Native View UI执行页面渲染;两个部分是彼此独立的,页面点击时候触发事件,View线程会获取APPService服务线程(其实就是获取webview),执行其中的js逻辑;APPService执行js逻辑改变数据通过setData调用,触发一个JSCore通信,通知view线程执行UI更新,这里结合这张图做下理解:


① 微信打开一个小程序时,主UI线程继续运行,开启一个webview(我认为这里的主线程就是view Thread,webview就是APPService线程,这里可能有误)


② 主View等待构建页面命令,逻辑层开始载入js逻辑(编译过),微信底层应该会将WXML以及WXSS翻译为JS代码,逻辑层执行JS代码做一些初始化工作APP结束后,开始Page逻辑,而他这个图只有Page的逻辑,没有将app囊括进去,这里也引发了我一个疑惑:我在onLoad的时候打了个断点,而页面这个时候事实上已经进行了结构层的渲染,也就是说页面的WXML逻辑已经执行了:



如果要按照我现有的逻辑下做解释的话,我认为实例化Page的时候,执行了一个create事件,但是小程序并没有释放onCreate事件让我们做注册,所以我这里知识体系的基础依旧是:


JS逻辑先于Native UI 执行,页面渲染是由实例化Page时候发出


所以我觉得,这里的图好像少了一部分(或者说我理解是有问题的):



③ 业务线程执行实例化Page逻辑,引发onLoad、onShow事件,onShow的时候页面初步渲染已经结束,如果系统有异步数据或者其他再次数据渲染会执行setData,引发Native UI更新,逻辑结束


但是微信给出的图不可能是错的,而从图上看,首次异步通知是由View Thread发起的,我这里就很是困惑了😪,因为我认为逻辑发起者一定是逻辑层的js发出通知


总结


今天我们对小程序进行了基本的了解学习,明天我们持续完成我们的demo吧


感兴趣的小伙伴,可以关注公众号【grain先森】,回复关键词 “小程序”,获取更多资料,更多关键词玩法期待你的探索~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    X先生_未知数的X阅读 15,934评论 3 118
  • 【浮生缘,相思劫】03—凌霄宝殿逢冤家 文/锦歌长安 目录&序言上一章—天地巨变遇知音 上古纪昊天元历两千年! 那...
    锦歌长安阅读 775评论 2 7
  • “哈哈梦到我啥了” “梦见你早上上学,自己走的,刚下楼,就下雨了,我就后悔没送你去。” “还上学啊 我都工作多久了...
    烧作繁星阅读 194评论 0 7
  • 测试 谷歌
    ShermanYixiong阅读 288评论 0 0
  • 在路上看见几位很吸引我的男生,1体型好2穿衣有品,这来自于背后我看不见的坚持和自律,他们更爱自己更欣赏自己,更喜欢...
    floweryang是正能量阅读 205评论 0 0