热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

微信小程序开发02小程序基本介绍【组件化开发】前端进阶篇之如何编写可维护可升级的代码(有些晦涩有些乱,但是对于整体了解小程序结构有帮助)

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

前言

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

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

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

① 弹出层

② 页面跳转

③ 缓存

④ 数据请求

⑤ 列表页、滚动分页

⑥ ......

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

小程序的布局

为什么不使用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

1 <article class="cm-page page-list" id="main">
2     <div class="js_sort_wrapper sort-bar-wrapper">
3         <mySortBar :entity="sortEntity">mySortBar>
4     div>
5     <myList :entity="listEntity" :sort="sort">myList>
6 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进行说明:

 1 <view class="section">
 2   <view class="section__title">flex-direction: rowview>
 3   <view class="flex-wrp" style="flex-direction:row;">
 4     <view class="flex-item bc_green">1view>
 5     <view class="flex-item bc_red">2view>
 6     <view class="flex-item bc_blue">3view>
 7   view>
 8 view>
 9 <view class="section">
10   <view class="section__title">flex-direction: columnview>
11   <view class="flex-wrp" style="height: 300px;flex-direction:column;">
12     <view class="flex-item bc_green">1view>
13     <view class="flex-item bc_red">2view>
14     <view class="flex-item bc_blue">3view>
15   view>
16 view>
1 @import "../lib/weui.wxss";
2 
3 .page-section{
4   margin-bottom: 20rpx;
5 }
6 .flex-wrp {display: flex;}
7 .bc_green {background: green;width:100px; height: 100px;}
8 .bc_red {background: red;width:100px; height: 100px;}
9 .bc_blue {background: blue;width:100px; height: 100px;}

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

swipe

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

 1 <view class="container">
 2   <view class="page-body">
 3     <view class="page-section page-section-spacing swiper">
 4       <swiper
 5         indicator-dots="{{indicatorDots}}" autoplay="{{autoplay}}" circular="{{circular}}" vertical="{{vertical}}"
 6         interval="{{interval}}" duration="{{duration}}" previous-margin="{{previousMargin}}px" next-margin="{{nextMargin}}px">
 7         <block wx:for="{{background}}" wx:key="*this">
 8           <swiper-item>
 9             <view class="swiper-item {{item}}">view>
10           swiper-item>
11         block>
12       swiper>
13     view>
14     <view class="page-section" style="margin-top: 40rpx;margin-bottom: 0;">
15       <view class="weui-cells weui-cells_after-title">
16         <view class="weui-cell weui-cell_switch">
17           <view class="weui-cell__bd">指示点view>
18           <view class="weui-cell__ft">
19             <switch checked="{{indicatorDots}}" bindchange="changeProperty" data-property-name="indicatorDots" />
20           view>
21         view>
22         <view class="weui-cell weui-cell_switch">
23           <view class="weui-cell__bd">自动播放view>
24           <view class="weui-cell__ft">
25             <switch checked="{{autoplay}}" bindchange="changeProperty" data-property-name="autoplay" />
26           view>
27         view>
28         <view class="weui-cell weui-cell_switch">
29           <view class="weui-cell__bd">衔接滑动view>
30           <view class="weui-cell__ft">
31             <switch checked="{{circular}}" bindchange="changeProperty" data-property-name="circular" />
32           view>
33         view>
34         <view class="weui-cell weui-cell_switch">
35           <view class="weui-cell__bd">竖向view>
36           <view class="weui-cell__ft">
37             <switch checked="{{vertical}}" bindchange="changeProperty" data-property-name="vertical" />
38           view>
39         view>
40       view>
41     view>
42 
43     <view class="page-section page-section-spacing">
44       <view class="page-section-title">
45         <text>幻灯片切换时长(ms)text>
46         <text class="info">{{duration}}text>
47       view>
48       <slider value="{{duration}}" min="500" max="2000" bindchange="changeProperty" data-property-name="duration" />
49       <view class="page-section-title">
50         <text>自动播放间隔时长(ms)text>
51         <text class="info">{{interval}}text>
52       view>
53       <slider value="{{interval}}" min="2000" max="10000" bindchange="changeProperty" data-property-name="interval" />
54       <view class="page-section-title">
55         <text>前边距(px)text>
56         <text class="info">{{previousMargin}}text>
57       view>
58       <slider value="{{previousMargin}}" min="0" max="50" bindchange="changeProperty" data-property-name="previousMargin" />
59       <view class="page-section-title">
60         <text>后边距(px)text>
61         <text class="info">{{nextMargin}}text>
62       view>
63       <slider value="{{nextMargin}}" min="0" max="50" bindchange="changeProperty" data-property-name="nextMargin" />
64     view>
65   view>
66 view>
View Code
 1 Page({
 2   data: {
 3     background: [\'demo-text-1\', \'demo-text-2\', \'demo-text-3\'],
 4     indicatorDots: true,
 5     vertical: false,
 6     autoplay: false,
 7     circular: false,
 8     interval: 2000,
 9     duration: 500,
10     previousMargin: 0,
11     nextMargin: 0
12   },
13   changeProperty: function (e) {
14     var propertyName = e.currentTarget.dataset.propertyName
15     var newData = {}
16     newData[propertyName] = e.detail.value
17     this.setData(newData)
18   },
19   changeIndicatorDots: function (e) {
20     this.setData({
21       indicatorDots: !this.data.indicatorDots
22     })
23   },
24   changeAutoplay: function (e) {
25     this.setData({
26       autoplay: !this.data.autoplay
27     })
28   },
29   intervalChange: function (e) {
30     this.setData({
31       interval: e.detail.value
32     })
33   },
34   durationChange: function (e) {
35     this.setData({
36       duration: e.detail.value
37     })
38   }
39 })
View Code

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

movable-area

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

icon

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

text

文本

rich-text

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

 1 Page({
 2   data: {
 3     html: \'
Hello World!
\', 4 nodes: [{ 5 name: \'div\', 6 attrs: { 7 class: \'div_class\', 8 style: \'line-height: 60px; color: red;\' 9 }, 10 children: [{ 11 type: \'text\', 12 text: \'Hello World!\' 13 }] 14 }] 15 }, 16 tap() { 17 console.log(\'tap\') 18 } 19 })

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发起的,我这里就很是困惑了


推荐阅读
  • ScrollView嵌套Collectionview无痕衔接四向滚动,支持自定义TitleView
    本文介绍了如何实现ScrollView嵌套Collectionview无痕衔接四向滚动,并支持自定义TitleView。通过使用MainScrollView作为最底层,headView作为上部分,TitleView作为中间部分,Collectionview作为下面部分,实现了滚动效果。同时还介绍了使用runtime拦截_notifyDidScroll方法来实现滚动代理的方法。具体实现代码可以在github地址中找到。 ... [详细]
  • 最近做个项目要用百度地图,每一个点都要在地图上显示出来,而且都在可是范围之内,因为之前已经将所有的点都标注到地图上了,但是地图大小不变化。下面是代码:functionresizeMap(){ ... [详细]
  • 微信小程序导航跟随的实现方法
    本文介绍了在微信小程序中实现导航跟随的方法。通过设置导航的position属性和绑定滚动事件,可以实现页面向下滚动到导航位置时,导航固定在页面最上方;页面向上滚动到导航位置时,导航恢复到原始位置;点击导航可以平滑跳转到相应位置。代码示例也给出了具体实现方法。 ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • JNI技术实践小结转自http:sett ... [详细]
  • 一、在androidStudio中实现tabs比较简单,新建项目就可以选择tabs模板进行创建,默认实现tabs功能:直接运行项目就可以看到效果:可以说非常简单,但是我们在实际开发 ... [详细]
  • [二分图]JZOJ 4612 游戏
    DescriptionInputOutputSampleInput44#****#****#*xxx#SampleOutput5DataConstraint分析非常眼熟࿰ ... [详细]
  • Adapter相当于C(Controller,控制器),listView相当于V(View,视图)用于显示数据为ListView提供数据的List,数组或数据库相当于MVC模式中的 ... [详细]
  • Educational Codeforces Round 43 (Rated for Div. 2)
    EducationalCodeforcesRound43(RatedforDiv.2)https:codeforces.comcontest976A ... [详细]
  • WPF开发心率检测大数据曲线图的高性能实现方法
    本文介绍了在WPF开发中实现心率检测大数据曲线图的高性能方法。作者尝试过使用Canvas和第三方开源库,但性能和功能都不理想。最终作者选择使用DrawingVisual对象,并结合局部显示的方式实现了自己想要的效果。文章详细介绍了实现思路和具体代码,对于不熟悉DrawingVisual的读者可以去微软官网了解更多细节。 ... [详细]
  • 本文介绍了一款名为TimeSelector的Android日期时间选择器,采用了Material Design风格,可以在Android Studio中通过gradle添加依赖来使用,也可以在Eclipse中下载源码使用。文章详细介绍了TimeSelector的构造方法和参数说明,以及如何使用回调函数来处理选取时间后的操作。同时还提供了示例代码和可选的起始时间和结束时间设置。 ... [详细]
  • 如何在HTML中获取鼠标的当前位置
    本文介绍了在HTML中获取鼠标当前位置的三种方法,分别是相对于屏幕的位置、相对于窗口的位置以及考虑了页面滚动因素的位置。通过这些方法可以准确获取鼠标的坐标信息。 ... [详细]
  • 本文介绍了Cocos2dx学习笔记中的更新函数scheduleUpdate、进度计时器CCProgressTo和滚动视图CCScrollView的用法。详细介绍了scheduleUpdate函数的作用和使用方法,以及schedule函数的区别。同时,还提供了相关的代码示例。 ... [详细]
  • Tkinter Frame容器grid布局并使用Scrollbar滚动原理
    本文介绍了如何使用Tkinter实现Frame容器的grid布局,并通过Scrollbar实现滚动效果。通过将Canvas作为父容器,使用滚动Canvas来滚动Frame,实现了在Frame中添加多个按钮,并通过Scrollbar进行滚动。同时,还介绍了更新Frame大小和绑定滚动按钮的方法,以及配置Scrollbar的相关参数。 ... [详细]
  • 涉及的知识点-ViewGroup的测量与布局-View的测量与布局-滑动冲突的处理-VelocityTracker滑动速率跟踪-Scroller实现弹性滑动-屏幕宽高的获取等实现步 ... [详细]
author-avatar
0.0
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有