diff --git "a/\343\200\220\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\343\200\221\345\274\200\345\217\221\345\256\236\346\210\230-\344\271\213-\343\200\214\345\274\200\345\217\221\346\241\206\346\236\266MINA\346\236\204\346\210\220\343\200\215.md" "b/\343\200\220\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\343\200\221\345\274\200\345\217\221\345\256\236\346\210\230-\344\271\213-\343\200\214\345\274\200\345\217\221\346\241\206\346\236\266MINA\346\236\204\346\210\220\343\200\215.md" new file mode 100644 index 0000000..b2ed346 --- /dev/null +++ "b/\343\200\220\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\343\200\221\345\274\200\345\217\221\345\256\236\346\210\230-\344\271\213-\343\200\214\345\274\200\345\217\221\346\241\206\346\236\266MINA\346\236\204\346\210\220\343\200\215.md" @@ -0,0 +1,114 @@ +**小程序开发框架的目标是通过尽可能简单、高效的方式让开发者可以在微信中开发具有原生 APP 体验的服务。** + +微信团队为小程序提供的框架命名为MINA。MINA框架通过封装微信客户端提供的文件系统、网络通信、任务管理、数据安全等基础功能,对上层提供一整套JavaScript API,让开发者方便的使用微信客户端提供的各种基础功能与能力,快速构建应用。 + +### MINA框架 + +微信小程序的框架示意图如下所示: + + ![](https://upload-images.jianshu.io/upload_images/19956127-9cd6fb39b2ab1924.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +#### MINA框架主要分为两大部分: + +第一部分页面视图层,开发者使用WXML文件来搭建页面的基本视图结构(WXML是类似于HTML标签的语言和一系列基础组件),使用WXSS文件来控制页面的表现样式。 + +第二部分AppService应用逻辑层,是MINA框架的服务中心,通过微信客户端启动异步线程单独加载运行,页面渲染所需的数据、页面交互处理逻辑都在其中实现。MINA框架中的AppService使用JavaScript来编写交互逻辑、网络请求、数据处理,但不能使用JavaScript中的DOM操作。小程序中的各个页面可以通过AppService实现数据管理、网络通信、生命周期管理和页面路由。 + +MINA框架为页面组件提供了一系列事件监听相关的属性(比如bindtap、bindtouchstart等),来与AppService中的事件处理函数绑定在一起,来实现页面向AppService层同步用户交互数据。MINA框架同时提供了很多方法将AppService中的数据与页面进行单向绑定(注意数据的绑定方向是单向的),当AppService中的数据变更时,会主动触发对应页面组件的重新渲染。 + +**框架的核心是一个响应式的数据绑定系统,它能让数据与视图很简单的保持同步**。只需要在逻辑层修改数据,视图层就会做相应的更新。示例如下: +``` + + + 欢迎使用{{appname}} + + + +//AppService应用逻辑层代码 +//初始数据 +page({ + data:{ + appname:'易投票' + }, + changeAppname:function(e){ + this.setData({ + appname:'我的小程序' + }) + } +}) +``` +![图1:初始名称](https://upload-images.jianshu.io/upload_images/19956127-e4608803dbcf6cbe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +![图2:点击按钮“更换名称”以后](https://upload-images.jianshu.io/upload_images/19956127-370f3e032584ee83.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +示例中数据是如何更新的呢?首先,开发者通过框架将AppService应用逻辑层数据中的appname与页面视图层名为appname的变更进行了绑定,页面在刚打开的时候会显示“欢迎使用 易投票。然后,当点击按钮“更换名称”之后,视图层会发送changeAppname的tap事件给逻辑层,逻辑层找到事件函数changeAppname。最后,逻辑层changeAppname函数执行了setData操作,将对象appname的值改变为“我的小程序”,因为该对象已经在视图层绑定,所以视图层会显示为图2的名称了。 + +小程序的MINA框架有着接近原生App的运行速度,在框架层面做了大量的优化,在重功能上(page或tab切换、多媒体、网络连接等)上使用接近于native的组件继承,对安卓和ios端做出了高度一致的呈现,还有近乎完备的开发、调试工具。 + +### 目录结构 + +典型的小程序目录结构非常简洁,一般一个项目包含两个目录(pages和utils)三个文件(app.js、app.json、app.wxss)。pages目录下包括程序所需的各个页面,一个页面对应一个目录,包含2至4个文件(.js、.wxml、.json及.wxss)。utils目录则包含一些公共的js代码文件。当然,我们还可以添加其他的公共目录,如用来存放本地图片资源的images目录。 + + ![](https://upload-images.jianshu.io/upload_images/19956127-93279c70b2164c2d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +### 逻辑层 + +小程序的逻辑层就是所有.js脚本文件的集合。小程序在逻辑层处理数据并发送至视图层,同时接受视图层发回的事件请求。 + +MINA框架的逻辑层是由JavaScript编写,在此基础上,微信团队做出了一些优化,以便更高效的开发小程序,这些优化包括: + +1、增加app方法用来注册程序,增加page方法用来注册页面; + +2、提供丰富的API接口; + +3、页面的作用域相对独立,并拥有了模块化的能力; + +简单概括,逻辑层就是各个页面的.js脚本文件。 + +需要注意的是,小程序的逻辑层由js编写,但并不是在浏览器中运行的,所以JavaScript在Web中的一些能力都不能使用,比如 dom、window等,这也是我们开发过程中要克服的阻碍。 + +### 视图层 + +对于微信小程序而言,视图层就是所有的.wxml(WeiXin Markup language)文件与.wxss(WeiXin Style Sheet)文件的集合:.wxml用于描述页面结构而.wxss用于描述页面样式。 + +视图层以给定的样式来展现数据并反馈事件给逻辑层,而数据展现是以组件来进行的。组件(Component)是视图的基本组成单元。 + +### 数据层 + +数据层包括临时数据或缓存、文件存储、网络存储与调用。 + +#### 1、页面临时数据或缓存 + +在页面page()中,我们要使用setData函数来将数据从逻辑层发送到视图层,同时改变对应的this.data的值。this在小程序中一般指调用页面,广泛情况下指的是包含它的函数作为方法被调用时所属的对象。直接修改this.data是无效的,无法改变页面的状态,还会造成数据的不一致。单次设置的数据有一个大小限制,不能超过1024KB,避免一次性设置过多的数据。 + +setData()函数的参数接受一个对象。以key,value的形式表示,将this.data中的key对应的值改变为value。key可以非常灵活,包括以数据路径的形式表示,如array[0].title,并且无需在this.data中预定义。 + +#### 2、文件存储(本地存储) + +使用微信提供的现成数据API接口,如: + +wx.getStorage:获取本地数据缓存 + +wx.setStorage:设置本地数据缓存 + +wx.clearStorage:清理本地数据缓存 + +#### 3、网络存储与调用 + +上传或下载文件的API接口,如: + +wx.request:发起网络请求 + +wx.uploadFile:上传文件 + +wx.downloadFile:下载文件 + +#### 调用URL的API接口如下: + +wx.navigateTo:保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。可返回原页面。 + +wx.redirectTo:关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。不可返回原页面。 + + 以上就是微信小程序框架的相关描述,微信团队一直在不断的优化框架能力,及时的关注官方提供的[小程序开发者文档](https://developers.weixin.qq.com/miniprogram/dev/index.html?t=19041716),了解小程序的最新能力及优化点。 +原文作者:DreamGo +原文链接:https://www.cnblogs.com/idreamo/p/10867241.html diff --git "a/\345\260\217\347\250\213\345\272\217\346\212\200\346\234\257\345\247\213\344\272\216\345\276\256\344\277\241\357\274\237\346\235\245\347\234\213\347\234\213\347\247\273\345\212\250\347\253\257\345\260\217\347\250\213\345\272\217\346\212\200\346\234\257\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237\357\274\201.md" "b/\345\260\217\347\250\213\345\272\217\346\212\200\346\234\257\345\247\213\344\272\216\345\276\256\344\277\241\357\274\237\346\235\245\347\234\213\347\234\213\347\247\273\345\212\250\347\253\257\345\260\217\347\250\213\345\272\217\346\212\200\346\234\257\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237\357\274\201.md" new file mode 100644 index 0000000..142b0c8 --- /dev/null +++ "b/\345\260\217\347\250\213\345\272\217\346\212\200\346\234\257\345\247\213\344\272\216\345\276\256\344\277\241\357\274\237\346\235\245\347\234\213\347\234\213\347\247\273\345\212\250\347\253\257\345\260\217\347\250\213\345\272\217\346\212\200\346\234\257\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237\357\274\201.md" @@ -0,0 +1,301 @@ +本文由DCloud 公司创始人王安原创发布于CSDN,原题《小程序技术演进史》,即时通讯网收录时有改动,感谢原作者。 + +## 1、引言 + +微信的成功,并非特定于某个具体的功能,微信的成功实际上是一大批创新技术和体验的成功合集,这也是它为何如此难此被超越的根本原因。 + +作为微信这个超级社交应用中最为亮眼的技术之一——微信小程序,俨然已成历移动端小程序的代名词,很多人一提起“小程序”3个字就条件反射式地认为是微信小程序。事实是,小程序技术并非微信独创,它的出现和演进,实际上包含了一大批各类公司、各产品技术先驱们的努力。 + +实际上,早在微信小程序之前,有力推轻应用的百度,有来自 HTML5 中国产业联盟的 DCloud 所主张的流应用,但最终却都已经淹没在了移动互联网的历史长河之中。唯有微信小程序风生水起,更是带动了巨头们的争相入场。 + +小程序迎来了专属于中国移动互联网的群雄逐鹿的时代。 + +本文作者王安即是流应用的创造者,作为移动领域的老兵,他依然在矢志不移地构建移动开发工具框架及生态,从原生应用到 HTML5 再到如今的小程序,他是这段历史的见证者、参与者。 + +本篇文章,将为你盘点移动端小程序技术的前世今生。通过本文,我们能够鲜活地看到小程序的技术演进历程,以及对于所有开发者来说,终将去往何处。 + +![小程序技术始于微信?来看看移动端小程序技术的前世今生!_cover.jpg](https://upload-images.jianshu.io/upload_images/19956127-7aa4dd8dffa02d76.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 "小程序技术始于微信?来看看移动端小程序技术的前世今生!_cover.jpg") + + +## 2、关于作者 + +![小程序技术始于微信?来看看移动端小程序技术的前世今生!_aa.jpg](https://upload-images.jianshu.io/upload_images/19956127-02f819b9d44e8ba7.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 "小程序技术始于微信?来看看移动端小程序技术的前世今生!_aa.jpg") + + +**王安:**DCloud 公司创始人,HTML5 中国产业联盟秘书长。2003 年开始从事移动互联网工作,十几年编程和商业经验,连续创业者。曾任北京市学联主席,毕业后创办 DCloud 公司。兴趣爱好:编程、颠覆式创新。 + +## 3、相关文章 + +《[最火移动端跨平台方案盘点:React Native、weex、Flutter](http://www.52im.net/thread-1870-1-1.html)》 +《[盘点主流移动端跨平台UI技术:实现原理、技术优劣、横向对比等](http://www.52im.net/thread-2641-1-1.html)》 + +## 4、中国特色的移动互联网时代 + +伴随着 [QQ 小程序](https://mp.weixin.qq.com/s?__biz=MjM5MjAwODM4MA==&mid=2650722592&idx=1&sn=7537b4af132453ff3d80314e27ccc065&chksm=bea6a0f389d129e531afec52c75c05cb34ddd912fc560f9f4d68b3eb91eeaea97cc353fbf8db&scene=21#wechat_redirect) 面向用户开放,这个手机端月活 7 亿的巨无霸正式入场。小程序,终于成为了超级 App 的标配。 + +**盘点下已经支持小程序的超级 App:** + +微信、企业微信、QQ、支付宝、高德地图、手机淘宝、百度、百度贴吧、百度地图、今日头条、抖音…… + +这些璀璨耀眼的名字,背后都是巨大的流量。 + +在这群超级 App 的支持下,中国的移动互联网格局被彻底改变。 + +这个有中国特色的移动互联网时代,被称为“小程序时代”。 + +这是继手机支付后,中国的移动互联网领先世界的第二个代表事物。 + +中国的技术标准、开发者生态,第一次得到大规模的普及应用,而且很明显,小程序在功能和体验上均超过了 HTML5。 + +中国人能建立开发者生态吗?这个命题曾一度让人怀疑。 + +小程序完成了这一步突破,这是一场值得歌颂的中国技术生态发展史。 + +让我们来回顾下这场技术生态革命,是如何开始,又将要去向何方。 + +## 5、罗马不是一天建成的,小程序也不是一天发明出来的 + +HTML5 于 2007 年在 W3C 立项,与 iPhone 发布同年。 + +乔布斯曾期待 HTML5 能帮助 iPhone 打造起应用生态系统。 + +但 HTML5 的发展速度并不如预期,它虽然成功地实现了打破 IE+Flash 垄断局面的目标,却没有达到承载优秀的移动互联网体验的地步。 + +于是在 iPhone 站稳脚跟后,发布了自己的 App Store,开启了移动互联网的原生应用时代。 + +随后的 Android,本来是基于 Linux 的 OS,与之同期的 MeeGo 等竞争对手采用 C + HTML5 的双模应用生态策略,然而 C 的开发难度太大,HTML5 体验又不行。Android 依靠 Java 技术生态,在竞争中脱颖而出。 + +于是:在移动互联网初期,应用生态被定了基调 —— 原生开发。 + +在那个时候,硬件不行,也没有其他办法,原生开发才能在低配硬件上带来商用体验。 + +但大家都在怀念 HTML,那种无需安装更新、即点即用,直达二级页面的特点,一直让人迷恋。 + +![小程序技术始于微信?来看看移动端小程序技术的前世今生!_1.jpg](https://upload-images.jianshu.io/upload_images/19956127-e729183198b23984.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 "小程序技术始于微信?来看看移动端小程序技术的前世今生!_1.jpg") + + + +国内有一批做浏览器的厂商,尝试去改进 HTML5,他们提出了轻应用的概念。 + +通过给 WebView 扩展原生能力,补充 JS API,让 HTML5 应用可以实现更多功能。 + +不过这类业务没有取得成功,HTML5 的问题不止是功能不足,性能体验是它更严重的问题,而体验问题,不是简单地扩展 JS 能力能搞定的。 + +这类业务发展的顶峰,是微信的 JS SDK。 + +作为国内事实上最大的手机浏览器,微信为它的浏览器内核扩充了大量 JS API,让开发者可以用 JS 调用微信支付、扫码等众多 HTML5 做不到的功能。 + +![小程序技术始于微信?来看看移动端小程序技术的前世今生!_2.jpeg](https://upload-images.jianshu.io/upload_images/19956127-f6cd63ba7f2d8283.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 "小程序技术始于微信?来看看移动端小程序技术的前世今生!_2.jpeg") + +▲ 微信 JS SDK 说明文档 + +但微信团队对这套方案的体验仍然不满意,微信钱包栏目里打车、理财等很多应用虽然嵌入了 JS SDK,但每次点击要等半天白屏,让人用着很痛苦,他们在业内开始寻找新的解决方案。 + +业内早有专业团队看到了相同的问题。 + +与浏览器不同,Hybrid 应用是另一个细分领域。它们为开发者提供使用 JS 编写跨平台应用的工具,为了让 JS 应用更接近原生应用的功能体验,这个行业的从业者做出了很多尝试。 + +笔者所在的 DCloud 即是其中之一,我们提出了改进 HTML5 的“性工能”障碍的解决方案 —— 通过工具、引擎优化、开发模式调整,让开发者可以通过 JS 写出更接近原生 App 体验的应用。 + +多 WebView 模式,原生接管转场动画、下拉刷新、Tab 分页,预载 WebView……各种优化技术不停迭代,终于让 Hybrid 应用取得了性能体验的突破。 + +Hybrid 应用和普通的轻应用相比,还有一个巨大的差别:一个是 Client/Server,一个是 Browser/Server。简单来说,Hybrid 应用是 JS 编写的需要安装的 App,而轻应用是在线网页。 + +C/S 的应用在每次页面加载时,仅需要联网获取 JSON 数据;而 B/S 应用除了 JSON 数据外,还需要每次从服务器加载页面 DOM、样式、逻辑代码,所以 B/S 应用的页面加载很慢,体验很差。 + +可是这样的 C/S 应用虽然体验好,却失去了 HTML5 的动态性,仍然需要安装、更新,无法即点即用、直达二级页面。 + +那么 C/S 应用的动态性是否可以解决呢?对此,我们提出了流应用概念,把之前 Hybrid 应用里的运行于客户端的 JS 代码,先打包发布到服务器,制定流式加载协议,手机端引擎动态下载这些 JS 代码到本地,并且为了第一次加载速度更快,实现了应用的边下载边运行。 + +就像流媒体的边下边播一样,应用也可以实现边用边下。 + +在这套方案的保障下,终于解决了之前的各种难题:让 JS 应用功能体验达到原生,并且可即点即用、可直达二级页面。 + +如今看来,这已经变成了常识。但在当年,先驱们做了无数艰辛探索。 + +这套技术,需要让客户端引擎提前预置在手机上,就像流媒体的普及,建立在 Flash 的装机量巨大的基础上,那么普及这个客户端引擎就变得很重要。 + +2015 年,360 和 DCloud 合作,在 360 手机助手里内嵌了这个客户端引擎,推出了业内第一个商用的小程序,360 称之为 360 微应用。 + +微应用实现了在 360 手机助手的应用下载页面,同时出现了“秒开”按钮,点击后直接使用。 + +并且在 360 手机助手的扫码里,应用的分享里,都实现了扫码获得一个应用,点击分享消息获得一个应用。 + +![小程序技术始于微信?来看看移动端小程序技术的前世今生!_3.jpg](https://upload-images.jianshu.io/upload_images/19956127-93a7267b739e3a21.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 "小程序技术始于微信?来看看移动端小程序技术的前世今生!_3.jpg") + +▲ 在 360 手机助手 3.4 版本中上线的中国第一个小程序 + +为了做大生态,DCloud 把这套技术标准,捐献给了 HTML5 中国产业联盟,随后,联盟开始推动更多的超级 App 和手机厂商加入,共同推进动态 App 产业的发展。 + +然而事情并不顺利,巨头们有自己的利益诉求。虽然有一批厂商同意加入联盟共建生态,但最关键的角色,真正的国民应用“微信”,最终决定自立标准、自研引擎,当然技术原理与流应用是基本一致的。 + +* 2016 年 1 月 11 日,微信公开课,张小龙罕见露面,公布了微信应用号的计划,为这个大事件亲自站台。 +* 2016 年 9 月 21 日,微信宣布更名应用号为小程序,面向首批开发者内测。从此,这个词被正式定了下来,“小程序”,成为后续一个时代的代名词。而“流应用”、“微应用”则淹没在历史长河中成为一个令人唏嘘的故事。 +* 2017 年 1 月 9 日,微信公开课,小程序面向用户正式推出。 + +从此后,阿里巴巴、手机厂商联盟、百度、今日头条,陆续推出了自己的小程序平台,其中也有很多波折与故事,在有偶然、有必然的过程中,形成了今天的局面。 + +小程序大潮卷入了更多人,并形成了更大的浪潮,最终迎来了不可逆转的小程序时代。 + +## 6、生态难,难于上青天 + +发明能解决功能体验和动态性的技术方案,虽然难,但不是最难的事情。 + +最难的是开发者生态的建设。 + +最初 HTML5 中国产业联盟的策略是在 HTML5 上扩展强化,复用现有的 HTML5 生态。 + +当微信的标准完全自立重建时,业内人士都悬着一颗心。 + +在全球,基于 Web 的技术生态已经非常成熟,各种开发工具、框架、组件、模板...提升着开发者的效率。 + +小程序丢弃了国际标准组织 W3C 的 DOM 和 Window 标准,仅仅采用基础 JavaScript。这意味着 HTML5 生态的各种轮子无法复用,要完全重造一个新的小程序开发生态。 + +当初微信推广 JS SDK 时,是那么地顺其自然,开发者纷纷开始使用,因为对于开发者,只是在他们的 H5 版本上补充一些 API 而已。 + +而小程序初期,充满了开发者的质疑声:我的业务迭代那么久,让我重新做一个版本,你的生态到底能不能支撑我的投入? + +微信用持续而快速的版本升级、高管的站台,告诉大家微信做小程序的决心,并最终通过 2017 年底的跳一跳,引爆了小程序。 + +从此大家的问题不再是我要不要做小程序了,而转向了:既然要做,怎么才能提升小程序的开发效率、降低开发成本? + +任何一种技术,或者开发模式的演进,在不断成熟的过程中,都遵循着类似的成熟规律: + +技术标准 -> 基础平台 -> 开发工具 -> 培训市场 -> 框架诞生 -> 周边生态逐步完善 -> 轮子之上的轮子 + +在 HTML5 生态里,已经发展到最终极的形态,比如 [Vue](https://github.com/vuejs/vue) 是一个重要框架,而基于 Vue 的各种丰富的 UI 库、测试框架,则是轮子之上的轮子。 + +多层轮子代表着生态的繁荣,也意味着开发者的开发效率更高。 + +可微信的全新标准出现时,它把开发者推回了原始社会,一切都要重来。 + +这在当时看来,并不是一个必然会成功的事情(其实直到现在,比如图表类轮子,小程序仍然比不过 HTML5)。 + +时至今日,讨论这个标准的选择对错已经没有意义。当支付宝、百度、今日头条都开始参考这个标准做小程序时,时代已经不可阻挡。 + +所幸,最终的结果是,中国人做成了。在国际标准之外,在中国,终于建立起了自己的技术生态。 + +并且这个生态,给用户带来了更好的体验,给开发者带来了更多流量和变现效率的提升,这是一个比 HTML5 更优秀的生态。 + +## 7、野蛮的技术生态成长速度 + +两年时间,中国的小程序开发者如何从原始社会进阶到现代文明?这也是一段有趣的历史。 + +我们来看看小程序技术生态是如何快速成长,走完上面所说的这套技术成熟路线,也就是从技术标准到轮子之上的轮子的。 + +在 Web 世界里,已经成熟到了原生 JS 用量很少的时代了,开发人员大量使用 [Vue](https://github.com/vuejs/vue) 等框架,并且在 Vue 的基础之上,又有更多轮子。 + +![小程序技术始于微信?来看看移动端小程序技术的前世今生!_4.jpg](https://upload-images.jianshu.io/upload_images/19956127-385c778427e63323.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 "小程序技术始于微信?来看看移动端小程序技术的前世今生!_4.jpg") + +当中国的开发人员面临重头开始时,他们感受到效率对比的差距,既然时代已不可阻挡,那就拥抱它。勤劳的中国技术人开始蓬勃地建设起了小程序各种周边技术生态。 + +其中比较重要的是开发框架的迭代,我们看看每个小程序开发框架为什么会诞生、流行和衰落。 + +最初的微信小程序,一片荒蛮,一份文档 + 一个难用的 IDE,很多效率工具比如 npm、预处理器这些都不支持,而这些已经是大型项目离不开的工具。 + +于是,第一个标志性的框架出现了 —— [WePY](https://wepyjs.github.io/wepy-docs/)。 + +WePY 紧随微信小程序在 2017 年发布,原本是腾讯其他部门的一个个人工程师的作品。在那个年代,WePY 有效地解决了小程序不支持 npm、预处理器的痛点,被引爆后,腾讯官方才把这个框架收编到官方的 GitHub 下。 + +![小程序技术始于微信?来看看移动端小程序技术的前世今生!_5.jpg](https://upload-images.jianshu.io/upload_images/19956127-b328fe26697f71d4.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 "小程序技术始于微信?来看看移动端小程序技术的前世今生!_5.jpg") + + +不过 WePY 也面临很多问题,它使用了私有语法,这让它在生态建设上面临很大难度,IDE 着色、语法提示、语法校验、格式化、人员招聘培训等各方面问题制约着它的流行和普及。 + +面对这些问题,人们开始思考,有什么更好的方式,可以复用现有技术生态来快速完善小程序生态? + +这时候下一个重要框架借势诞生,美团前端在 2018 年初开源了 [MPVue](https://mp.weixin.qq.com/s?__biz=MjM5MjAwODM4MA==&mid=2650690209&idx=1&sn=e02487a14a7269e8c647f568838b4233&chksm=bea6237289d1aa64d3e580b63fea8c01678847d25a00ea28d34e71ed4c46c22c446522a590b2&scene=21#wechat_redirect)。 + +MPVue 采用 Vue 语法来开发小程序,通过对 Vue.js 的底层改造,实现了编译到微信小程序。 + +MPVue 良好地借助了 Vue 的技术生态,周边工具如 IDE、校验器、格式化等支持直接复用、人员招聘培训等生态建设压力大幅下降,受到了大量开发者的欢迎。 + +![小程序技术始于微信?来看看移动端小程序技术的前世今生!_6.jpg](https://upload-images.jianshu.io/upload_images/19956127-430b13cad66f115f.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 "小程序技术始于微信?来看看移动端小程序技术的前世今生!_6.jpg") + + +看着熟悉 Vue 的开发者终于有了趁手的轮子,那熟悉 React 的开发者怎会无动于衷? + +京东团队是 React 的重度用户,还自研了 JDreact,于是他们开发了 [Taro 框架](https://taro.aotu.io/),一款基于 React 语法编写小程序的框架。 + +但 Taro 并不是想简单做一个 MPVue 在 React 世界里的翻版,Taro 相比 MPVue,想要解决更多重要问题。 + +Taro 面世较晚,此时微信、支付宝、百度、头条都已发布或宣传了自己的小程序,开发者面临一个多端开发和适配的问题。 + +于是 Taro 率先支持多端开发,它甚至还能发布到 H5 和 App。 + +![小程序技术始于微信?来看看移动端小程序技术的前世今生!_7.jpg](https://upload-images.jianshu.io/upload_images/19956127-aef13ab63197bb67.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 "小程序技术始于微信?来看看移动端小程序技术的前世今生!_7.jpg") + +▲ 京东凹凸实验室 + +当时小程序领域还有一个重要变化,微信开始支持小程序自定义组件。 + +组件是一个成熟框架不可缺的东西,不管是 Vue 还是 React 都有丰富的组件生态。 + +在过去,MPVue 时代,是把 Vue 组件也编译成页面模板,这带来一个很大的性能问题,在复杂页面里(比如长列表)使用组件,更新组件状态会导致整个页面的数据全部从 JS 逻辑层向视图层通讯一次,大量数据通讯会非常卡顿。 + +注意:小程序的逻辑层运行在 V8 或 JSCore 下,和视图层是分离的,通讯阻塞很容易引发性能问题。 + +于是 Taro 把 React 组件编译为新出的微信小程序自定义组件,这种组件在数据更新时,只会更新组件内部的数据,而不是整个页面更新数据,从而大幅减少了数据通信量。 + +这一轮的后浪推前浪很猛,Taro 在性能和多端支持上,都超越了 MPVue。 + +看着 React 阵营取得如此成绩,Vue 阵营自然会继续追击。 + +我们基于 Vue 开发了 uni-app,它实现了自定义组件编译模式,并在算法上做了很多优化。另外,之前 MPVue 对 Vue 的语法支持度不太完善,比如过滤器等不支持,在 uni-app 中我们进行了解决。 + +同样,uni-app 也看到了前浪的其他问题:Taro 虽然迈出了多端的第一步,但多端支持能力比较弱,每个平台仍然各自开发大量代码。核心原因,是Taro 在 H5 端和 App 端,并不是一个完整的小程序技术架构,无法保持最大程度的统一。 + +于是 uni-app 在 App 端,使用了一个技术架构相同的小程序引擎,本身就可以直接运行小程序应用,这个引擎搭配小程序代码打包为 App,开发者一行代码不用改,可以同时发布小程序和 App。 + +当然,其 App 引擎从 Hybrid 应用起家,它提供的 API 要比小程序多很多,因为 App 的需求会比小程序丰富,它还支持把 WebView 渲染引擎替换为 Weex 渲染引擎。 + +之后 uni-app 又发布了 H5 版的小程序引擎,原理与小程序的 PC 模拟器相同,实现了良好的跨 H5 版的发布。于是 uni-app 比较完美地实现了开发一次,7 个平台发布。 + +第一层轮子就这样迅速发展了起来,Web 世界里最成熟的 Vue、React 技术生态被导入了小程序开发生态中。然后轮子之上的轮子开始如火如荼的建设。 + +以 UI 库为例,之前的 UI 库,有 Vue 库、React 库,有 PC 库、H5 库和小程序库,种类繁多,甚至说混乱。 + +比如在 Vue 阵营中,Vant 和 iView 这两个 UI 库,都是同时维护两个版本,它们即有 H5 版,又有小程序版。 + +不止框架作者麻烦,开发者想在多端使用这些 UI 库时,会发现在不同端还需要引入不同的 UI 库,写法都不一样,这让开发者很崩溃。 + +既然已经可以多端开发应用,于是在多端开发的领域里,开始出现轮子之上的轮子,多端 UI 库。 + +首先是 Taro 推出了 Taro UI,实现了 H5 和小程序 UI 库的统一,不过可惜 Taro UI 不支持 App 端。 + +然后 uni-app 推出了 uni UI,这个 UI 库同时支持多家小程序、H5、App。 + +由于 uni-app 和 MPVue 同属 Vue 阵营,它们的组件是互通的。于是这两家联合举办了一场插件大赛,建立了插件市场。 + +在中国的前端开发者领域,有很多和国外不一样的地方:一个是国内有小程序,第二个是国内 Vue 的开发者体量远超过 React 和 Angular。这里面很大的原因,是 Vue.js 的作者尤雨溪,是中国人。 + +![小程序技术始于微信?来看看移动端小程序技术的前世今生!_8.jpg](https://upload-images.jianshu.io/upload_images/19956127-4f5c38ebc16b9637.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 "小程序技术始于微信?来看看移动端小程序技术的前世今生!_8.jpg") + +▲ Vue 和 React 百度指数对比 + +在庞大的 Vue 用户体量支持下,uni-app 和 MPVue 的周边生态迅速发展起来,开发工具、周边轮子、教育培训等生态快速完善。目前在 Vue 阵营下,开发者在 Web 生态下所需的轮子,在多端开发下基本也都有了。 + +短短两年时间,小程序开发生态里几拨迭代,轮子之上的轮子不断涌现,快速进入了成熟期。 + +## 8、本文小结 + +产业还在继续发展,每当底层有重大技术变更时,上层框架世界就会发生新机会。 + +当年 HTML5 标准不统一,浏览器兼容性问题严重,诞生了 jQurey 的机会。而在移动互联网下半场,浏览器兼容已经不再是核心问题,jQurey 的地位被更适合移动互联网的 Vue 替代。 + +**我们不知道未来还会有什么新的框架出世,但我们知道方向:** + +对于开发者而言,总是会向着更高的开发效率、更高的性能、更高的投入产出比前进。 + +对于开发商,目前的小程序,虽然发展了 2 年,但流量增长空间仍然巨大,微信之外,很多超级 App 的势能将逐渐释放,整个小程序产业的日活总量有数亿的提升空间。 + +如果开发商能追上这拨红利,就能获得更多增长。而多端框架的出现,可以帮助开发商更好的把握这拨红利。 + +中国的技术发展,此刻正在经历一个分水岭,从全面的技术进口,到开始建设自己的标准和开发者生态。迟早,会开始向外输出,引领世界的进步。 + +不管中美是否开打贸易战,这一转变都是必须做的事情。 + +中国的移动支付、小程序、5G,很多领域已经走在了全球前面。中国人发明的 Vue 已经在影响全球。 + +虽然还有很多困难仍需克服,但我们每个开发者,都是新时代的见证者,更是新生态的建设者! +原文链接:http://www.52im.net/forum.php?mod=viewthread&tid=2645&ctid=16 diff --git "a/\345\274\200\345\217\221---\345\233\233\345\244\247\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\274\200\345\217\221\345\267\245\345\205\267\346\265\213\350\257\204.md" "b/\345\274\200\345\217\221---\345\233\233\345\244\247\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\274\200\345\217\221\345\267\245\345\205\267\346\265\213\350\257\204.md" new file mode 100644 index 0000000..fe60afd --- /dev/null +++ "b/\345\274\200\345\217\221---\345\233\233\345\244\247\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\274\200\345\217\221\345\267\245\345\205\267\346\265\213\350\257\204.md" @@ -0,0 +1,121 @@ +**一、微信[小程序](https://link.zhihu.com/?target=http%3A//bbs.zhichiwangluo.com/)官方开发工具** + +注意,它只是个工具,而不是一个IDE。官方工具中的代码编辑功能,就是将vscode的代码编辑功能嵌入到工具中,不足以支撑开发。 + +![](https://upload-images.jianshu.io/upload_images/19956127-688cf6358b77a9ae.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +优点 + +因为是官方工具所以有这其它第三方工具有这不可比拟的天然优势,如果不是他代码编辑功能太弱的话。 + +l 官方工具,可调试,可预览 + +l 基本的代码编辑、智能提示、调试等功能都有 + +l 项目管理、创建、手机预览、代码提交审核 + +l 官方维护更新 + +缺点 + +不好的地方也很明显,总体而言是一款工具而不是IDE。糟糕的代码编辑功能,写起代码非常别扭,这是我放弃它的最重要原因。 + +l api提示不全,要一个个查api,影响写代码的速度 + +l 很多必备的快捷键都没有,比如全选关键字、快速复制一行等等 + +l 颜色主题不能选,不喜欢白色风格怎么搞 + +l 没有插件 没有插件 没有插件 重要的事情说三遍 + +评价 + +目前因为需要用到微信web开发工具进行小程序的创建、调试、查看、预览、上传,所以这个工具必不可少。但是代码编辑功能实在太差,推荐使用其它第三方代码编辑工具代替。 + +**二、即速应用** + +适合技术小白的小程序开发工具 + +严格来说,即速应用并不是为专业程序员准备的开发工具,但它绝对是一款功能非常强大的微信小程序制作工具。不懂技术不懂编程的人,一定会爱上即速应用这款工具的。目前只要登录[www.jisuapp.cn](https://link.zhihu.com/?target=http%3A//www.jisuapp.cn/)就能使用这款工具。 + +![](https://upload-images.jianshu.io/upload_images/19956127-1152fc31c316ade9.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +优点 + +l 可视化操作,直接拖拽组件生成页面 + +l 提供大量可套用的模板 + +l 可将代码打包下载,直接对接到小程序的开发工具 + +l 下载下来后的代码可以任意编辑 + +缺点 + +l 电商模板居多,其他类别的模板较少 + +l 复杂的功能仍然需要专业程序员二次开发 + +评价 + +客观地说,即速应用这款微信小程序制作工具非常适合技术小白。因为它相当于把需要代码的部分都帮你做好了,所以不用太头疼技术方面的问题。当然,如果你是程序员,一样可以在它生成的代码基础上进行二次开发的。 + +**三、Sublime Text 3** + +简洁高效的开发工具 + +sublime text 3定位于代码编辑器而不是IDE,在代码提示方面只能算一般般,不过胜在使用起来非常方便。 + +![](https://upload-images.jianshu.io/upload_images/19956127-ecb5bf0c0db845cc.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +优点 + +l 打开文件速度倍儿快、UI简洁大方 + +l 代码编辑体验舒适、高效 + +l 拥有大量插件,针对不同需求基本上能找到对应插件来满足 + +l 第三方开发者开发小程序插件用于代码着色和代码提示 + +缺点 + +l 没有调试,没有预览 + +l 因为是第三方开发者编写的插件,代码提示也不是非常全面 + +评价 + +使用门槛不会太高,可以迅速上手。是但如果想实现一些丰富的功能就会比较吃力了。 + +**四、WebStorm** + +功能繁多的重度开发工具 + +WebStorm网上有个插件,可以实现代码提示,不能做调试和预览,并且属于重度工具,如果你是,可以尝试一下这个工具。 + +![](https://upload-images.jianshu.io/upload_images/19956127-6230fde8b6add046.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +优点 + +l 有插件可以实现代码高亮,代码提示等功能 + +l 有非常成熟和非常丰富的功能 + +l 各种快捷键 + +缺点 + +l 无法调试预览 + +l 功能比较多、比较臃肿 + +评价 + +Webstorm和上述几个工具相比,代码编辑功能较强大。但是需要插件支持才可以开发小程序,而且体积臃肿。 + +**总结** + +这四款工具各有优劣,适用于微信小程序开发过程中的不同情况。到底选择哪一种,就看自己的需求了。如果你想尽快学会开发微信小程序,那么熟练掌握这些开发工具是非常必要的。 +原文作者:朝花吸食 +原文链接:https://zhuanlan.zhihu.com/p/33258938 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217--\345\212\250\347\224\273.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217--\345\212\250\347\224\273.md" new file mode 100644 index 0000000..4dce214 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217--\345\212\250\347\224\273.md" @@ -0,0 +1,79 @@ +#### 起因: + +公司想开发一款微信小程序,1.没有人做过 2.找不到人做。加上我刚进公司,iOS项目一直在计划中,始终没能定下来,就想着先做一款小程序吸引用户进来,最后再开发软件。于是就把我调来开发这款小程序,想着应该不会太难,也就没推辞,把微信小程序文档API全部过一遍,然后一边看文档,一边练习,慢慢就上手了... + +微信有自己开发的专门用来做动画的API,简单点的动画(旋转,平移,缩放)用自带的就可以了,今天我用的是CSS3的一个动画库, + +> [animate.css](https://link.jianshu.com?t=https%3A%2F%2Fdaneden.me%2Fanimate%2F)是一个使用CSS3的[animation](https://link.jianshu.com?t=http%3A%2F%2Fwww.cnblogs.com%2Fxiaohuochai%2Fp%2F5391663.html)制作的动画效果的CSS集合,里面预设了很多种常用的动画,且使用非常简单。 + +稍微动动就可以用的小程序上,简直完美!!! + +![](//upload-images.jianshu.io/upload_images/1482470-22689c2ee96b1857.gif?imageMogr2/auto-orient/strip|imageView2/2/w/360/format/webp) + +# 使用方法: + +###### 1.把`animate.wxss`文件放进工程中,在`app.wxss`中引入 + +``` +@import "文件路径/animate.wxss"; + +``` + +###### 2.需要加动画的标签设置如下 + +``` + +微信小程序 + + +``` + +> 如果需要重复动画效果,只需要加上`infinite` + +``` + +微信小程序 + + +``` + +> **解释**:`animated`必须要写,这样才能真正使用, `bounce`是`animate.wxss`的其中一个动画,你可以选择你需要的动画,当然了,你也可以修改动画的参数来满足项目中的需求!!! + +###### 3.可以通过`*.js`中动态改变动画效果 + +``` +//.wxml + +微信小程序 + + +//.js +/** + * 页面的初始数据 + */ + data: { + animationType:"animated bounce" //初始的动画效果 + } + + //按钮点击 + clickBtn:function(){ + // "animated bounce infinite" + this.setData({ + animationType: "animated " + 动画名称 //别忘了加空格 + }) +} +这样就实现了动画改变,是不是很简单呀!!! + +``` + +###### 4.demo下载地址: + +[https://github.com/aiyakuaile/---animate.css-](https://link.jianshu.com?t=https%3A%2F%2Fgithub.com%2Faiyakuaile%2F---animate.css-) + +###### 5.参考资料 + +> animate.css官网:[https://daneden.me/animate/](https://link.jianshu.com?t=https%3A%2F%2Fdaneden.me%2Fanimate%2F) + + +作者:木语先生 +链接:https://www.jianshu.com/p/b93b9717b87c diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217--\351\200\273\350\276\221\345\261\202\344\270\216\347\225\214\351\235\242\345\261\202.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217--\351\200\273\350\276\221\345\261\202\344\270\216\347\225\214\351\235\242\345\261\202.md" new file mode 100644 index 0000000..12c7700 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217--\351\200\273\350\276\221\345\261\202\344\270\216\347\225\214\351\235\242\345\261\202.md" @@ -0,0 +1,570 @@ +# 一.逻辑层与界面层分离 +小程序开发框架将我们需要完成的编码,划分成了两种类型的编码:逻辑编码(由JavaScript完成,业务数据供给界面事件处理),界面编码(页面结构WXML,页面样式WXSS,展示逻辑层的数据). +# 二.逻辑层的JavaScript +小程序开发中使用到的JavaScript同常规网页开发所使用的JavaScript有所差异,在小程序的开发之中,有很多的.js文件,他们都属于页面的逻辑层,我们知道程序一旦启动就会去执行app.js文件中的代码,我们可以使用console.log()方法来验证. +小程序不是运行在浏览器中,所以没有BOM和DOM对象,但是在小程序只用存在一些特有的全局成员: +``` + 1 //app.js + 2 + 3 console.log("=============================="); + 4 //自定义逻辑代码 + 5 //1.小程序不是运行在浏览器中,所以没有BOM和DOM对象 + 6 console.log(window); //在小程序中无法获取到BOM中定义的成员 + 7 console.log(document); //无法获取到DOM中定义的成员 + 8 //2.小程序的JS有一些额外的成员(全局) + 9 //App 方法:用于定义应用程序实例对象 +10 //Page方法:用于定义页面对象 +11 //getApp方法:用于获取全局应用程序对象,每个小程序都由唯一的应用程序实例 +12 //getCurrentPages:用于获取当前页面的调用栈 +13 //wx对象: 用来提供核心api +14 console.log(wx); +15 //3.小程序的JS是支持CommonJS规范(用于约定这些文件与文件之间是如何组织,相互之间协同的)的 +16 //通过module 和 require来传递通用方法 +17 const foo = require("./utils/foo.js"); +18 foo.say("world"); +19 console.log("=============================="); +20 var obj = { +21 onLaunch: function() { +22 // 展示本地存储能力 +23 var logs = wx.getStorageSync('logs') || [] +24 logs.unshift(Date.now()) +25 wx.setStorageSync('logs', logs) +26 +27 // 登录 +28 wx.login({ +29 success: res => { +30 // 发送 res.code 到后台换取 openId, sessionKey, unionId +31 } +32 }) +33 // 获取用户信息 +34 wx.getSetting({ +35 success: res => { +36 if (res.authSetting['scope.userInfo']) { +37 // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 +38 wx.getUserInfo({ +39 success: res => { +40 // 可以将 res 发送给后台解码出 unionId +41 this.globalData.userInfo = res.userInfo +42 +43 // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 +44 // 所以此处加入 callback 以防止这种情况 +45 if (this.userInfoReadyCallback) { +46 this.userInfoReadyCallback(res) +47 } +48 } +49 }) +50 } +51 } +52 }) +53 }, +54 globalData: { +55 userInfo: null +56 }, +57 //自定义成员方法 +58 foo: function() { +59 console.log("自定义成员方法"); +60 } +61 }; +62 //调用了一个APP方法(全局方法) +63 App(obj); +64 //调用App方法的作用是用来创建应用程序实例对象 +65 //定义应用程序的生命周期事件 +``` +``` +1 function say(msg){ +2 console.log("hello " + msg); +3 } +4 +5 // 导出say()方法 +6 module.exports = { +7 say: say +8 } +9 //在标准的COmmonJS规范中还支持exports.say 来导出,但是在小程序当中是不支持的,只支持module.exports +``` +``` + 1 //index.js + 2 //获取应用实例 + 3 //完成页面的逻辑,包括功能的实现 + 4 const app = getApp() + 5 + 6 Page({ + 7 data: { + 8 motto: 'Hello World', + 9 userInfo: {}, +10 hasUserInfo: false, +11 canIUse: wx.canIUse('button.open-type.getUserInfo') +12 }, +13 //事件处理函数 +14 bindViewTap: function() { +15 wx.navigateTo({ +16 url: '../logs/logs' +17 }) +18 }, +19 onLoad: function () { +20 if (app.globalData.userInfo) { +21 this.setData({ +22 userInfo: app.globalData.userInfo, +23 hasUserInfo: true +24 }) +25 } else if (this.data.canIUse){ +26 // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 +27 // 所以此处加入 callback 以防止这种情况 +28 app.userInfoReadyCallback = res => { +29 this.setData({ +30 userInfo: res.userInfo, +31 hasUserInfo: true +32 }) +33 } +34 } else { +35 // 在没有 open-type=getUserInfo 版本的兼容处理 +36 wx.getUserInfo({ +37 success: res => { +38 app.globalData.userInfo = res.userInfo +39 this.setData({ +40 userInfo: res.userInfo, +41 hasUserInfo: true +42 }) +43 } +44 }) +45 } +46 }, +47 getUserInfo: function(e) { +48 console.log(e) +49 app.globalData.userInfo = e.detail.userInfo +50 this.setData({ +51 userInfo: e.detail.userInfo, +52 hasUserInfo: true +53 }) +54 }, +55 onShow: function () { +56 //在每次该界面唤醒时,获取当前页面的调用栈: +57 console.log(getCurrentPages()); +58 console.log("当前调用栈中的页面数量: " + getCurrentPages()); +59 } +60 +61 }) +``` +``` + 1 // pages/demo/demo.js + 2 + 3 //获取当前小程序对象实例 + 4 var app = getApp(); + 5 Page({ + 6 + 7 /** + 8 * 页面的初始数据 + 9 */ +10 data: { +11 +12 }, +13 +14 /** +15 * 生命周期函数--监听页面加载 +16 */ +17 onLoad: function (options) { +18 app.foo(); +19 +20 }, +21 +22 /** +23 * 生命周期函数--监听页面初次渲染完成 +24 */ +25 onReady: function () { +26 +27 }, +28 +29 /** +30 * 生命周期函数--监听页面显示 +31 */ +32 onShow: function () { +33 //在每次该界面唤醒时,获取当前页面的调用栈: +34 console.log(getCurrentPages()); +35 console.log("当前调用栈中的页面数量: " + getCurrentPages()); +36 console.log(getCurrentPages()[getCurrentPages().length - 1] == this); +37 }, +38 +39 /** +40 * 生命周期函数--监听页面隐藏 +41 */ +42 onHide: function () { +43 +44 }, +45 +46 /** +47 * 生命周期函数--监听页面卸载 +48 */ +49 onUnload: function () { +50 +51 }, +52 +53 /** +54 * 页面相关事件处理函数--监听用户下拉动作 +55 */ +56 onPullDownRefresh: function () { +57 +58 }, +59 +60 /** +61 * 页面上拉触底事件的处理函数 +62 */ +63 onReachBottom: function () { +64 +65 }, +66 +67 /** +68 * 用户点击右上角分享 +69 */ +70 onShareAppMessage: function () { +71 +72 } +73 }) +``` +# 三.界面层--数据绑定 +在程序的开发过程中,界面层提供一种模板机制,可以借助一种特殊的语法来完成数据的绑定,将动态的数据绑定到模板当中,最近将嵌入过后的数据显示到界面中,小程序中使用的是Mustache 语法(双大括号)语法: +``` +1 + 2 + 3 + 7 + 8 {{ message }} + 9 {{ person.name }} : {{ person.age }} +10 +``` +``` + 1 // pages/demo/demo.js + 2 + 3 Page({ + 4 //为页面提供数据,界面和逻辑之间的桥梁 + 5 data:{ + 6 message:"hello world", + 7 person:{ + 8 name: "张三", + 9 age:25 +10 } +11 } +12 }) +``` +--数据绑定语法补充,除了在页面标签的内部我们会使用Mustache语法进行输出,在标签的内部,我们也可以使用Mustache语法: +``` + 1 + 2 + 3 + 7 + 8 {{ message }} + 9 {{ person.name }} : {{ person.age }} +10 +14 +15 +16 {{ 'hello' }} +17 {{ 111 }} +18 {{ 111 + 222 }} +19 {{ 111 < 222 ? 'yes' : 'no' }} +20 {{ true }} +21 +24 复选框1 +25 复选框2 +26 +``` +# 四.列表渲染 +在逻辑层中,很多的情况下都会是一个数组类型的数据(列表数据),那么此时在我们的界面层中就需要使用到列表渲染: +``` +1 + 4 复选框1 + 5 复选框2 + 6 + 7 + 8 +20 +30 +31 {{ bbb + 1 }}: +32 +33 {{ item.name }} {{ aaa.name }} +34 +35 +36 +37 +38 +39 +40 {{ i }} * {{ j }} = {{ i * j }} +41 +42 +43 +44 +45 +``` +# 五.事件处理 +``` +1 +3 +``` +``` +1 buttonTapHandle: function(e){ +2 console.log("点击按钮打印此条."); +3 // console.dir()将一个对象以树状的形式打印到控制台,便于我们调试复杂对象 +4 console.dir(e); +5 } +``` +# 六.事件冒泡 +``` +1 +4 +5 +6 +``` +``` +1 innerHandler: function(){ +2 console.log("触发内部事件"); +3 }, +4 outerHandler: function(){ +5 console.log("触发外部事件"); +6 } +``` +# 七.事件传参 +``` +1 +8 +``` +``` +1 handleWithParm(e){ +2 console.log(e); //获取当前的点击元素 +3 console.log(e.target.dataset); //获取元素上所有data-[xxx]属性的集合 +4 } +``` +# 八.单向数据流 +``` +1 +4 +5 +6 {{ inputMessage }} +7 +``` +``` + 1 inputHandler: function(e) { + 2 //e.detail.value 获取到当前输入的值 + 3 console.log(e.detail.value); + 4 //小程序中的数据绑定,本质上是一次绑定,在绑定完成之后,并不会去监视数据的变化.如果想要得到此次的变化,那么就需要使用setData的方法进行改变 + 5 //setData是用来改变data数据的,与直接赋值区别在于setData可以通知界面作出变化,而直接赋值的话没有办法实现这一点(早期的JS无法实现) + 6 this.setData({ + 7 inputMessage: "您输入的内容: " + e.detail.value + 8 }) + 9 console.log(this.data.message); +10 } +``` +# 九.登录页面案例 +``` + 1 + 2 + 3 + 4 + 6 + 8 + 9 +10 +11 +12 +13 +``` +``` + 1 // pages/login/login.js + 2 /* 实现登录界面 + 3 1. 设计数据的结构(data属性) + 4 2. 将数据绑定到指定的元素上 + 5 */ + 6 Page({ + 7 data: { + 8 username: "", + 9 password: "" +10 }, +11 //用于处理登录按钮点击的事件 +12 buttonLogin: function() { +13 console.log("执行登录事件"); +14 }, +15 //用于处理注册按钮点击的事件 +16 buttonRegister: function() { +17 //1. 首先需要知道用户输入了什么 +18 console.log(this.data.username + " " + this.data.password); +19 //2. 根据用户输入的值去判断 +20 //3. 根据判断的结果做出响应 +21 console.log("执行注册事件"); +22 }, +23 //用户输入用户名 +24 usernameChangeHandler: function(e) { +25 this.setData({ +26 username: e.detail.value +27 }) +28 }, +29 //用户输入密码 +30 passwordChangeHandler: function(e) { +31 this.setData({ +32 password: e.detail.value +33 }) +34 } +35 }) +``` +# 十.抽象共同的事件处理函数 +如我在我们的代码之中为每一个input标签都增加一个事件绑定函数,那么在我们的代码之中,将会存在很多的重复代码,为了避免这样的的情况,我们可以抽象共同的事件处理函数: +``` +1 + 2 + 3 + 4 + 6 + 8 + 9 +10 +11 +12 +13 +``` +``` +1 // pages/login/login.js + 2 /* 实现登录界面 + 3 1. 设计数据的结构(data属性) + 4 2. 将数据绑定到指定的元素上 + 5 */ + 6 Page({ + 7 data: { + 8 username: "", + 9 password: "" +10 }, +11 //用于处理登录按钮点击的事件 +12 buttonLogin: function() { +13 console.log(this.data.username + " " + this.data.password); +14 console.log("执行登录事件"); +15 }, +16 //用于处理注册按钮点击的事件 +17 buttonRegister: function() { +18 //1. 首先需要知道用户输入了什么 +19 console.log(this.data.username + " " + this.data.password); +20 //2. 根据用户输入的值去判断 +21 //3. 根据判断的结果做出响应 +22 console.log("执行注册事件"); +23 }, +24 //用户输入用户名 +25 // usernameChangeHandler: function(e) { +26 // this.setData({ +27 // username: e.detail.value +28 // }) +29 // }, +30 //用户输入密码 +31 // passwordChangeHandler: function(e) { +32 // this.setData({ +33 // password: e.detail.value +34 // }), +35 // console.log(e); +36 // } +37 //抽象上述两个方法,完成事件 +38 inputChangeHandler: function(e) { +39 var key = e.target.dataset.name; +40 var value = e.detail.value; +41 var changed = {}; +42 changed[key] = value; +43 this.setData(changed); +44 } +45 }) +``` +--除此之外,我们还可以使用表单的方式来进行数据的接收,这样可以免除这一些列复杂的操作: +``` +1 + 2 + 4 + 6 + 7 + 8 + 9 +10 +``` +``` +1 //使用表单提交的方式来完成数据接收 +2 loginSubmit: function(e){ +3 console.log(e.detail.value); +4 } +``` +# 十一.条件渲染 +``` + 1 + 2 + 3 + 4 + 5 面板中显示的内容 + 6 面板中显示的内容 + 7 面板中显示的内容 + 8 + 9 +11 +12 面板中显示的内容1 +13 面板中显示的内容2 +14 面板中显示的内容3 +15 +16 +19 +24 +``` +# 十二.界面层(WXSS vs CSS) +rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。即将所有设备都使用rpx为750设置为撑满屏幕宽度. +``` +1 .demo { +2 width: 750rpx; +3 height: 200px; +4 background-color: red; +5 } +``` +原文作者:灰色天空_graySky +原文链接:https://www.cnblogs.com/skykuqi/p/11735404.html diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217-\345\274\271\345\207\272\345\257\271\350\257\235\346\241\206.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217-\345\274\271\345\207\272\345\257\271\350\257\235\346\241\206.md" new file mode 100644 index 0000000..75bc52d --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217-\345\274\271\345\207\272\345\257\271\350\257\235\346\241\206.md" @@ -0,0 +1,100 @@ +什么是对话框 +对话框是微信小程序的,界面交互的一种方式,其他的还有toast等。 +# wx.showModal(Object object) + +显示模态对话框 + +## [](https://developers.weixin.qq.com/miniprogram/dev/api/ui/interaction/wx.showModal.html#参数)参数 + +### [](https://developers.weixin.qq.com/miniprogram/dev/api/ui/interaction/wx.showModal.html#Object-object)Object object +![](https://upload-images.jianshu.io/upload_images/19956127-c5fc9f127c281157.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +#### object.success 回调函数 + +##### [](https://developers.weixin.qq.com/miniprogram/dev/api/ui/interaction/wx.showModal.html#参数-2)参数 + +###### [](https://developers.weixin.qq.com/miniprogram/dev/api/ui/interaction/wx.showModal.html#Object-res)Object res +![](https://upload-images.jianshu.io/upload_images/19956127-96d771b11fe222fa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +示例代码 +``` +wx.showModal({ + title: '提示', + content: '这是一个模态弹窗', + success (res) { + if (res.confirm) { + console.log('用户点击确定') + } else if (res.cancel) { + console.log('用户点击取消') + } + } +}) + +``` + +## [](https://developers.weixin.qq.com/miniprogram/dev/api/ui/interaction/wx.showModal.html#注意)注意 + +* Android 6.7.2 以下版本,点击取消或蒙层时,回调 fail, errMsg 为 "fail cancel"; +* Android 6.7.2 及以上版本 和 iOS 点击蒙层不会关闭模态弹窗,所以尽量避免使用「取消」分支中实现业务逻辑 +怎么使用 +下面是一个官方的使用方式,用触发时间来触发即可 +``` + + + +``` +``` +showWindows: function() { +wx.showModal({ + title: '提示', + content: '这是一个模态弹窗', + success (res) { + if (res.confirm) { + console.log('用户点击确定') + } else if (res.cancel) { + console.log('用户点击取消') + } + } +}) +} +``` +如何把信息传到弹出界面 +在wxml文件里面 {{data.showWindows.Content}} 把内容传上去即可 +``` + + + + + +``` +``` +//获取应用实例 +var app = getApp() +Page({ + data: { + modalHidden:true,//是否隐藏对话框 + }, + //事件处理函数 + bindViewTap: function() { + this.setData({ + modalHidden:!this.data.modalHidden + }) + + }, + //确定按钮点击事件 + modalBindaconfirm:function(){ + this.setData({ + modalHidden:!this.data.modalHidden, + }) + }, + //取消按钮点击事件 + modalBindcancel:function(){ + this.setData({ + modalHidden:!this.data.modalHidden, + }) + }, +}) +``` +原文作者:叉叉敌 +原文链接:https://blog.csdn.net/weixin_42514606/article/details/99250768 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\270\213\346\213\211\345\210\267\346\226\260-\344\270\212\346\213\211\345\212\240\350\275\275\346\233\264\345\244\232.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\270\213\346\213\211\345\210\267\346\226\260-\344\270\212\346\213\211\345\212\240\350\275\275\346\233\264\345\244\232.md" new file mode 100644 index 0000000..d8ee2e5 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\270\213\346\213\211\345\210\267\346\226\260-\344\270\212\346\213\211\345\212\240\350\275\275\346\233\264\345\244\232.md" @@ -0,0 +1,83 @@ +查看文档,在用page()函数注册页面的时候有这样的两个对象参数用户判断用户在最顶部下拉和到达最底部。 +![](https://upload-images.jianshu.io/upload_images/19956127-6451dd1806ea043f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +在小程序里,用户顶部下拉是默认禁止的,我们需要把他设置为启用,在app.json中的设置对所有页面有效,在单独页面设置则对当前页面有效; + +看一下json文件 +``` +"enablePullDownRefresh": true, +``` +注意这里的true是布尔型而不是字符; +![](https://upload-images.jianshu.io/upload_images/19956127-30c6b4b4f987a8de.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +有同学说设置完之后可以下拉,但是看不到图标; + +在app.json中这样设置; +![](https://upload-images.jianshu.io/upload_images/19956127-5854f8402daf4eac.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +这样下拉之后就可以看到了; + +每个页面生成的时候已经默认为我们设置了前面提到的onPullDownRefresh函数和onReachBottom函数 + +直接上代码: + +page为全局变量,用在在后面的加载请求,这里要和编写数据接口的同事讨论好请求; +``` + // 下拉刷新 + onPullDownRefresh: function () { + // 显示顶部刷新图标 + wx.showNavigationBarLoading(); + var that = this; + wx.request({ + url: 'https://xxx/?page=0', + method: "GET", + header: { + 'content-type': 'application/text' + }, + success: function (res) { + that.setData({ + moment: res.data.data + }); + console.log(that.data.moment); + // 隐藏导航栏加载框 + wx.hideNavigationBarLoading(); + // 停止下拉动作 + wx.stopPullDownRefresh(); + } + }) + }, + ``` +上拉加载更多: + ``` +/** + * 页面上拉触底事件的处理函数 + */ + onReachBottom: function () { + var that = this; + // 显示加载图标 + wx.showLoading({ + title: '玩命加载中', + }) + // 页数+1 + page = page + 1; + wx.request({ + url: 'https://xxx/?page=' + page, + method: "GET", + // 请求头部 + header: { + 'content-type': 'application/text' + }, + success: function (res) { + // 回调函数 + var moment_list = that.data.moment; + const oldData = that.data.moment; + that.setData({ + moment:oldData.concat(res.data.data) + }) + // 隐藏加载框 + wx.hideLoading(); + } + }) + + }, + ``` +完成。 +原文作者:ruff1996 +原文链接:https://blog.csdn.net/ruffaim/article/details/78839214 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213wx-if\350\247\206\345\233\276\345\261\202\347\232\204\346\235\241\344\273\266\346\270\262\346\237\223-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21010\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213wx-if\350\247\206\345\233\276\345\261\202\347\232\204\346\235\241\344\273\266\346\270\262\346\237\223-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21010\357\274\211.md" new file mode 100644 index 0000000..f42365b --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213wx-if\350\247\206\345\233\276\345\261\202\347\232\204\346\235\241\344\273\266\346\270\262\346\237\223-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21010\357\274\211.md" @@ -0,0 +1,243 @@ +![](https://upload-images.jianshu.io/upload_images/19956127-d9afef6be99efec2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +使用wx:if进行视图层的条件渲染 + +**示例:** +wxml:使用view +``` + + + + + + + + +     + + + + + +     + + +``` +  +wxss: +``` +/**index.wxss**/ + +.bg_black { + +  height: 200rpx; + +  background: lightskyblue; + +} + +.bg_red { + +  height: 200rpx; + +  background: lightpink; + +} +``` +  +js: +``` +// index.js + +Page({ + +  data: { + +    boolean:false + +  }, + +  EventHandle: function(){ + +    var bol = this.data.boolean; + +    this.setData({ + +      boolean: !bol + +    }) + +  } + +}) +``` +**运行:** +![](https://upload-images.jianshu.io/upload_images/19956127-2658eeef66f3e5c8.gif?imageMogr2/auto-orient/strip) + +**续上:** + +把上面标注绿色部分的view改成block + +**wxml:使用block** +``` + + + + + + + + +     + + + + + +     + + +``` +运行: +![](https://upload-images.jianshu.io/upload_images/19956127-42428cab327f5ae5.gif?imageMogr2/auto-orient/strip) + +**续上:** + +增加一个wx:for做列表渲染 + +**wxml:** +``` + + + + + + + + +    内容:{{item}} + + + + + +    无内容 + + +``` +  +**index.js:** +``` +// index.js + +Page({ + +  data: { + +    boolean:false, + +    arr: [1,2,3] + +  }, + +  EventHandle: function(){ + +    var bol = this.data.boolean; + +    this.setData({ + +      boolean: !bol + +    }) + +  } + +}) +``` +**运行:** + +编辑错误。 +![](https://upload-images.jianshu.io/upload_images/19956127-c1fa842b158d6234.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +原因是wx:if不能与wx:for共用在一个组件上! + +**续上:** + +wx:if和wx:for必须分开使用 + +**wxml:** +``` + + + + + + + + +     + +        内容:{{item}} + +     + + + + + +    无内容 + + +``` +**wxss:** +``` +/**index.wxss**/ + +.bg_black { + +  height: 200rpx; + +  background: lightskyblue; + +} + +.bg_red { + +  height: 200rpx; + +  background: lightpink; + +} +``` +**index.js:** +``` +// index.js + +Page({ + +  data: { + +    boolean:false, + +    arr: [1,2,3] + +  }, + +  EventHandle: function(){ + +    var bol = this.data.boolean; + +    this.setData({ + +      boolean: !bol + +    }) + +  } + +}) +``` +运行: +![](https://upload-images.jianshu.io/upload_images/19956127-ff9da8a88f5260c6.gif?imageMogr2/auto-orient/strip) + +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/55049118 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213wxss-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21013\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213wxss-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21013\357\274\211.md" new file mode 100644 index 0000000..1644c0a --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213wxss-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21013\357\274\211.md" @@ -0,0 +1,56 @@ +WXSS(WeiXin Style Sheet)与CSS对应,用于描述页面的样式。 + + + +# 特性 + +内联样式: +组件的 style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进style中,以免影响渲染速度。 + +**选择器** +对于常用的选择器,目前支持的选择器有: +![](https://upload-images.jianshu.io/upload_images/19956127-031ceea2ce50f733.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +注:绿色背景色行表示官方文档中没有说明,但经个人亲测后确定也支持的选择器。 + + + +目前不支持的选择器有: +![](https://upload-images.jianshu.io/upload_images/19956127-871d8ebc28c33b22.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +**注意:** +如之前提到,页面的顶层是节点,所以作用于整个页面的样式或修改顶层节点样式请使用page选择器。 +小程序目前不支持Media Query。 + +**扩展的特性** +![](https://upload-images.jianshu.io/upload_images/19956127-98142135b7252bba.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +建议:开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准。 + +注意: 由于数值较小时渲染时会存在四舍五入的情况,在较小屏幕上差距会很大,所以要求精确而较小的视图内容需避免使用此单位。 + + + +样式导入 +用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用;表示语句结束。 + +**示例:** + +index.wxml: +![](https://upload-images.jianshu.io/upload_images/19956127-282179a6e757e975.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +index.wxss: +![](https://upload-images.jianshu.io/upload_images/19956127-11edd9f8754b42d5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +**运行:** + +选择iphone 4手机查看 +![](https://upload-images.jianshu.io/upload_images/19956127-5904d59fafc38ec2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +选择iphone 6 Plus手机查看 +![](https://upload-images.jianshu.io/upload_images/19956127-3e3530f9724d3acb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/55050052 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\344\270\212\346\213\211\345\212\240\350\275\275\345\222\214\344\270\213\346\213\211\345\210\267\346\226\260-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21018\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\344\270\212\346\213\211\345\212\240\350\275\275\345\222\214\344\270\213\346\213\211\345\210\267\346\226\260-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21018\357\274\211.md" new file mode 100644 index 0000000..496152f --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\344\270\212\346\213\211\345\212\240\350\275\275\345\222\214\344\270\213\346\213\211\345\210\267\346\226\260-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21018\357\274\211.md" @@ -0,0 +1,71 @@ +在微信小程序上实现下拉刷新、上拉加载的效果 + +使用系统提供的onPullDownRefresh、onReachBottom这2个事件, + +前提需要在app.json或page.json配置文件中设置,才能使用。 + +app.json是全应用的页面都可以使用该事件,page.json则只是对应的页面才可以使用。 + +![](https://upload-images.jianshu.io/upload_images/19956127-200cf97d8b848d7b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +**示例:** + +app.json: + +在app.json文件里设置window属性 + +``` +{ + "window":{ +"enablePullDownRefresh": true + } +} +``` + + +**page.json:** + +在page.json文件里直接设置属性  +``` +{ + "enablePullDownRefresh": true +} +``` +  + +**示例:** +可以结合导航栏loading显示正在加载的效果 +``` +Page({ + data: { + pageNum: 1, // 设置加载的第几次,默认是第一次 + isFirstLoad: true, // 用于判断List数组是不是空数组,默认true,空的数组 + hasMore: false, // “加载更多” + }, + // 下拉刷新 + onPullDownRefresh: function () { + // 显示导航栏loading + wx.showNavigationBarLoading(); + // 调用接口加载数据 + this.loadData(); + // 隐藏导航栏loading + wx.hideNavigationBarLoading(); + // 当处理完数据刷新后,wx.stopPullDownRefresh可以停止当前页面的下拉刷新 + wx.stopPullDownRefresh(); + }, + // 上拉加载 + onReachBottom(e) { + let that = this; + if (that.data.hasMore) { + that.setData({ + pageNum: that.data.pageNum + 1, // 每次触发上拉事件,把pageNum+1 + isFirstLoad: false // 触发到上拉事件,把isFirstLoad设为为false + }); + + that.loadData(); + } + }, +}) +``` +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/55215104 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\344\273\277android-fragment\344\271\213\345\217\257\346\273\221\345\212\250\347\232\204\345\272\225\351\203\250\345\257\274\350\210\252\346\240\217\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2104\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\344\273\277android-fragment\344\271\213\345\217\257\346\273\221\345\212\250\347\232\204\345\272\225\351\203\250\345\257\274\350\210\252\346\240\217\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2104\357\274\211.md" new file mode 100644 index 0000000..95c8f72 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\344\273\277android-fragment\344\271\213\345\217\257\346\273\221\345\212\250\347\232\204\345\272\225\351\203\250\345\257\274\350\210\252\346\240\217\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2104\357\274\211.md" @@ -0,0 +1,249 @@ +底部3-5个选项的底部导航栏,目前在移动端上是主流布局之一 + +因此腾讯官方特地做了,可以通过设置,就可以做出了一个底部的导航栏 + +相关教程:http://blog.csdn.net/michael_ouyang/article/details/55045300 + +但是通过设置的这个底部的导航栏,功能上比较固定,它必须要设置与它对应的一个页面,而且并不能滑动。 + +在业务上,有时候会比较限制,并不能完全满足所需。 + + +又例如早前有人拿着UI稿问我,这种广告轮播图的样式,在小程序能不能实现呢? + +我当时没有想了下,还不是很确定,因为小程序的轮播图的那几个小点点实在比较普通,样式单一。 + +因此特意写了一篇自定义轮播图的文章 + +链接:http://blog.csdn.net/michael_ouyang/article/details/58591232 + +因此自定义就有这个必要性 + +### 下面介绍这个仿android fragment可滑动的底部导航栏如何实现 + +项目最终效果图: + +![](https://upload-images.jianshu.io/upload_images/19956127-00625c2ca21b2ad9.gif?imageMogr2/auto-orient/strip) + + +**wxml:** +``` + + + + + + + + + + + {{item}} + + + + + + + + + + + + + + + {{item}} + + + + + + + + + + + + + + + {{item}} + + + + + + + + + + + + + + + {{item}} + + + + + + + + + + + + frag01 + + + + frag02 + + + + frag03 + + + + frag04 + + +``` + +**wxss:** +``` +/*swiper*/ +.swiper-box { + display: block; + height: 100%; + width: 100%; + overflow: hidden; +} +.hot-box { + display: block; + height: 100%; + font-family: Helvetica; +} +/* list */ +.themes-list { + background: #fff; + display: block; + margin-bottom: 20px; +} +.themes-list-box { + display: block; + position: relative; + padding: 16px 20px; + border-bottom: 1px solid #f2f2f2; +} +.themes-list-main { + margin-left: 1px; +} +.themes-list-name { + font-size: 14px; + color: #444; + height: 20px; + line-height: 20px; + overflow: hidden; +} +/*tab*/ +.swiper-tab { + height: 50px; + background: #fff; + display: flex; + position: relative; + z-index: 2; + flex-direction: row; + justify-content: center; + align-items: center; + border-top: 1px solid #ccc; +} +.swiper-tab-list { + margin: 0 20px; + padding: 0 4px; + font-size: 28rpx; + font-family: Helvetica; +} +.active { + /*border-bottom: 1px solid #FFCC00;*/ + color: #FFCC00; +} +.swiper-tab-img { + text-align: center; +} +.img { + width:23px; + height: 23px; +} +``` + +**js:** +``` +Page( { + data: { + winWidth: 0, + winHeight: 0, + currentTab: 0, + datalists : [ + "习近平主持中央财经领导小组第十五次会议", + "李克强打叉的“万里审批图”成历史", + "新疆自治区举行反恐维稳誓师大会", + "朝鲜代表团抵达马来西亚处理金正男遇害案", + "宝马车祸案肇事者二次精神鉴定:案发为精神病状态", + "朝鲜代表团抵达马来西亚处理金正男遇害案", + "宝马车祸案肇事者二次精神鉴定:案发为精神病状态", + "朝鲜代表团抵达马来西亚处理金正男遇害案", + "宝马车祸案肇事者二次精神鉴定:案发为精神病状态", + "朝鲜代表团抵达马来西亚处理金正男遇害案", + "宝马车祸案肇事者二次精神鉴定:案发为精神病状态", + "砸锅卖铁!索尼是在走向毁灭 还是在奔向新生?" + ], + reslists:["hello","thank you for your read","if u feel good","can u give me good?"], + iconlists:[ + {normal:"../../images/wp.png",focus:"../../images/wpselect.png"}, + {normal:"../../images/ss.png",focus:"../../images/ssselect.png"}, + {normal:"../../images/hc.png",focus:"../../images/hcselect.png"}, + {normal:"../../images/my.png",focus:"../../images/myselect.png"}, + ] + }, + onLoad: function( options ) { + var that = this; + //获取系统信息 + wx.getSystemInfo( { + success: function( res ) { + that.setData( { + winWidth: res.windowWidth, + winHeight: res.windowHeight + }); + } + }); + }, + /** + * 滑动切换tab + */ + bindChange: function( e ) { + var that = this; + that.setData( { currentTab: e.detail.current }); + }, + /** + * 点击切换tab + */ + swichNav: function( e ) { + console.log(e) + var that = this; + if( this.data.currentTab === e.currentTarget.dataset.current ) { + //点击的是同一个,则不操作 + return false; + } else { + that.setData( { + currentTab: e.currentTarget.dataset.current + }) + } + + } +}) +``` +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/60333699 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\344\273\277\346\267\230\345\256\235\345\210\206\347\261\273\345\205\245\345\217\243-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2102\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\344\273\277\346\267\230\345\256\235\345\210\206\347\261\273\345\205\245\345\217\243-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2102\357\274\211.md" new file mode 100644 index 0000000..ea7a376 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\344\273\277\346\267\230\345\256\235\345\210\206\347\261\273\345\205\245\345\217\243-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2102\357\274\211.md" @@ -0,0 +1,108 @@ +分类入口,已经成为了商城项目必须的布局之一,这里以仿照淘宝的分类入口来做案例 + +下图红框部分,就是本文重点讲解部分,另外本文并没有写点击某个入口跳转页面。 + +如需学习页面跳转的同学,可以参考此文 + +[微信小程序的页面跳转和参数传递 —— 微信小程序教程系列(6)](https://www.jianshu.com/p/4a6eb83dc8d1) +![](https://upload-images.jianshu.io/upload_images/19956127-58210537a79f416b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +**页面分析:** + +使用for循环遍历所有项,插入页面,页面中的项使用左浮动,并使用百分比布局,设置20%的宽度每一项。 + +这样满5个item后,自动排在下一行 + + +**wxml:** +``` + + + + + {{menu.descs[index]}} + + + + +wxss: + +.menu-wrp { + width:100%; + margin-top:20rpx; +} +.menu-wrp:after{ + content:""; + display:block; + clear:both; +} + +.menu-list{ + float:left; + width:20%; + box-sizing: border-box; + padding-bottom:10px; +} + +.menu-img{ + width:120rpx; + height:84rpx; + display:block; + margin:0 auto; + margin-bottom:5px; +} +.menu-desc{ + background-color:#ffffff; + color:#333333; + width:100%; + text-align: center; + display:block; + font-size:12px; +} +.gap-1,.gap-2{ + width:100%; + height:10rpx; + background:rgb(238, 238, 238); +} +``` + +**js:** + +这里的准备的数据,我直接写在js中,同学们可以改编成通过访问接口来获取 +``` +Page({ + data: { +//准备数据 + menu:{ + imgUrls:[ + 'http://gw.alicdn.com/tps/i2/TB19BluIVXXXXX6XpXXN4ls0XXX-183-129.png?imgtag=avatar', + 'http://gw.alicdn.com/tps/TB1FDOHLVXXXXcZXFXXXXXXXXXX-183-129.png?imgtag=avatar', + 'http://gw.alicdn.com/tps/TB1PlmNLVXXXXXEXFXXXXXXXXXX-183-129.png?imgtag=avatar', + 'http://gw.alicdn.com/tps/TB1RN0HMFXXXXXNXpXXXXXXXXXX-183-129.png?imgtag=avatar', + 'http://gw.alicdn.com/tps/TB1exaOLVXXXXXeXFXXXXXXXXXX-183-129.png?imgtag=avatar', + 'http://img.alicdn.com/tps/TB1GzMJLXXXXXXoXXXXXXXXXXXX-183-129.png', + 'http://gw.alicdn.com/tps/i3/TB1Ewu2KVXXXXXkapXXN4ls0XXX-183-129.png', + 'http://gw.alicdn.com/tps/TB1cniBJpXXXXataXXXXXXXXXXX-183-129.png?imgtag=avatar', + 'http://img.alicdn.com/tps/TB1caopLVXXXXaDaXXXXXXXXXXX-183-129.png', + 'http://gw.alicdn.com/tps/i1/TB1c1FMIpXXXXawXpXXN4ls0XXX-183-129.png?imgtag=avatar' + ], + descs:[ + '聚划算', + '天猫', + '天猫国际', + '外卖', + '天猫超市', + '充值中心', + '阿里旅行', + '领金币', + '到家', + '分类' + ] + } + } + +}) +``` +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/70178207 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\344\276\247\346\240\217\345\210\206\347\261\273-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2101\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\344\276\247\346\240\217\345\210\206\347\261\273-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2101\357\274\211.md" new file mode 100644 index 0000000..511b328 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\344\276\247\346\240\217\345\210\206\347\261\273-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2101\357\274\211.md" @@ -0,0 +1,197 @@ +在商场项目中,一般都会有分类页面。 + +分类页面可以给用户快速找到相关的商品,下面以侧栏分类为例,如下图 + +![](https://upload-images.jianshu.io/upload_images/19956127-79e5412215a1dfd2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +**布局分析:** + +<主盒子> + +<左盒子> + +<右盒子> + + + +左盒子使用标准流 + +右盒子使用绝对定位(top、right) +![](https://upload-images.jianshu.io/upload_images/19956127-89ecdc8c3415b974.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +**wxml:** +``` + + + + + + + + {{item.tree.desc}} + + + + + + + + + + + + + + + + + + + + + {{item.tree.desc}} + + + {{item.tree.desc2}} + + + + + + + 暂无数据 + + +``` + +**wxss:** +``` +page{ + background: #f5f5f5; +} +/*总体主盒子*/ +.container { + position: relative; + width: 100%; + height: 100%; + background-color: #fff; + color: #939393; +} + +/*左侧栏主盒子*/ +.nav_left{ + /*设置行内块级元素(没使用定位)*/ + display: inline-block; + width: 25%; + height: 100%; + /*主盒子设置背景色为灰色*/ + background: #f5f5f5; + text-align: center; +} +/*左侧栏list的item*/ +.nav_left .nav_left_items{ + /*每个高30px*/ + height: 30px; + /*垂直居中*/ + line-height: 30px; + /*再设上下padding增加高度,总高42px*/ + padding: 6px 0; + /*只设下边线*/ + border-bottom: 1px solid #dedede; + /*文字14px*/ + font-size: 14px; +} +/*左侧栏list的item被选中时*/ +.nav_left .nav_left_items.active{ + /*背景色变成白色*/ + background: #fff; +} + +/*右侧栏主盒子*/ +.nav_right{ + /*右侧盒子使用了绝对定位*/ + position: absolute; + top: 0; + right: 0; + flex: 1; + /*宽度75%,高度占满,并使用百分比布局*/ + width: 75%; + height: 100%; + padding: 10px; + box-sizing: border-box; + background: #fff; +} +/*右侧栏list的item*/ +.nav_right .nav_right_items{ + /*浮动向左*/ + float: left; + /*每个item设置宽度是33.33%*/ + width: 33.33%; + height: 80px; + text-align: center; +} +.nav_right .nav_right_items image{ + /*被图片设置宽高*/ + width: 50px; + height: 30px; +} +.nav_right .nav_right_items text{ + /*给text设成块级元素*/ + display: block; + margin-top: 5px; + font-size: 10px; + /*设置文字溢出部分为...*/ + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +``` +**js:** +``` +Page({ + data: { + navLeftItems: [], + navRightItems: [], + curNav: 1, + curIndex: 0 + }, + onLoad: function() { + // 加载的使用进行网络访问,把需要的数据设置到data数据对象 + var that = this + wx.request({ + url: 'http://huanqiuxiaozhen.com/wemall/goodstype/typebrandList', + method: 'GET', + data: {}, + header: { + 'Accept': 'application/json' + }, + success: function(res) { + console.log(res) + that.setData({ + navLeftItems: res.data, + navRightItems: res.data + }) + } + }) + }, + + //事件处理函数 + switchRightTab: function(e) { + // 获取item项的id,和数组的下标值 + let id = e.target.dataset.id, + index = parseInt(e.target.dataset.index); + // 把点击到的某一项,设为当前index + this.setData({ + curNav: id, + curIndex: index + }) + } + +}) +``` + +demo地址:http://download.csdn.net/detail/michael_ouyang/9816426 +原文作者: michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/70172207 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\345\212\240\350\275\275\346\233\264\345\244\232\357\274\210\345\210\206\351\241\265\345\212\240\350\275\275\357\274\211\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2102\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\345\212\240\350\275\275\346\233\264\345\244\232\357\274\210\345\210\206\351\241\265\345\212\240\350\275\275\357\274\211\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2102\357\274\211.md" new file mode 100644 index 0000000..cc0797a --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\345\212\240\350\275\275\346\233\264\345\244\232\357\274\210\345\210\206\351\241\265\345\212\240\350\275\275\357\274\211\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2102\357\274\211.md" @@ -0,0 +1,301 @@ +## loadmore + +加载更多(分页加载) + +  + +当用户打开一个页面时,假设后台数据量庞大时,一次性地返回所有数据给客户端,页面的打开速度就会有所下降,而且用户只看上面的内容而不需要看后面的内容时,也浪费用户流量,基于优化的角度来考虑,后台不要一次性返回所有数据,当用户有需要再往下翻的时候,再加载更加数据出来。 + +  + +**业务需求:** + +列表滚动到底部时,继续往上拉,加载更多内容 + +  + +**必备参数:** + +(1)pageindex: 1 //第几次加载 + +(2)callbackcount: 15 //需要返回数据的个数 + +**其他参数:** + +根据接口的所需参数 + +  + +**实现原理:** + +当第一次访问接口时,传递2个必备参数(第1次加载,需要返回数据的个数为15个),和其他参数(需要搜索的字符串)给后台,后台返回第一次数据过来。在请求成功的的回调函数中,判断返回的数据是否>0,是,则取出数据,渲染视图层,并把“上拉加载”显示在列表底部;否,则没有数据可取,并把“没有更多”显示在列表底部,同时把“上拉加载”隐藏掉。 + +当用户已经滚动到列表底部(这里使用到小程序提供的scroll-view组件的bindscrolltolower事件),触发bindscrolltolower事件,参数pageindex+1,再把2个必备参数(第2次加载,需要返回数据的个数为15个)和其他参数(需要搜索的字符串)给后台,后台把其余的数据返回给前台,前台在原来数据的基础上添加数据。 + + +**示例:** + +**wxml:** +``` + + + + + + + 搜索 + + + + + + {{item.songname}} + + {{item.name}} + + + + + + + +``` + + +**js:** +``` +var util = require('../../utils/util.js') +Page({ + data: { + searchKeyword: '', //需要搜索的字符 + searchSongList: [], //放置返回数据的数组 + isFromSearch: true, // 用于判断searchSongList数组是不是空数组,默认true,空的数组 + searchPageNum: 1, // 设置加载的第几次,默认是第一次 + callbackcount: 15, //返回数据的个数 + searchLoading: false, //"上拉加载"的变量,默认false,隐藏 + searchLoadingComplete: false //“没有数据”的变量,默认false,隐藏 + }, + //输入框事件,每输入一个字符,就会触发一次 + bindKeywordInput: function(e){ + console.log("输入框事件") + this.setData({ + searchKeyword: e.detail.value + }) + }, + //搜索,访问网络 + fetchSearchList: function(){ + let that = this; + let searchKeyword = that.data.searchKeyword,//输入框字符串作为参数 + searchPageNum = that.data.searchPageNum,//把第几次加载次数作为参数 + callbackcount =that.data.callbackcount; //返回数据的个数 + //访问网络 + util.getSearchMusic(searchKeyword, searchPageNum,callbackcount, function(data){ + console.log(data) + //判断是否有数据,有则取数据 + if(data.data.song.curnum != 0){ + let searchList = []; + //如果isFromSearch是true从data中取出数据,否则先从原来的数据继续添加 + that.data.isFromSearch ? searchList=data.data.song.list : searchList=that.data.searchSongList.concat(data.data.song.list) + that.setData({ + searchSongList: searchList, //获取数据数组 + zhida: data.data.zhida, //存放歌手属性的对象 + searchLoading: true //把"上拉加载"的变量设为false,显示 + }); + //没有数据了,把“没有数据”显示,把“上拉加载”隐藏 + }else{ + that.setData({ + searchLoadingComplete: true, //把“没有数据”设为true,显示 + searchLoading: false //把"上拉加载"的变量设为false,隐藏 + }); + } + }) + }, + //点击搜索按钮,触发事件 + keywordSearch: function(e){ + this.setData({ + searchPageNum: 1, //第一次加载,设置1 + searchSongList:[], //放置返回数据的数组,设为空 + isFromSearch: true, //第一次加载,设置true + searchLoading: true, //把"上拉加载"的变量设为true,显示 + searchLoadingComplete:false //把“没有数据”设为false,隐藏 + }) + this.fetchSearchList(); + }, + //滚动到底部触发事件 + searchScrollLower: function(){ + let that = this; + if(that.data.searchLoading && !that.data.searchLoadingComplete){ + that.setData({ + searchPageNum: that.data.searchPageNum+1, //每次触发上拉事件,把searchPageNum+1 + isFromSearch: false //触发到上拉事件,把isFromSearch设为为false + }); + that.fetchSearchList(); + } + } +}) +``` + +**util.js:** +``` +function getSearchMusic(keyword, pageindex, callbackcount, callback){ + wx.request({ + url: 'https://c.y.qq.com/soso/fcgi-bin/search_for_qq_cp', + data: { + g_tk: 5381, + uin: 0, + format: 'json', + inCharset: 'utf-8', + outCharset: 'utf-8', + notice: 0, + platform: 'h5', + needNewCode: 1, + w: keyword, + zhidaqu: 1, + catZhida: 1, + t: 0, + flag: 1, + ie: 'utf-8', + sem: 1, + aggr: 0, + perpage: 20, + n: callbackcount, //返回数据的个数 + p: pageindex, + remoteplace: 'txt.mqq.all', + _: Date.now() + }, + method: 'GET', + header: {'content-Type': 'application/json'}, + success: function(res){ + if(res.statusCode == 200){ + callback(res.data); + } + } + }) +} + +module.exports = { + getSearchMusic: getSearchMusic +} +``` +**wxss:** +``` +page{ + display: flex; + flex-direction: column; + height: 100%; +} + +/*搜索*/ +.search{ + flex: auto; + display: flex; + flex-direction: column; + background: #fff; +} +.search-bar{ + flex: none; + display: flex; + align-items: center; + justify-content: space-between; + padding: 20rpx; + background: #f4f4f4; +} +.search-wrap{ + position: relative; + flex: auto; + display: flex; + align-items: center; + height: 80rpx; + padding: 0 20rpx; + background: #fff; + border-radius: 6rpx; +} +.search-wrap .icon-search{ + margin-right: 10rpx; +} +.search-wrap .search-input{ + flex: auto; + font-size: 28rpx; +} +.search-cancel{ + padding: 0 20rpx; + font-size: 28rpx; +} + +/*搜索结果*/ +.search-result{ + flex: auto; + position: relative; +} +.search-result scroll-view{ + position: absolute; + bottom: 0; + left: 0; + right: 0; + top: 0; +} +.result-item{ + position: relative; + display: flex; + flex-direction: column; + padding: 20rpx 0 20rpx 110rpx; + overflow: hidden; + border-bottom: 2rpx solid #e5e5e5; +} + +.result-item .media{ + position: absolute; + left: 16rpx; + top: 16rpx; + width: 80rpx; + height: 80rpx; + border-radius: 999rpx; +} +.result-item .title, +.result-item .subtitle{ + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + line-height: 36rpx; +} +.result-item .title{ + margin-bottom: 4rpx; + color: #000; +} +.result-item .subtitle{ + color: #808080; + font-size: 24rpx; +} +.result-item:first-child .subtitle text{ + margin-right: 20rpx; +} +.result-item:not(:first-child) .subtitle text:not(:first-child):before{ + content: '/'; + margin: 0 8rpx; +} +.loading{ + padding: 10rpx; + text-align: center; +} +.loading:before{ + display: inline-block; + margin-right: 5rpx; + vertical-align: middle; + content: ''; + width: 40rpx; + height: 40rpx; + background: url(../../images/icon-loading.png) no-repeat; + background-size: contain; + animation: rotate 1s linear infinite; +} +.loading.complete:before{ + display: none; +} +``` + + +运行: +![](https://upload-images.jianshu.io/upload_images/19956127-63f7cc0a3216a4eb.gif?imageMogr2/auto-orient/strip) + +原文作者: michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/56846185 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\345\225\206\345\223\201\345\261\236\346\200\247\345\210\206\347\261\273-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2104\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\345\225\206\345\223\201\345\261\236\346\200\247\345\210\206\347\261\273-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2104\357\274\211.md" new file mode 100644 index 0000000..28c5af3 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\345\225\206\345\223\201\345\261\236\346\200\247\345\210\206\347\261\273-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2104\357\274\211.md" @@ -0,0 +1,450 @@ +续上一篇的文章:微信小程序之购物数量加减 —— 微信小程序实战商城系列(3) + +所提及的购物数量的加减,现在说说商品属性值联动选择。 + + + +为了让同学们有个直观的了解,到电商网截了一个图片,就是红圈所示的部分 + +![](https://upload-images.jianshu.io/upload_images/19956127-7d9c0c0ecff07311.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + + + +现在就为大家介绍这个小组件,在小程序中,该如何去写 + +下图为本项目的图: +![](https://upload-images.jianshu.io/upload_images/19956127-8bf2714eefc79c3a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + + + + +**wxml:** +``` +商品属性值联动选择 + + + + + + {{attrValueObj.attrKey}} + + + + {{value}} + + + + + + + +``` + +**wxss:** +``` +.title { + padding: 10rpx 20rpx; + margin: 10rpx 0; + border-left: 4rpx solid #ccc; +} + +/*全部属性的主盒子*/ +.commodity_attr_list { + background: #fff; + padding: 0 20rpx; + font-size: 26rpx; + overflow: hidden; + width: 100%; +} +/*每组属性的主盒子*/ +.attr_box { + width: 100%; + overflow: hidden; + border-bottom: 1rpx solid #ececec; +} +/*属性名*/ +.attr_name { + width: 20%; + float: left; + padding: 15rpx 0; +} +/*属性值*/ +.attr_value_box { + width: 80%; + float: left; + padding: 15rpx 0; + overflow: hidden; +} +/*每个属性值*/ +.attr_value { + float: left; + padding: 0 10rpx; + margin: 0 10rpx; + border: 1rpx solid #ececec; +} +/*每个属性选中的当前样式*/ +.attr_value_active { + background: #FFCC00; + border-radius: 10rpx; + color: #fff; + padding: 0 10rpx; +} +/*禁用属性*/ +.attr_value_disabled { + color: #ccc; +} + +/*button*/ +.btn-area { + margin: 1.17647059em 15px 0.3em; +} + +.btn { + margin-top: 15px; + background-color:#FFCC00; + color: #fff; +} +.btn:first-child { + margin-top: 0; +} +``` +**js:** + +数据部分,一般情况都是访问接口获取数据的,这里并没有使用网络访问,为了简化demo,直接把一组数据放在data对象中。 +``` +Page({ + data: { + firstIndex: -1, + //准备数据 + //数据结构:以一组一组来进行设定 + commodityAttr: [ + { + priceId: 1, + price: 35.0, + "stock": 8, + "attrValueList": [ + { + "attrKey": "型号", + "attrValue": "2" + }, + { + "attrKey": "颜色", + "attrValue": "白色" + }, + { + "attrKey": "大小", + "attrValue": "小" + }, + { + "attrKey": "尺寸", + "attrValue": "S" + } + ] + }, + { + priceId: 2, + price: 35.1, + "stock": 9, + "attrValueList": [ + { + "attrKey": "型号", + "attrValue": "1" + }, + { + "attrKey": "颜色", + "attrValue": "黑色" + }, + { + "attrKey": "大小", + "attrValue": "小" + }, + { + "attrKey": "尺寸", + "attrValue": "M" + } + ] + }, + { + priceId: 3, + price: 35.2, + "stock": 10, + "attrValueList": [ + { + "attrKey": "型号", + "attrValue": "1" + }, + { + "attrKey": "颜色", + "attrValue": "绿色" + }, + { + "attrKey": "大小", + "attrValue": "大" + }, + { + "attrKey": "尺寸", + "attrValue": "L" + } + ] + }, + { + priceId: 4, + price: 35.2, + "stock": 10, + "attrValueList": [ + { + "attrKey": "型号", + "attrValue": "1" + }, + { + "attrKey": "颜色", + "attrValue": "绿色" + }, + { + "attrKey": "大小", + "attrValue": "大" + }, + { + "attrKey": "尺寸", + "attrValue": "L" + } + ] + } + ], + attrValueList: [] + }, + onShow: function () { + this.setData({ + includeGroup: this.data.commodityAttr + }); + this.distachAttrValue(this.data.commodityAttr); + // 只有一个属性组合的时候默认选中 + // console.log(this.data.attrValueList); + if (this.data.commodityAttr.length == 1) { + for (var i = 0; i < this.data.commodityAttr[0].attrValueList.length; i++) { + this.data.attrValueList[i].selectedValue = this.data.commodityAttr[0].attrValueList[i].attrValue; + } + this.setData({ + attrValueList: this.data.attrValueList + }); + } + }, + /* 获取数据 */ + distachAttrValue: function (commodityAttr) { + /** + 将后台返回的数据组合成类似 + { + attrKey:'型号', + attrValueList:['1','2','3'] + } + */ + // 把数据对象的数据(视图使用),写到局部内 + var attrValueList = this.data.attrValueList; + // 遍历获取的数据 + for (var i = 0; i < commodityAttr.length; i++) { + for (var j = 0; j < commodityAttr[i].attrValueList.length; j++) { + var attrIndex = this.getAttrIndex(commodityAttr[i].attrValueList[j].attrKey, attrValueList); + // console.log('属性索引', attrIndex); + // 如果还没有属性索引为-1,此时新增属性并设置属性值数组的第一个值;索引大于等于0,表示已存在的属性名的位置 + if (attrIndex >= 0) { + // 如果属性值数组中没有该值,push新值;否则不处理 + if (!this.isValueExist(commodityAttr[i].attrValueList[j].attrValue, attrValueList[attrIndex].attrValues)) { + attrValueList[attrIndex].attrValues.push(commodityAttr[i].attrValueList[j].attrValue); + } + } else { + attrValueList.push({ + attrKey: commodityAttr[i].attrValueList[j].attrKey, + attrValues: [commodityAttr[i].attrValueList[j].attrValue] + }); + } + } + } + // console.log('result', attrValueList) + for (var i = 0; i < attrValueList.length; i++) { + for (var j = 0; j < attrValueList[i].attrValues.length; j++) { + if (attrValueList[i].attrValueStatus) { + attrValueList[i].attrValueStatus[j] = true; + } else { + attrValueList[i].attrValueStatus = []; + attrValueList[i].attrValueStatus[j] = true; + } + } + } + this.setData({ + attrValueList: attrValueList + }); + }, + getAttrIndex: function (attrName, attrValueList) { + // 判断数组中的attrKey是否有该属性值 + for (var i = 0; i < attrValueList.length; i++) { + if (attrName == attrValueList[i].attrKey) { + break; + } + } + return i < attrValueList.length ? i : -1; + }, + isValueExist: function (value, valueArr) { + // 判断是否已有属性值 + for (var i = 0; i < valueArr.length; i++) { + if (valueArr[i] == value) { + break; + } + } + return i < valueArr.length; + }, + /* 选择属性值事件 */ + selectAttrValue: function (e) { + /* + 点选属性值,联动判断其他属性值是否可选 + { + attrKey:'型号', + attrValueList:['1','2','3'], + selectedValue:'1', + attrValueStatus:[true,true,true] + } + console.log(e.currentTarget.dataset); + */ + var attrValueList = this.data.attrValueList; + var index = e.currentTarget.dataset.index;//属性索引 + var key = e.currentTarget.dataset.key; + var value = e.currentTarget.dataset.value; + if (e.currentTarget.dataset.status || index == this.data.firstIndex) { + if (e.currentTarget.dataset.selectedvalue == e.currentTarget.dataset.value) { + // 取消选中 + this.disSelectValue(attrValueList, index, key, value); + } else { + // 选中 + this.selectValue(attrValueList, index, key, value); + } + + } + }, + /* 选中 */ + selectValue: function (attrValueList, index, key, value, unselectStatus) { + // console.log('firstIndex', this.data.firstIndex); + var includeGroup = []; + if (index == this.data.firstIndex && !unselectStatus) { // 如果是第一个选中的属性值,则该属性所有值可选 + var commodityAttr = this.data.commodityAttr; + // 其他选中的属性值全都置空 + // console.log('其他选中的属性值全都置空', index, this.data.firstIndex, !unselectStatus); + for (var i = 0; i < attrValueList.length; i++) { + for (var j = 0; j < attrValueList[i].attrValues.length; j++) { + attrValueList[i].selectedValue = ''; + } + } + } else { + var commodityAttr = this.data.includeGroup; + } + + // console.log('选中', commodityAttr, index, key, value); + for (var i = 0; i < commodityAttr.length; i++) { + for (var j = 0; j < commodityAttr[i].attrValueList.length; j++) { + if (commodityAttr[i].attrValueList[j].attrKey == key && commodityAttr[i].attrValueList[j].attrValue == value) { + includeGroup.push(commodityAttr[i]); + } + } + } + attrValueList[index].selectedValue = value; + + // 判断属性是否可选 + for (var i = 0; i < attrValueList.length; i++) { + for (var j = 0; j < attrValueList[i].attrValues.length; j++) { + attrValueList[i].attrValueStatus[j] = false; + } + } + for (var k = 0; k < attrValueList.length; k++) { + for (var i = 0; i < includeGroup.length; i++) { + for (var j = 0; j < includeGroup[i].attrValueList.length; j++) { + if (attrValueList[k].attrKey == includeGroup[i].attrValueList[j].attrKey) { + for (var m = 0; m < attrValueList[k].attrValues.length; m++) { + if (attrValueList[k].attrValues[m] == includeGroup[i].attrValueList[j].attrValue) { + attrValueList[k].attrValueStatus[m] = true; + } + } + } + } + } + } + // console.log('结果', attrValueList); + this.setData({ + attrValueList: attrValueList, + includeGroup: includeGroup + }); + + var count = 0; + for (var i = 0; i < attrValueList.length; i++) { + for (var j = 0; j < attrValueList[i].attrValues.length; j++) { + if (attrValueList[i].selectedValue) { + count++; + break; + } + } + } + if (count < 2) {// 第一次选中,同属性的值都可选 + this.setData({ + firstIndex: index + }); + } else { + this.setData({ + firstIndex: -1 + }); + } + }, + /* 取消选中 */ + disSelectValue: function (attrValueList, index, key, value) { + var commodityAttr = this.data.commodityAttr; + attrValueList[index].selectedValue = ''; + + // 判断属性是否可选 + for (var i = 0; i < attrValueList.length; i++) { + for (var j = 0; j < attrValueList[i].attrValues.length; j++) { + attrValueList[i].attrValueStatus[j] = true; + } + } + this.setData({ + includeGroup: commodityAttr, + attrValueList: attrValueList + }); + + for (var i = 0; i < attrValueList.length; i++) { + if (attrValueList[i].selectedValue) { + this.selectValue(attrValueList, i, attrValueList[i].attrKey, attrValueList[i].selectedValue, true); + } + } + }, + /* 点击确定 */ + submit: function () { + var value = []; + for (var i = 0; i < this.data.attrValueList.length; i++) { + if (!this.data.attrValueList[i].selectedValue) { + break; + } + value.push(this.data.attrValueList[i].selectedValue); + } + if (i < this.data.attrValueList.length) { + wx.showToast({ + title: '请完善属性', + icon: 'loading', + duration: 1000 + }) + } else { + wx.showToast({ + title: '选择的属性:' + value.join('-'), + icon: 'sucess', + duration: 1000 + }) + } + } +}) +``` +运行效果: + +![](https://upload-images.jianshu.io/upload_images/19956127-0e870421bba89649.gif?imageMogr2/auto-orient/strip) + + +demo地址:http://download.csdn.net/detail/michael_ouyang/9816438 +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/70209626 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\345\276\256\344\277\241\347\231\273\351\231\206-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21020\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\345\276\256\344\277\241\347\231\273\351\231\206-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21020\357\274\211.md" new file mode 100644 index 0000000..c8e7b20 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\345\276\256\344\277\241\347\231\273\351\231\206-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21020\357\274\211.md" @@ -0,0 +1,504 @@ +#简介: + +微信登陆,在新建一个微信小程序Hello World项目的时候,就可以看到项目中出现了我们的微信头像,其实这个Hello World项目,就有一个简化版的微信登陆。只不过是,还没有写入到咱们自家的后台中而已。 +![](https://upload-images.jianshu.io/upload_images/19956127-b3e61d7e08f07ef4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +新建一个Hello World项目,找到app.js文件打开,代码如下: + +app.js: +``` +App({ + +  onLaunch: function () { + +    //调用API从本地缓存中获取数据 + +    var logs = wx.getStorageSync('logs') || [] + +    logs.unshift(Date.now()) + +    wx.setStorageSync('logs', logs) + +  }, + +  getUserInfo:function(cb){ + +    var that = this + +    if(this.globalData.userInfo){ + +      typeof cb == "function" && cb(this.globalData.userInfo) + +    }else{ + +      //调用登录接口 + +      wx.login({ + +        success: function () { + +          wx.getUserInfo({ + +            success: function (res) { + +              that.globalData.userInfo = res.userInfo + +              typeof cb == "function" && cb(that.globalData.userInfo) + +            } + +          }) + +        } + +      }) + +    } + +  }, + +  globalData:{ + +    userInfo:null + +  } + +}) +``` +黄色标注的部分就是登陆部分  + +下面详细介绍微信小程序的微信登陆 + +第一步:获取登陆态code +微信登陆部分,首先需要使用微信小程序的api—— wx.login(OBJECT)来获取登录态 + +这个登陆态的作用是为了获取用户的openid(用户的唯一标识) +![](https://upload-images.jianshu.io/upload_images/19956127-d300dd7d256c2656.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +相关链接:https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-login.html#wxloginobject + +  + +**示例:官方示例** + +js: +``` +//调用登录 + +    wx.login({ + +      success: function(res) { + +       console.log(res); + +        if (res.code) { + +          //发起网络请求 + +          //doSomething + +        } else { + +          console.log('获取用户登录态失败!' + res.errMsg) + +        } + +      }, + +  fail: function(){ + +    console.log("启用wx.login函数,失败!"); + +  }, + +  complete:function(){ + +    console.log("已启用wx.login函数"); + +  } + +  + +}); +``` +  +**TIPS:** + +上面这段代码的console.log(res);输出wx.login(OBJECT)的success成功回调函数返回值res的内容如下: + +情况一: + +出现这个code:”the code is a mock one”是在项目没有使用appid的情况下返回的,正常不是返回这个的!! +![](https://upload-images.jianshu.io/upload_images/19956127-879eed415de95969.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +情况二: + +项目在绑定appID后才能成功返回登录态,正确的登陆态如下图所示: +![](https://upload-images.jianshu.io/upload_images/19956127-1ecc60015d9d2d6b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +  + +第二步:将登陆态code发送给第三方服务器(即自家的服务器) + ![](https://upload-images.jianshu.io/upload_images/19956127-afea600c3601eae4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +上面通过wx.login(OBJECT)获取了登录态后,接下来就是将code发送给第三方服务器 + +  + +我们先看看微信登陆的序时图: + +序时图所示,通过wx.login()获取了code后,就使用wx.request()发送code给第三方服务器(也就是自家的服务器) + + + + +下面用代码来进行讲解这一步如何操作 + +  + +示例:官方示例 + +把wx.login获取到的res.code返回值,直接以参数的形式,发起网络请求发送登陆态给自家服务器 + +js: +``` +//调用登录 + +    wx.login({ + +      success: function(res) { + +       console.log(res); + +        if (res.code) { + +          //就是在这里发起网络请求,使用wx.request(),将登陆态发送给自家的服务器上 + +          wx.request({ + +            url: 'https://test.com/onLogin', + +            data: { + +              code: res.code + +            }, + +            method: 'POST',   + +      header: {'content-type': 'application/json'}, + +            success: function(data){ + +            } + +          }) + +        } else { + +          console.log('获取用户登录态失败!' + res.errMsg) + +        } + +      }, + +  fail: function(){ + +    console.log("启用wx.login函数,失败!"); + +  }, + +  complete:function(){ + +    console.log("已启用wx.login函数"); + +  } + +}); +``` + +如何使用微信小程序发起网络请求? + +请看如下教程:微信小程序的网络请求 ——微信小程序教程系列(14) + +  + +第三步:code 换取 session_key和openid +  + +登陆态发送给自家的服务器后,接下来就是后台进行操作。 + +下面我把 自家的服务器简称 后台,方便阅读(你知道我说的后台指的是我们自己的服务器,而不是微信的服务器就行)。 + +后台接收到登陆态后,由后台发起网络请求给微信服务器 + +备注:后台没有语言要求!!任意一门后台语言都可以。 + +  + +接口地址: + +https://api.weixin.qq.com/sns/jscode2session + + +参数说明: +![](https://upload-images.jianshu.io/upload_images/19956127-78e77c1487202bf9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +备注: + +appid和secret登陆微信公众平台,打开设置——开发设置,即可获取(app secret需要生成)。 +![](https://upload-images.jianshu.io/upload_images/19956127-9387bede14df9933.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +grant_type是固定写法,值为authorization_code即可。 + +  + +返回结果: +![](https://upload-images.jianshu.io/upload_images/19956127-ab9949e46a3999e0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +后台发送请求成后,腾讯服务器会返回session_key 和 openid,如下图: + +成功返回的结果 +![](https://upload-images.jianshu.io/upload_images/19956127-0e484ceb640aba43.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +失败返回的结果 +![](https://upload-images.jianshu.io/upload_images/19956127-a354e1cc300afde9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +第四步:生成3rd_session返回给客户端 +  + +第四步也是做后台中的操作!! + +此时把微信服务器返回的session_key 和 openid保留在后台中,由于考虑安全性的问题,不要直接返回给客户端。 + +然后用操作系统提供的随机数算法生成一个新的session,微信把它叫做3rd_session。(注意:这个session要有足够的长度,建议有2^128种组合,即长度为16B;设置一定的时效性) + +以3rd_session为名作为key,返回的session_key和openid作为值,保存在后台上。 + +最后只需要在后台,返回一个3rd_session给客户端即可。 + +  + +以后客户端部分,就使用这个3rd_session发送给后台,后台接收3rd_session获取对应的session_key和openid,再通过session_key和openid判断对应的用户返回该用户相关的数据 + +  + +备注:小程序用这种方法来代替浏览器自身发送的cookie,因为web的做法是服务器A会保存起访问登录接口的这个cookie到session中,当你再次访问其他接口的时候,服务器A首先会判断这个session,是否是之间的cookie从而知道是不是对应的用户。(http协议是一种短链接的关系,其特点是客户端发起请求链接到服务端,服务端返回数据,链接断开!因此之间是不会有任何数据的储存。) + +  + +示例:接上示例 + +js: +``` +    wx.login({ + +      success: function(res) { + +       console.log(res); + +        if (res.code) { + +          wx.request({ + +            url: 'https://test.com/onLogin', + +            data: { + +              code: res.code + +            }, + +            method: 'POST',   + +       header: {'content-type': 'application/json'}, + +// 在发送请求成功的部分,返回的数据是后台返回的3rd_session + +            success: function(data){ + +console.log(data) + +            } + +          }) + +        } else { + +          console.log('获取用户登录态失败!' + res.errMsg) + +        } + +      }, + +  fail: function(){ + +    console.log("启用wx.login函数,失败!"); + +  }, + +  complete:function(){ + +    console.log("已启用wx.login函数"); + +  } + +}); +``` +  +PS: + +要是阅读到这里,有不明之处,请叫上后台的小伙伴一起过来阅读这篇文章 + +第三步,和第四步,要交给后台的同事去处理!!! + +  + +  + +  + +  + +第五步:客户端保存3rd_session +  + +回到客户端的工作了。 + +从第四步后台返回的3rd_session后,需要将3rd_session存入缓存中。 + +小程序提供了保存到本地缓存的api,使用非常简单。 + +  + +(1)wx.setStorage(OBJECT) + +传入key和data即可。 +![](https://upload-images.jianshu.io/upload_images/19956127-4b4a0fe0c39d1053.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +(2)wx.setStorageSync(KEY,DATA) +![](https://upload-images.jianshu.io/upload_images/19956127-ed53c1ff95ed6ac3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +第六步:获取用户信息 +![](https://upload-images.jianshu.io/upload_images/19956127-650d224e01e23833.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +相关连接:https://mp.weixin.qq.com/debug/wxadoc/dev/api/open.html + + + +示例:接上示例 + +js: +``` +    wx.login({ + +      success: function(res) { + +       console.log(res); + +        if (res.code) { + +          wx.request({ + +            url: 'https://test.com/onLogin', + +            data: { + +              code: res.code + +            }, + +            method: 'POST',   + +       header: {'content-type': 'application/json'}, + +            success: function(data){ + +console.log(data) + +            } + +          }) + +          // 使用wx.getUserInfo获取用户信息 + +  wx.getUserInfo({ + +        success: function (res) { + +            utils.log(res); + +        }, + +fail:function(){ + +console.log("启用app.getUserInfo函数,失败!"); + +}, + +complete:function(){ + +console.log("已启用app.getUserInfo函数");    + +      }); + +  + +        } else { + +          console.log('获取用户登录态失败!' + res.errMsg) + +        } + +      }, + +  fail: function(){ + +    console.log("启用wx.login函数,失败!"); + +  }, + +  complete:function(){ + +    console.log("已启用wx.login函数"); + +  } + +}); +``` + +输出wx.getUserInfo的success成功回调函数返回值res的内容如下: +![](https://upload-images.jianshu.io/upload_images/19956127-f83c5f0197328418.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +userInfo对象内是用户的信息: + +avatarUrl: 用户头像 + +city: 城市 + +country: 国家 + +gender: 性别 + +language: 语言 + +nickName: 昵称 + +province: 省份 +  + +第七步:登录态维护 +通过上面六步,已经成功登陆微信小程序了,但是还需要做登陆维护。 + +也就是说,登陆小程序后,然后又退出该小程序了。在一段时间内,再次进入该小程序,视为有效登陆,如果超出这个指定的时间,则视为无效登陆,需要重新登陆 +![](https://upload-images.jianshu.io/upload_images/19956127-ea406404a43db3a6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +![](https://upload-images.jianshu.io/upload_images/19956127-451a688618e53866.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/72635263 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\347\231\273\345\275\225\351\241\265\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2105\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\347\231\273\345\275\225\351\241\265\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2105\357\274\211.md" new file mode 100644 index 0000000..dc69fb3 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\347\231\273\345\275\225\351\241\265\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2105\357\274\211.md" @@ -0,0 +1,177 @@ +提供一个登录页的案例,供同学们使用 + +**项目效果图:** +![](https://upload-images.jianshu.io/upload_images/19956127-2b8440573c59b361.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +**目录结构:** +![](https://upload-images.jianshu.io/upload_images/19956127-235186ce302d538a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +图片资源: + +name.png +![](https://upload-images.jianshu.io/upload_images/19956127-9251070cf870f07d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +key.png +![](https://upload-images.jianshu.io/upload_images/19956127-95329bec26860162.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +loginLog.jpg +![](https://upload-images.jianshu.io/upload_images/19956127-866bcd40f108a585.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +**login.wxml:** +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +**login.wxss:** +``` +page{ + height: 100%; +} + +.container { + height: 100%; + display: flex; + flex-direction: column; + padding: 0; + box-sizing: border-box; + background-color: #f2f2f2 +} + +/*登录图片*/ +.login-icon{ + flex: none; +} +.login-img{ + width: 750rpx; +} + +/*表单内容*/ +.login-from { + margin-top: 20px; + flex: auto; + height:100%; +} + +.inputView { + background-color: #fff; + line-height: 44px; +} +/*输入框*/ +.nameImage, .keyImage { + margin-left: 22px; + width: 14px; + height: 14px +} + +.loginLab { + margin: 15px 15px 15px 10px; + color: #545454; + font-size: 14px +} +.inputText { + flex: block; + float: right; + text-align: right; + margin-right: 22px; + margin-top: 11px; + color: #cccccc; + font-size: 14px +} + +.line { + width: 100%; + height: 1px; + background-color: #cccccc; + margin-top: 1px; +} +/*按钮*/ +.loginBtnView { + width: 100%; + height: auto; + background-color: #f2f2f2; + margin-top: 0px; + margin-bottom: 0px; + padding-bottom: 0px; +} + +.loginBtn { + width: 80%; + margin-top: 35px; +} + + +login.js: + +Page({ + data: { + phone: '', + password:'' + }, + +// 获取输入账号 + phoneInput :function (e) { + this.setData({ + phone:e.detail.value + }) + }, + +// 获取输入密码 + passwordInput :function (e) { + this.setData({ + password:e.detail.value + }) + }, + +// 登录 + login: function () { + if(this.data.phone.length == 0 || this.data.password.length == 0){ + wx.showToast({ + title: '用户名和密码不能为空', + icon: 'loading', + duration: 2000 + }) +}else { + // 这里修改成跳转的页面 + wx.showToast({ + title: '登录成功', + icon: 'success', + duration: 2000 + }) + } + } +}) +``` + +运行结果: +![](https://upload-images.jianshu.io/upload_images/19956127-b6fee530db1a2324.gif?imageMogr2/auto-orient/strip) +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/60751291 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\347\273\204\344\273\266-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21019\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\347\273\204\344\273\266-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21019\357\274\211.md" new file mode 100644 index 0000000..b0430b1 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\347\273\204\344\273\266-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21019\357\274\211.md" @@ -0,0 +1,90 @@ +**什么是组件:** + +组件是视图层的基本组成单元。 +组件自带一些功能与微信风格的样式。 +一个组件通常包括开始标签和结束标签,属性用来修饰这个组件,内容在两个标签之内。 +``` + +  Content goes here ... + +``` +注意:所有组件与属性都是小写,以连字符-连接 + +**组件属性类型** +![](https://upload-images.jianshu.io/upload_images/19956127-d04d1090d60975a8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + + + + +**共同属性类型** + +所有组件都有的属性: +![](https://upload-images.jianshu.io/upload_images/19956127-8d00c6ef5eba0017.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +**特殊属性** +特殊属性是各个组件自己定义的属性,如 组件的size属性,具体各参见官方文档各组件具体说明。 + + +**组件列表** +![](https://upload-images.jianshu.io/upload_images/19956127-3ad05e6d595bd9c9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + + +组件列表中的一些教程如下:(点击可打开) + + +**视图容器** + +view组件 + +scroll-view组件 + +swiper组件 + + + +**基础内容** + +icon组件 + +text组件 + +progress组件 + + +**表单组件** + +button组件 + +checkbox组件 + +form组件 + +input组件 + +picker组件 + +radio组件 + +slider组件 + +switch组件 + + +**导航** + +navigator组件 + + +**媒体组件** + +audio组件 + +image组件 + +video组件 + + +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/56277811 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\207\252\345\256\232\344\271\211toast\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2106\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\207\252\345\256\232\344\271\211toast\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2106\357\274\211.md" new file mode 100644 index 0000000..9b96cee --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\207\252\345\256\232\344\271\211toast\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2106\357\274\211.md" @@ -0,0 +1,132 @@ +微信提供了一个toast的api  wx.showToast() + +相关连接:https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-react.html#wxshowtoastobject + +  + +本来是比较好的,方便使用,但是这个toast会显示出图标,而且不能去除。 + +假设:我们执行完业务的时候,toast一下,当执行成功的时候,效果还可以接受,如下图: +![](https://upload-images.jianshu.io/upload_images/19956127-cbff9b61ee652d28.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +但是,当执行失败的时候,如下图: + +失败了,你还显示个扣扣图案,那到底是成功还是失败??这肯定是不能接受的。【捂脸】 + +若是给老板看到这种效果,又是一顿臭骂,程序猿的委屈 +![](https://upload-images.jianshu.io/upload_images/19956127-cfcd7450e15ee451.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +下面介绍一个自定义的toast + +效果: +![](https://upload-images.jianshu.io/upload_images/19956127-4859494f834da3ef.gif?imageMogr2/auto-orient/strip) + +**具体实现:** + + +**wxml:** +``` + + + button + + + + + + + + + {{toastText}} + + + +``` +**wxss:** +``` +Page { + background: #fff; +} +/*按钮*/ +.btn { + font-size: 28rpx; + padding: 15rpx 30rpx; + width: 100rpx; + margin: 20rpx; + text-align: center; + border-radius: 10rpx; + border: 1px solid #000; +} +/*mask*/ +.toast_mask { + opacity: 0; + width: 100%; + height: 100%; + overflow: hidden; + position: fixed; + top: 0; + left: 0; + z-index: 888; +} +/*toast*/ +.toast_content_box { + display: flex; + width: 100%; + height: 100%; + justify-content: center; + align-items: center; + position: fixed; + z-index: 999; +} +.toast_content { + width: 50%; + padding: 20rpx; + background: rgba(0, 0, 0, 0.5); + border-radius: 20rpx; +} +.toast_content_text { + height: 100%; + width: 100%; + color: #fff; + font-size: 28rpx; + text-align: center; +} +``` +**js:** +``` +Page({ + data: { + //toast默认不显示 + isShowToast: false + }, + showToast: function () { + var _this = this; + // toast时间 + _this.data.count = parseInt(_this.data.count) ? parseInt(_this.data.count) : 3000; + // 显示toast + _this.setData({ + isShowToast: true, + }); + // 定时器关闭 + setTimeout(function () { + _this.setData({ + isShowToast: false + }); + }, _this.data.count); + }, + /* 点击按钮 */ + clickBtn: function () { + console.log("你点击了按钮") + //设置toast时间,toast内容 + this.setData({ + count: 1500, + toastText: 'Michael’s Toast' + }); + this.showToast(); + } +}) +``` +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/60867679 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\207\252\345\256\232\344\271\211\346\212\275\345\261\211\350\217\234\345\215\225\357\274\210\344\273\216\344\270\213\346\213\211\345\207\272\357\274\211\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2107\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\207\252\345\256\232\344\271\211\346\212\275\345\261\211\350\217\234\345\215\225\357\274\210\344\273\216\344\270\213\346\213\211\345\207\272\357\274\211\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2107\357\274\211.md" new file mode 100644 index 0000000..c12c057 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\207\252\345\256\232\344\271\211\346\212\275\345\261\211\350\217\234\345\215\225\357\274\210\344\273\216\344\270\213\346\213\211\345\207\272\357\274\211\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2107\357\274\211.md" @@ -0,0 +1,149 @@ +微信提供了动画api,就是下面这个 +![](https://upload-images.jianshu.io/upload_images/19956127-772ee5fc0195436a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +相关链接:https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-animation.html#wxcreateanimationobject + +  + +通过使用这个创建动画的api,可以做出很多特效出来 + +下面介绍一个抽屉菜单的案例 + + + +**实现代码:** + +**wxml:** +``` + +button + + + + + + + + 菜单1 + 菜单2 + 菜单3 + 菜单4 + 菜单5 + + +``` + +**wxss:** +``` +/*button*/ +.btn { + width: 80%; + padding: 20rpx 0; + border-radius: 10rpx; + text-align: center; + margin: 40rpx 10%; + background: #0C1939; + color: #fff; +} +/*mask*/ +.drawer_screen { + width: 100%; + height: 100%; + position: fixed; + top: 0; + left: 0; + z-index: 1000; + background: #000; + opacity: 0.2; + overflow: hidden; +} +/*content*/ +.drawer_attr_box { + width: 100%; + overflow: hidden; + position: fixed; + bottom: 0; + left: 0; + z-index: 1001; + background: #fff; +} +.drawer_content { + padding: 20rpx 40rpx; + height: 470rpx; + overflow-y: scroll; +} +.drawer_title{ + padding:20rpx; + font:42rpx "microsoft yahei"; + text-align: center; +} +.line{ + border-bottom: 1px solid #f8f8f8; +} +``` +**js:** +``` +Page({ + data: { + showModalStatus: false + }, + powerDrawer: function (e) { + var currentStatu = e.currentTarget.dataset.statu; + this.util(currentStatu) + }, + util: function(currentStatu){ + /* 动画部分 */ + // 第1步:创建动画实例 + var animation = wx.createAnimation({ + duration: 200, //动画时长 + timingFunction: "linear", //线性 + delay: 0 //0则不延迟 + }); + + // 第2步:这个动画实例赋给当前的动画实例 + this.animation = animation; + + // 第3步:执行第一组动画:Y轴偏移240px后(盒子高度是240px),停 + animation.translateY(240).step(); + + // 第4步:导出动画对象赋给数据对象储存 + this.setData({ + animationData: animation.export() + }) + + // 第5步:设置定时器到指定时候后,执行第二组动画 + setTimeout(function () { + // 执行第二组动画:Y轴不偏移,停 + animation.translateY(0).step() + // 给数据对象储存的第一组动画,更替为执行完第二组动画的动画对象 + this.setData({ + animationData: animation + }) + + //关闭抽屉 + if (currentStatu == "close") { + this.setData( + { + showModalStatus: false + } + ); + } + }.bind(this), 200) + + // 显示抽屉 + if (currentStatu == "open") { + this.setData( + { + showModalStatus: true + } + ); + } + } +}) +``` +效果: +![](https://upload-images.jianshu.io/upload_images/19956127-ae09cfe64576b9ed.gif?imageMogr2/auto-orient/strip) + +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/60954907 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\207\252\345\256\232\344\271\211\346\250\241\346\200\201\345\274\271\347\252\227\357\274\210\345\270\246\345\212\250\347\224\273\357\274\211\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2108\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\207\252\345\256\232\344\271\211\346\250\241\346\200\201\345\274\271\347\252\227\357\274\210\345\270\246\345\212\250\347\224\273\357\274\211\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2108\357\274\211.md" new file mode 100644 index 0000000..6c35478 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\207\252\345\256\232\344\271\211\346\250\241\346\200\201\345\274\271\347\252\227\357\274\210\345\270\246\345\212\250\347\224\273\357\274\211\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2108\357\274\211.md" @@ -0,0 +1,228 @@ +首先看看官方提供的模态弹窗 +![](https://upload-images.jianshu.io/upload_images/19956127-ef353435f461a10c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +**api如下:** +![](https://upload-images.jianshu.io/upload_images/19956127-6e129c95be0ced09.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + + +**示例:** +![](https://upload-images.jianshu.io/upload_images/19956127-2946ce629f43c71d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +这样的模态弹窗,充其量只能做个alert,提示一下信息。 + +但是并不能使用它来处理复杂性的弹窗业务,因此写了Michael从新自定义了一个,采用了仿原生的样式写法 + + +**wxml:** + +``` + +button + + + + + + + + + 弹窗标题 + + + + + + + + + + + + + + + + + + + + + + + 确定 + +``` + +**wxss:** +``` +/*button*/ +.btn { + width: 80%; + padding: 20rpx 0; + border-radius: 10rpx; + text-align: center; + margin: 40rpx 10%; + background: #000; + color: #fff; +} + +/*mask*/ +.drawer_screen { + width: 100%; + height: 100%; + position: fixed; + top: 0; + left: 0; + z-index: 1000; + background: #000; + opacity: 0.5; + overflow: hidden; +} + +/*content*/ +.drawer_box { + width: 650rpx; + overflow: hidden; + position: fixed; + top: 50%; + left: 0; + z-index: 1001; + background: #FAFAFA; + margin: -150px 50rpx 0 50rpx; + border-radius: 3px; +} + +.drawer_title{ + padding:15px; + font: 20px "microsoft yahei"; + text-align: center; +} +.drawer_content { + height: 210px; + overflow-y: scroll; /*超出父盒子高度可滚动*/ +} + +.btn_ok{ + padding: 10px; + font: 20px "microsoft yahei"; + text-align: center; + border-top: 1px solid #E8E8EA; + color: #3CC51F; +} + +.top{ + padding-top:8px; +} +.bottom { + padding-bottom:8px; +} +.title { + height: 30px; + line-height: 30px; + width: 160rpx; + text-align: center; + display: inline-block; + font: 300 28rpx/30px "microsoft yahei"; +} + +.input_base { + border: 2rpx solid #ccc; + padding-left: 10rpx; + margin-right: 50rpx; +} +.input_h30{ + height: 30px; + line-height: 30px; +} +.input_h60{ + height: 60px; +} +.input_view{ + font: 12px "microsoft yahei"; + background: #fff; + color:#000; + line-height: 30px; +} + +input { + font: 12px "microsoft yahei"; + background: #fff; + color:#000 ; +} +radio{ + margin-right: 20px; +} +.grid { display: -webkit-box; display: box; } +.col-0 {-webkit-box-flex:0;box-flex:0;} +.col-1 {-webkit-box-flex:1;box-flex:1;} +.fl { float: left;} +.fr { float: right;} +``` +**js:** +``` +Page({ + data: { + showModalStatus: false + }, + powerDrawer: function (e) { + var currentStatu = e.currentTarget.dataset.statu; + this.util(currentStatu) + }, + util: function(currentStatu){ + /* 动画部分 */ + // 第1步:创建动画实例 + var animation = wx.createAnimation({ + duration: 200, //动画时长 + timingFunction: "linear", //线性 + delay: 0 //0则不延迟 + }); + + // 第2步:这个动画实例赋给当前的动画实例 + this.animation = animation; + + // 第3步:执行第一组动画 + animation.opacity(0).rotateX(-100).step(); + + // 第4步:导出动画对象赋给数据对象储存 + this.setData({ + animationData: animation.export() + }) + + // 第5步:设置定时器到指定时候后,执行第二组动画 + setTimeout(function () { + // 执行第二组动画 + animation.opacity(1).rotateX(0).step(); + // 给数据对象储存的第一组动画,更替为执行完第二组动画的动画对象 + this.setData({ + animationData: animation + }) + + //关闭 + if (currentStatu == "close") { + this.setData( + { + showModalStatus: false + } + ); + } + }.bind(this), 200) + + // 显示 + if (currentStatu == "open") { + this.setData( + { + showModalStatus: true + } + ); + } + } + +}) +``` +**运行:** +![](https://upload-images.jianshu.io/upload_images/19956127-a7be11f9fd519ecb.gif?imageMogr2/auto-orient/strip) + +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/62430905 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\207\252\345\256\232\344\271\211\350\275\256\346\222\255\345\233\276\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2103\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\207\252\345\256\232\344\271\211\350\275\256\346\222\255\345\233\276\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2103\357\274\211.md" new file mode 100644 index 0000000..c86e08a --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\207\252\345\256\232\344\271\211\350\275\256\346\222\255\345\233\276\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2103\357\274\211.md" @@ -0,0 +1,168 @@ +轮播图是大部分应用的一个常用的功能,常用于广告投放、产品展示、活动展示等等。 + +漂亮的轮播图效果可以吸引用户的点击,达到推广产品的作用。 + +废话少说,下面开始动手。 + +  + +业务需求: + +5个图片轮番播放,可以左右滑动,点击指示点可以切换图片 + +  + +重点说明: + +由于微信小程序,整个项目编译后的大小不能超过1M + +![](https://upload-images.jianshu.io/upload_images/19956127-0a89c50161361c75.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +查看做轮播图功能的一张图片大小都已经有100+k了 +![](https://upload-images.jianshu.io/upload_images/19956127-1cd7509d2616b94c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +那么我们可以把图片放在服务器上,发送请求来获取。 + + + + + +index.wxml: + +这里使用小程序提供的组件 + +autoplay:自动播放 + +interval:自动切换时间 + +duration:滑动动画的时长 + +current:当前所在的页面 + +bindchange:current 改变时会触发 change 事件 + +由于组件提供的指示点样式比较单一,另外再自定义指示点的样式 +``` + + + + + + + + + + + + {{index+1}} + + + + +``` +**index.wxss:** +``` +.swiper-container{ + position: relative; +} +.swiper-container .swiper{ + height: 300rpx; +} +.swiper-container .swiper .img{ + width: 100%; + height: 100%; +} +.swiper-container .dots{ + position: absolute; + right: 40rpx; + bottom: 20rpx; + display: flex; + justify-content: center; +} +.swiper-container .dots .dot{ + margin: 0 10rpx; + width: 28rpx; + height: 28rpx; + background: #fff; + border-radius: 50%; + transition: all .6s; + font: 300 18rpx/28rpx "microsoft yahei"; + text-align: center; +} +.swiper-container .dots .dot.active{ + background: #f80; + color:#fff; +} +``` +**index.js:** +``` +//导入js +var util = require('../../utils/util.js') +Page({ + data: { + slider: [], + swiperCurrent: 0 + }, + onLoad: function () { + var that = this; +//网络访问,获取轮播图的图片 + util.getRecommend(function(data){ + that.setData({ + slider: data.data.slider + }) + }); + }, + //轮播图的切换事件 + swiperChange: function(e){ +//只要把切换后当前的index传给组件的current属性即可 + this.setData({ + swiperCurrent: e.detail.current + }) + }, + //点击指示点切换 + chuangEvent: function(e){ + this.setData({ + swiperCurrent: e.currentTarget.id + }) + } +}) +``` +**utils.js:** +``` +//网络访问 +function getRecommend(callback) { + wx.request({ + url: 'https://c.y.qq.com/musichall/fcgi-bin/fcg_yqqhomepagerecommend.fcg', + data: { + g_tk: 5381, + uin: 0, + format: 'json', + inCharset: 'utf-8', + outCharset: 'utf-8', + notice: 0, + platform: 'h5', + needNewCode: 1, + _: Date.now() + }, + method: 'GET', + header: {'content-Type': 'application/json'}, + success: function(res){ + if(res.statusCode == 200){ + callback(res.data); + } + } + }) +} + +module.exports = { + getRecommend: getRecommend +} +``` + +运行: +![](https://upload-images.jianshu.io/upload_images/19956127-f9c98e4ed91ed147.gif?imageMogr2/auto-orient/strip) + + +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/58591232 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\264\255\347\211\251\346\225\260\351\207\217\345\212\240\345\207\217-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2103\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\264\255\347\211\251\346\225\260\351\207\217\345\212\240\345\207\217-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2103\357\274\211.md" new file mode 100644 index 0000000..5bd1073 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\264\255\347\211\251\346\225\260\351\207\217\345\212\240\345\207\217-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2103\357\274\211.md" @@ -0,0 +1,132 @@ +我们在购买宝贝的时候,购物的数量,经常是我们需要使用的,如下所示: + +在宝贝详情页里: +![](https://upload-images.jianshu.io/upload_images/19956127-18bfe59f789c38d9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + + +在购物车里: +![](https://upload-images.jianshu.io/upload_images/19956127-994224cadaa64c58.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +现在就为大家介绍这个小组件,在小程序中,该如何去写 + +下图为本项目的图: +![](https://upload-images.jianshu.io/upload_images/19956127-27d3886b44663a47.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +**wxml:** +``` + + + + - + + + + + + +``` +**wxss:** +``` +/*全局样式*/ +page { + padding: 20px 0; +} + +/*主容器*/ +.stepper { + width: 80px; + height: 26px; + /*给主容器设一个边框*/ + border: 1px solid #ccc; + border-radius: 3px; + margin:0 auto; +} + +/*加号和减号*/ +.stepper text { + width: 19px; + line-height: 26px; + text-align: center; + float: left; +} + +/*数值*/ +.stepper input { + width: 40px; + height: 26px; + float: left; + margin: 0 auto; + text-align: center; + font-size: 12px; + /*给中间的input设置左右边框即可*/ + border-left: 1px solid #ccc; + border-right: 1px solid #ccc; +} + +/*普通样式*/ +.stepper .normal{ + color: black; +} + +/*禁用样式*/ +.stepper .disabled{ + color: #ccc; +} +``` +**js:** +``` +Page({ + data: { + // input默认是1 + num: 1, + // 使用data数据对象设置样式名 + minusStatus: 'disabled' + }, + /* 点击减号 */ + bindMinus: function() { + var num = this.data.num; + // 如果大于1时,才可以减 + if (num > 1) { + num --; + } + // 只有大于一件的时候,才能normal状态,否则disable状态 + var minusStatus = num <= 1 ? 'disabled' : 'normal'; + // 将数值与状态写回 + this.setData({ + num: num, + minusStatus: minusStatus + }); + }, + /* 点击加号 */ + bindPlus: function() { + var num = this.data.num; + // 不作过多考虑自增1 + num ++; + // 只有大于一件的时候,才能normal状态,否则disable状态 + var minusStatus = num < 1 ? 'disabled' : 'normal'; + // 将数值与状态写回 + this.setData({ + num: num, + minusStatus: minusStatus + }); + }, + /* 输入框事件 */ + bindManual: function(e) { + var num = e.detail.value; + // 将数值与状态写回 + this.setData({ + num: num + }); + } +}) +``` +运行结果: +![](https://upload-images.jianshu.io/upload_images/19956127-2dd5bbce0a468057.gif?imageMogr2/auto-orient/strip) + + +demo下载地址:http://download.csdn.net/detail/michael_ouyang/9815524 + +原文作者: michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/70194144 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\264\255\347\211\251\350\275\246-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2105\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\264\255\347\211\251\350\275\246-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2105\357\274\211.md" new file mode 100644 index 0000000..fc1390f --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\350\264\255\347\211\251\350\275\246-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\345\225\206\345\237\216\347\263\273\345\210\227\357\274\2105\357\274\211.md" @@ -0,0 +1,588 @@ + + +续上一篇的文章:微信小程序之商品属性分类 —— 微信小程序实战商城系列(4) + + + +自从认识某人后,我收获了两个成功。登录成功、付款成功,而且还拥有了自己的一辆车: + +购物车 + +也发现了自己的不足之处: + +余额不足。 + + +为大家介绍的就是购物车 + +这里演示从商品列表中添加到购物车 + +下面先做商品列表页。如下图: +![](https://upload-images.jianshu.io/upload_images/19956127-04b9a687e0a1431a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + + + + + + +**布局分析:** + +首先一个list的主盒子,接着是item盒子,这是必须的。 +      然后把item分成左侧的图片部分,和右侧的说明部分(item盒子使用横向弹性盒) +            右侧的说明部分又分上下2部分(右侧说明部分盒子使用纵向弹性盒) +                  下面价钱购物车部分(下面价钱购物车部分也使用横向弹性盒,中间使用justify-content: space-between;填充空白) +![](https://upload-images.jianshu.io/upload_images/19956127-7ce5f0cd09cdc403.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + + + + + +**index.wxml:** +``` + + + + + 商品列表 + 更多 + + + + + + + + + + + + + + + {{item.name}} + + + + ¥{{item.price}} + + + + + + + +``` +**index.wxss:** +``` +/**index.wxss**/ +page{ + height: 100%; +} +.container{ + background: #f5f5f5; +} + +.tit{ + display: flex; + flex-direction: row; + justify-content: space-between; + height: 30px; + position: relative; +} +.tit::before{ + content:''; + background: #ffcc00; + width:5px; + height: 100%; + position: absolute; + left: 0; + top: 0; +} + +.title_val{ + padding: 0 15px; + font-size: 14px; + color: #555; + line-height: 30px; +} +.more{ + font-size: 12px; + line-height: 30px; + color: #999; + padding: 0 5px 0 0 ; +} +.goodslist{ + background: #fff; + display: flex; + flex-direction: column; +} +.goods{ + display: flex; + flex-direction: row; + border-bottom: 1px solid #ddd; +} +.good-img{ + padding: 5px; + width: 80px; + height: 80px; +} +.good-cont{ + display: flex; + flex: 1; + flex-direction: column; + font-size: 14px; +} +.goods-navigator{ + display: flex; + flex: 1; + flex-direction: column; + justify-content: center; +} +.good-name{ + display: flex; + flex: 1; + flex-direction: column; + color: #555; + justify-content: center; +} +.good-price{ + display: flex; + flex: 1; + flex-direction: row; + justify-content: space-between; + color:#e4393c; + font-weight: 600; +} +.cart{ + width: 40px; + height: 40px; + padding-right: 10px; +} +``` + +**index.js:** + +数据部分,一般情况都是访问接口获取数据的,这里并没有使用网络访问,为了简化demo,直接把一组数据放在data对象中。同学们可以根据其数据结构自己编写后台接口 +``` +Page({ + data: { + goodslist: [ + { + id:"001", + imgUrl:"http://img5.imgtn.bdimg.com/it/u=2906541843,1492984080&fm=23&gp=0.jpg", + name:"女装T恤中长款大码摆裙春夏新款", + price:"65.00" + }, + { + id:"002", + imgUrl:"http://img4.imgtn.bdimg.com/it/u=1004404590,1607956492&fm=23&gp=0.jpg", + name:"火亮春秋季 男青年修身款圆领男士T恤", + price:"68.00" + }, + { + id:"003", + imgUrl:"http://img1.imgtn.bdimg.com/it/u=2305064940,3470659889&fm=23&gp=0.jpg", + name:"新款立体挂脖t恤女短袖大码宽松条纹V领上衣显瘦休闲春夏", + price:"86.00" + }, + { + id:"004", + imgUrl:"http://img4.imgtn.bdimg.com/it/u=3986819380,1610061022&fm=23&gp=0.jpg", + name:"男运动上衣春季上新品 上衣流行装青年", + price:"119.00" + }, + { + id:"005", + imgUrl:"http://img1.imgtn.bdimg.com/it/u=3583238552,3525141111&fm=23&gp=0.jpg", + name:"时尚字母三角露胸t恤女装亮丝大码宽松不规则春夏潮", + price:"69.00" + }, + { + id:"006", + imgUrl:"http://img2.imgtn.bdimg.com/it/u=1167272381,3361826143&fm=23&gp=0.jpg", + name:"新款立体挂脖t恤短袖大码宽松条纹V领上衣显瘦休闲春夏", + price:"86.00" + }, + { + id:"007", + imgUrl:"http://img0.imgtn.bdimg.com/it/u=789486313,2033571593&fm=23&gp=0.jpg", + name:"时尚字母三角露胸t恤女装亮丝大码宽松不规则春夏潮", + price:"119.00" + }, + { + id:"008", + imgUrl:"http://img2.imgtn.bdimg.com/it/u=3314044863,3966877419&fm=23&gp=0.jpg", + name:"男运动上衣春季上新品 上衣流行装青年", + price:"69.00" + }, + ] + }, + // 加入购物车 + addcart:function(e){ + this.setData({ + toastHidden:false + }); + // 遍历列表 与 购物车列表 + for (var i in this.data.goodslist){ + // 列表中某一项item的id == 点击事件传递过来的id。则是被点击的项 + if(this.data.goodslist[i].id == e.target.id){ + // 给goodsList数组的当前项添加count元素,值为1,用于记录添加到购物车的数量 + this.data.goodslist[i].count = 1; + // 获取购物车的缓存数组(没有数据,则赋予一个空数组) + var arr = wx.getStorageSync('cart') || []; + // 如果购物车有数据 + if(arr.length>0){ + // 遍历购物车数组 + for(var j in arr){ + // 判断购物车内的item的id,和事件传递过来的id,是否相等 + if(arr[j].id == e.target.id){ + // 相等的话,给count+1(即再次添加入购物车,数量+1) + arr[j].count = arr[j].count + 1; + // 最后,把购物车数据,存放入缓存(此处不用再给购物车数组push元素进去,因为这个是购物车有的,直接更新当前数组即可) + try { + wx.setStorageSync('cart', arr) + } catch (e) { + console.log(e) + } + // 返回(在if内使用return,跳出循环节约运算,节约性能) + return; + } + } + // 遍历完购物车后,没有对应的item项,把goodslist的当前项放入购物车数组 + arr.push(this.data.goodslist[i]); + } + // 购物车没有数据,把item项push放入当前数据(第一次存放时) + else{ + arr.push(this.data.goodslist[i]); + } + // 最后,把购物车数据,存放入缓存 + try { + wx.setStorageSync('cart', arr) + // 返回(在if内使用return,跳出循环节约运算,节约性能) + return; + } catch (e) { + console.log(e) + } + } + } + } +}) +``` + +编写购物车部分,如下图所示: +![](https://upload-images.jianshu.io/upload_images/19956127-c7c741c71488f9ab.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + + + + + +**布局分析:** + +首先一个list的主盒子,接着是item盒子,这是必须的。 + +    然后把item分成左侧的图片部分,和右侧的说明部分(item盒子使用横向弹性盒) + +        右侧的说明部分又分上下2部分(右侧说明部分盒子使用纵向弹性盒) + +                        下面价钱、购物加减、购物车部分(使用纵向弹性盒) + +                最下面的购物加减、购物车部分(使用横向弹性盒,中间使用justify-content: space-between;填充空白) + + + + + + +**cart.wxml:** +``` + + + + +``` +**cart.wxss:** +``` +page { + background: #f2ebe3; +} + +.cart { + padding: 100px 0 0 0; + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; + color: #999; +} + +.cart image { + width: 66px; + height: 66px; + margin-bottom: 20px; +} + +.baoyou { + font-size: 18px; + color: #db2929; + padding: 10px; +} + +.goods { + background: #fff; + border-top: 1px solid #ddd; + margin-bottom: 10px; + padding: 10px 10px 0 10px; + display: flex; +} + +.goods image { + width: 80px; + height: 80px; + border: 1px solid #ddd; +} + +.goods .good-cont { + display: flex; + flex: 1; + flex-direction: column; + color: #555; + font-size: 14px; + padding: 5px; + height: 100px; +} + +.goods .good-cont .goods-navigator { + display: flex; + flex: 2; +} + +.goods .good-cont .good-price { + display: flex; + flex-direction: column; + flex: 3; +} + +.goods .good-cont .good-price .price { + font-size: 16px; + color: #ec5151; +} + +.goods .good-cont .good-price .btn-box { + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.goods .good-cont .good-price .btn-box image { + width: 23px; + height: 23px; + border: 0; + margin: 0; +} + +.goods .good-cont .good-price .btn { + display: flex; + flex-direction: row; +} + +.goods .good-cont .good-price .btn input { + margin: 0; + width: 40px; + text-align: center; + border: 1px solid #eee; + font-size: 16px; + height: 28px; +} + +.goods .good-cont .good-price .btn button { + margin: 0; +} + +.total { + height: 40px; + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 0 20px; +} + +.total .total_text { + display: flex; + color: #777; +} + +.total .total_text text { + color: #ec5151; +} + +.total .total_js { + color: #fff; + background: #ec5151; + height: 30px; + margin: 0; +} +``` +**cart.js:** +``` +Page({ + data: { + iscart: false, + cart: [], //数据 + count: 1, //商品数量默认是1 + total: 0, //总金额 + goodsCount: 0 //数量 + }, + onLoad: function (options) { + + }, + onShow: function () { + var that = this; + // 获取产品展示页保存的缓存数据(购物车的缓存数组,没有数据,则赋予一个空数组) + var arr = wx.getStorageSync('cart') || []; + // 有数据的话,就遍历数据,计算总金额 和 总数量 + if (arr.length > 0) { + for (var i in arr) { + that.data.total += Number(arr[i].price) * Number(arr[i].count); + that.data.goodsCount += Number(arr[i].count); + } + // 更新数据 + this.setData({ + iscart: true, + cart: arr, + total: that.data.total, + goodsCount: that.data.goodsCount + }); + } + }, + onHide: function(){ + // 清除数据 + this.setData({ + iscart: false, + cart: [], //数据 + total: 0, //总金额 + goodsCount: 0 //数量 + }); + }, + /* 减数 */ + delCount: function (e) { + console.log(e) + // 获取购物车该商品的数量 + // [获取设置在该btn的id,即list的index值] + if (this.data.cart[e.target.id.substring(3)].count <= 1) { + return; + } + // 商品总数量-1 + this.data.goodsCount -= 1; + // 总价钱 减去 对应项的价钱单价 + this.data.total -= Number(this.data.cart[e.target.id.substring(3)].price); + // 购物车主体数据对应的项的数量-1 并赋给主体数据对应的项内 + this.data.cart[e.target.id.substring(3)].count = --this.data.cart[e.target.id.substring(3)].count; + // 更新data数据对象 + this.setData({ + cart: this.data.cart, + total: this.data.total, + goodsCount: this.data.goodsCount + }) + // 主体数据重新赋入缓存内 + try { + wx.setStorageSync('cart', this.data.cart) + } catch (e) { + console.log(e) + } + }, + /* 加数 */ + addCount: function (e) { + // 商品总数量+1 + this.data.goodsCount += 1; + // 总价钱 加上 对应项的价钱单价 + this.data.total += Number(this.data.cart[e.target.id.substring(3)].price); + // 购物车主体数据对应的项的数量+1 并赋给主体数据对应的项内 + this.data.cart[e.target.id.substring(3)].count = ++this.data.cart[e.target.id.substring(3)].count; + // 更新data数据对象 + this.setData({ + cart: this.data.cart, + total: this.data.total, + goodsCount: this.data.goodsCount + }) + // 主体数据重新赋入缓存内 + try { + wx.setStorageSync('cart', this.data.cart) + } catch (e) { + console.log(e) + } + }, + /* 删除item */ + delGoods: function (e) { + // 商品总数量 减去 对应删除项的数量 + this.data.goodsCount = this.data.goodsCount - this.data.cart[e.target.id.substring(3)].count; + // 总价钱 减去 对应删除项的单价*数量 + this.data.total -= this.data.cart[e.target.id.substring(3)].price * this.data.cart[e.target.id.substring(3)].count; + // 主体数据的数组移除该项 + this.data.cart.splice(e.target.id.substring(3), 1); + // 更新data数据对象 + this.setData({ + cart: this.data.cart, + total: this.data.total, + goodsCount: this.data.goodsCount + }) + // 主体数据重新赋入缓存内 + try { + wx.setStorageSync('cart', this.data.cart) + } catch (e) { + console.log(e) + } + } +}) +``` + + +运行结果: +![](https://upload-images.jianshu.io/upload_images/19956127-43d4e05b55afc8aa.gif?imageMogr2/auto-orient/strip) + + + + +demo:http://download.csdn.net/detail/michael_ouyang/9825344 +原文链接:https://blog.csdn.net/michael_ouyang/article/details/70755892 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\351\241\266\351\203\250\345\257\274\350\210\252\346\240\217\357\274\210\351\200\211\351\241\271\345\215\241\357\274\211\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2101\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\351\241\266\351\203\250\345\257\274\350\210\252\346\240\217\357\274\210\351\200\211\351\241\271\345\215\241\357\274\211\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2101\357\274\211.md" new file mode 100644 index 0000000..e676d23 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\271\213\351\241\266\351\203\250\345\257\274\350\210\252\346\240\217\357\274\210\351\200\211\351\241\271\345\215\241\357\274\211\345\256\236\344\276\213-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\256\236\346\210\230\347\263\273\345\210\227\357\274\2101\357\274\211.md" @@ -0,0 +1,79 @@ +需求:顶部导航栏 + +**效果图:** +![](https://upload-images.jianshu.io/upload_images/19956127-c8fce2b6077bd870.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +**wxml:** +``` + + + {{item}} + + + + + + + + + + +``` +**wxss:** +``` +page{ + display: flex; + flex-direction: column; + height: 100%; +} +.navbar{ + flex: none; + display: flex; + background: #fff; +} +.navbar .item{ + position: relative; + flex: auto; + text-align: center; + line-height: 80rpx; +} +.navbar .item.active{ + color: #FFCC00; +} +.navbar .item.active:after{ + content: ""; + display: block; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 4rpx; + background: #FFCC00; +} +``` +**js:** +``` +var app = getApp() +Page({ + data: { + navbar: ['首页', '搜索', '我'], + currentTab: 0 + }, + navbarTap: function(e){ + this.setData({ + currentTab: e.currentTarget.dataset.idx + }) + } +}) +``` +**运行:** +![](https://upload-images.jianshu.io/upload_images/19956127-b6a186e578a43072.gif?imageMogr2/auto-orient/strip) +原文作者:[michael_ouyang](https://me.csdn.net/michael_ouyang) + +原文链接:https://blog.csdn.net/michael_ouyang/article/details/56488665 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\275\277\347\224\250\347\231\276\345\272\246api\350\216\267\345\217\226\345\244\251\346\260\224\344\277\241\346\201\257-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21016\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\275\277\347\224\250\347\231\276\345\272\246api\350\216\267\345\217\226\345\244\251\346\260\224\344\277\241\346\201\257-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21016\357\274\211.md" new file mode 100644 index 0000000..616c832 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\344\275\277\347\224\250\347\231\276\345\272\246api\350\216\267\345\217\226\345\244\251\346\260\224\344\277\241\346\201\257-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\21016\357\274\211.md" @@ -0,0 +1,99 @@ +下面介绍使用百度api来获取天气信息。 + + + +1> 第一步:先到百度开放平台http://lbsyun.baidu.com申请ak +http://lbsyun.baidu.com/index.php?title=wxjsapi/guide/key +![](https://upload-images.jianshu.io/upload_images/19956127-486dcc6ac6fd207b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +申请到ak后,在我的应用里就能查看到 +![](https://upload-images.jianshu.io/upload_images/19956127-af6d18112e655b4e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +2> 第二步:配置你的request合法域名 + +配置域名请到微信公众平台的后台里设置 +![](https://upload-images.jianshu.io/upload_images/19956127-176b1703e595b0ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +3> 第三步:下载百度地图的api ,链接:http://download.csdn.net/detail/michael_ouyang/9754015 +解压后,里面有2个js文件,一个是常规没压缩的,另一个是压缩过的 +PS:由于小程序项目文件大小限制为1M,建议使用压缩版的js文件! +![](https://upload-images.jianshu.io/upload_images/19956127-fc8f3ca7e7992eee.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +4> 第四步:引入JS模块 +在项目根目录下新建一个路径,将百度的js文件拷贝到新建的路径下,完成。 +如下图所示,新建路径 "libs/bmap-wx" ,将 bmap-xw.min.js 文件拷贝至 "libs/bmap-wx" 路径下。 +![](https://upload-images.jianshu.io/upload_images/19956127-862105b9301fab8b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +5> 第五步:在所需的js文件内导入js +// 引用百度地图,注意:require传入一个相对路径 +var bmap = require('../../libs/bmap-wx/bmap-wx.js');  + + +6> 第六步:编辑代码 +注意:此处楼主使用的ak是随便写的,同学们需要自行申请!!! +xxx.wxml: +``` + + {{weatherData}} + + + + + {{item.date}} + {{item.temperature}} + {{item.weather}} + {{item.wind}} + + +``` + +xxx.js: +``` +// 引用百度地图微信小程序JSAPI模块 +var bmap = require('../../libs/bmap-wx/bmap-wx.min.js'); + +Page({ + data:{ + ak:"FHG7utZtdyXN23W", + weatherData:'', + futureWeather:[] + }, + onLoad:function(options){ + var that = this; + // 新建bmap对象 + var BMap = new bmap.BMapWX({ + ak: that.data.ak + }); + var fail = function(data) { + console.log(data); + }; + var success = function(data) { + console.log(data); + + var weatherData = data.currentWeather[0]; + var futureWeather = data.originalData.results[0].weather_data; + console.log(futureWeather); + weatherData = '城市:' + weatherData.currentCity + '\n' + 'PM2.5:' + weatherData.pm25 + '\n' +'日期:' + weatherData.date + '\n' + '温度:' + weatherData.temperature + '\n' +'天气:' + weatherData.weatherDesc + '\n' +'风力:' + weatherData.wind + '\n'; + that.setData({ + weatherData: weatherData, + futureWeather: futureWeather + }); + } + + // 发起weather请求 + BMap.weather({ + fail: fail, + success: success + }); + } + +}) +``` +7> 第七步:运行 + ![](https://upload-images.jianshu.io/upload_images/19956127-2a44a5845feb57a2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +更多的百度地图api,可到github查看:https://github.com/baidumapapi/wxapp-jsapi + +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/55099684 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\215\225\345\220\221\346\225\260\346\215\256\346\265\201.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\215\225\345\220\221\346\225\260\346\215\256\346\265\201.md" new file mode 100644 index 0000000..b045ee3 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\215\225\345\220\221\346\225\260\346\215\256\346\265\201.md" @@ -0,0 +1,52 @@ +**单向数据流:**指的是我们先把模板写好,然后把模板和数据(数据可能来自后台)整合到一起形成HTML代码,然后把这段HTML代码插入到文档流里面。 + +**优点:**数据跟踪方便,流向单一,追寻问题比较方便【主要体现:微信小程序】。 + +**缺点:**就是写起来不太方便,如果修改UI界面数据需要维护对应的model对象。 + +**图形解说:** +![](https://upload-images.jianshu.io/upload_images/19956127-5559667bdbdb1d81.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +**例子:** + +想要类似vue中,文本框内容改变时,绑定该数据的地方也随着改变; + +**界面:** +![](https://upload-images.jianshu.io/upload_images/19956127-f6f23da8b3335e71.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +**逻辑层:** + +将界面上的数据再次同步回 数据源上 + +this.data.foo = e.detail.value  就只是改变数据源,要想改变数据源之后再渲染到页面上,需要this.setData({)} + +  + +# setData 作用:    +1.改变数据源 + +2.通知框架 数据源变了,需要重新渲染页面 +``` +// pages/shuju/shuju.js +Page({ + + data: { + foo:'hello wechat app' + }, + inputChangeHandle(e){ + // e.target -> 当前文本框 + console.log(e.detail.value) + + // 将界面上的数据再次同步回 数据源上 + // this.data.foo = e.detail.value 就只是改变数据源 + + // setData 作用:1.改变数据源 + // 2.通知框架 数据源变了,需要重新渲染页面 + this.setData({ foo:e.detail.value }) + } + +}) +``` +**效果:** +![](https://upload-images.jianshu.io/upload_images/19956127-dbd753f655337bc7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +版权声明:本文为CSDN博主「Anna·」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 +原文链接:https://blog.csdn.net/weixin_42220533/article/details/83586903 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\246\202\344\275\225\346\226\260\345\273\272\351\241\265\351\235\242-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\2104\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\246\202\344\275\225\346\226\260\345\273\272\351\241\265\351\235\242-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\2104\357\274\211.md" new file mode 100644 index 0000000..f201c10 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\246\202\344\275\225\346\226\260\345\273\272\351\241\265\351\235\242-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\2104\357\274\211.md" @@ -0,0 +1,28 @@ +例如在web的开发中,新建一个页面只需要新建一个html文件即可。 + +但是到在微信小程序中,新建一个页面也不只是新建一个wxml文件,那么该如何做呢?下面我们一起来学习 + +新建一个页面的步骤: +1> 必须要创建一个wxml文件和一个js文件,并且文件名要同名(例:test.wxml 和 test.js)。 +2> js文件内,需要写上注册页面的Page()函数! +3> 并且要到app.json文件中,注册新建页面的路径信息。 + +示例: + +新建了一个test.js文件和一个test.wxml文件, +以及在app.json文件内的”pages”数组内,放在第一个的页面,就是程序启动时,第一个所打开的页面。 +![](https://upload-images.jianshu.io/upload_images/19956127-bec86183cda11866.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +在test.js文件中,必须要有一个Page()函数 +![](https://upload-images.jianshu.io/upload_images/19956127-35e7590b2faa4f41.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +在wxml文件内,随便写一点内容(否则打开空白页,你都不知道是否成功运行项目) +![](https://upload-images.jianshu.io/upload_images/19956127-9e46d1f58f5d1ddd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +F5运行项目: +![](https://upload-images.jianshu.io/upload_images/19956127-0cdfd8be0077df36.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +成功新建了一个页面 +备注: +记得要新建js文件,并且要注册Page()函数,否则就会报如下错误 +![](https://upload-images.jianshu.io/upload_images/19956127-862125e3fd203f6d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/54923311 + + diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\270\203\345\261\200-\345\233\276\347\211\207+\346\226\207\345\255\227.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\270\203\345\261\200-\345\233\276\347\211\207+\346\226\207\345\255\227.md" new file mode 100644 index 0000000..6d5ab9c --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\270\203\345\261\200-\345\233\276\347\211\207+\346\226\207\345\255\227.md" @@ -0,0 +1,55 @@ +# 文字放置在图片的水平和垂直居中的位置上 + +效果图片 + +![](//upload-images.jianshu.io/upload_images/5379947-3eb78b753d0eddc7.png?imageMogr2/auto-orient/strip|imageView2/2/w/399/format/webp) + +wxml代码如下 + +``` + + + child + + +``` + +wxss代码如下 + +``` +.image { + width: 746rpx; +} + +.image-parent { + height: 746rpx; + position: relative; + border: 2rpx solid red; +} + +.child { + width: 100px; + height: 24px; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + margin: auto; + text-align: center; + background: yellowgreen; +} + +``` + +## 要点: + +1. 查看图片宽高比,上述示例中图片宽高比为1:1 +2. wxml中标签设置mode为'widthFix',即“宽度不变,高度自动变化,保持原图宽高比不变” +3. 设置image宽度为w,上述示例中w=746rpx +4. 设置image所在的父容器height值,根据图片的宽高比,算出来image的height值,并且赋值给父容器height,上述示例中父容器height=746rpx(这一步必须注意,如果不设置父容器height与image的height值相等,会出现不居中或者图片底部会有一栏空白) +5. 注意文字的样式.child中通过绝对布局和margin实现了垂直居中 + +作者:代码坊 +链接:https://www.jianshu.com/p/138252f2ad8c + diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\274\200\345\217\221-Flex\345\270\203\345\261\200.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\274\200\345\217\221-Flex\345\270\203\345\261\200.md" new file mode 100644 index 0000000..f49e171 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\274\200\345\217\221-Flex\345\270\203\345\261\200.md" @@ -0,0 +1,121 @@ +微信小程序页面布局方式采用的是`Flex`布局。 +`Flex`布局,是W3c在2009年提出的一种新的方案,可以简便,完整,响应式的实现各种页面布局。 +Flex布局提供了元素在容器中的对齐,方向以及顺序,甚至他们可以是动态的或者不确定的大小的。 +Flex布局的主要特征是能够调整其子元素在不同的屏幕大小中能够用最适合的方法填充合适的空间。 + +![](https://upload-images.jianshu.io/upload_images/22188-26c5fea609a6d54c.png?imageMogr2/auto-orient/strip%7CimageView2/2) + +Flex布局的特点: + +* 任意方向的伸缩,向左,向右,向下,向上 +* 在样式层可以调换和重排顺序 +* 主轴和侧轴方便配置 +* 子元素的空间拉伸和填充 +* 沿着容器对齐 + +微信小程序实现了`Flex`布局,简单介绍下`Flex`布局在微信小程序中的使用。 + +## 伸缩容器 + +设有`display:flex`或者`display:block`的元素就是一个`flex container`(伸缩容器),里面的子元素称为`flex item`(伸缩项目),`flex container`中子元素都是使用`Flex`布局排版。 + +* `display:block` 指定为块内容器模式,总是使用新行开始显示,微信小程序的视图容器(view,scroll-view和swiper)默认都是`dispaly:block`。 +* `display:flex`:指定为行内容器模式,在一行内显示子元素,可以使用`flex-wrap`属性指定其是否换行,`flex-wrap`有三个值:*nowrap(不换行)*,*wrap(换行)*,*wrap-reverse(换行第一行在下面)* + 使用`display:block`(默认值)的代码: + + ``` + + 1 + 2 + 3 + + ``` + + 显示效果: + +![](https://upload-images.jianshu.io/upload_images/22188-017d5c26b63d40cb.png?imageMogr2/auto-orient/strip%7CimageView2/2) + +改换成`display:flex`的显示效果: + +![](https://upload-images.jianshu.io/upload_images/22188-a63bcc3980f93abf.png?imageMogr2/auto-orient/strip%7CimageView2/2) + +可以从效果图看到`block`和`flex`的区别,子元素`view`是在换行显示(`block`)还是行内显示(`flex`)。 + +## 主轴和侧轴 + +`Flex`布局的伸缩容器可以使用任何方向进行布局。 +容器默认有两个轴:*主轴(main axis)*和*侧轴(cross axis)*。 +主轴的开始位置为`主轴起点`(main start),主轴的结束位置为`主轴终点`(main end),而主轴的长度为`主轴长度`(main size)。 +同理侧轴的起点为`侧轴起点`(cross start),结束位置为`侧轴终点`(cross end),长度为`侧轴长度`(cross size)。详情见下图: + +![](https://upload-images.jianshu.io/upload_images/22188-bbf58812dfcac77d.png?imageMogr2/auto-orient/strip%7CimageView2/2) + +注意,`主轴`并不是一定是`从左到右`的,同理`侧轴`也不一定是`从上到下`,主轴的方向使用`flex-direction`属性控制,它有4个可选值: + +* `row` :从左到右的水平方向为主轴 +* `row-reverse`:从右到左的水平方向为主轴 +* `column`:从上到下的垂直方向为主轴 +* `column-reverse`从下到上的垂直方向为主轴 + +如果水平方向为主轴,那个垂直方向就是侧轴,反之亦然。 +四种主轴方向设置的效果图: + +![](https://upload-images.jianshu.io/upload_images/22188-c3cae998d57982ef.png?imageMogr2/auto-orient/strip%7CimageView2/2) + +图中的实例展示了使用了不同的`flex-direction`值排列方向的区别。 +实例代码: + +``` + + + 1 + 2 + 3 + + + c1 + c2 + c3 + + +``` + +运行效果: + +![](https://upload-images.jianshu.io/upload_images/22188-1bdb989fea46fdc1.png?imageMogr2/auto-orient/strip%7CimageView2/2) + +## 对齐方式 + +子元素有两种对齐方式: + +> `justify-conent` 定义子元素在主轴上面的对齐方式 +> `align-items` 定义子元素在侧轴上对齐的方式 + +`justify-content`有5个可选的对齐方式: + +* `flex-start` 主轴起点对齐(默认值) +* `flex-end` 主轴结束点对齐 +* `center` 在主轴中居中对齐 +* `space-between` 两端对齐,除了两端的子元素分别靠向两端的容器之外,其他子元素之间的间隔都相等 +* `space-around` 每个子元素之间的距离相等,两端的子元素距离容器的距离也和其它子元素之间的距离相同。 + `justify-content`的对齐方式和主轴的方向有关,下图以`flex-direction`为`row`,主轴方式是`从左到右`,描述`jstify-content`5个值的显示效果: + + ![](https://upload-images.jianshu.io/upload_images/22188-e843b222e9ae5244.png?imageMogr2/auto-orient/strip%7CimageView2/2) + +`align-items`表示侧轴上的对齐方式: + +* `stretch` 填充整个容器(默认值) +* `flex-start` 侧轴的起点对齐 +* `flex-end` 侧轴的终点对齐 +* `center` 在侧轴中居中对齐 +* `baseline` 以子元素的第一行文字对齐 + +`align-tiems`设置的对齐方式,和侧轴的方向有关,下图以`flex-direction`为`row`,侧轴方向是`从上到下`,描述`align-items`的5个值显示效果: + +![](https://upload-images.jianshu.io/upload_images/22188-b9c64a339a543827.png?imageMogr2/auto-orient/strip%7CimageView2/2) + +有了主轴和侧轴的方向再加上设置他们的对齐方式,就可以实现大部分的页面布局了。 + +源代码地址:[https://github.com/jjz/weixin-mina/blob/master/pages/flex/flex.wxml](https://github.com/jjz/weixin-mina/blob/master/pages/flex/flex.wxml) +原文作者:DragonDean  +原文链接:https://www.cnblogs.com/dragondean/p/5922740.html diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\274\200\345\217\221\342\200\224\342\200\224\345\212\250\347\224\273\346\225\210\346\236\234.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\274\200\345\217\221\342\200\224\342\200\224\345\212\250\347\224\273\346\225\210\346\236\234.md" new file mode 100644 index 0000000..4252ddd --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\345\274\200\345\217\221\342\200\224\342\200\224\345\212\250\347\224\273\346\225\210\346\236\234.md" @@ -0,0 +1,103 @@ +动画效果的实现,使用wx.createAnimation实现。具体实现时,首先,创建动画对象,并设置相关的参数;其次,设置动画类型,并执行动画;第三,导出并设置动画数据;最后,将设置的动画数据动态配置相应的组件,以此实现组件的动画效果。 + +效果图 + + +代码示例 + +xxx.wxml + +移动 + +旋转 + +透明度 + +缩放 + +倾斜 + +变形 + +移动\n变小\n透明 + +www.wxjs + +Page({ + + /** + * 页面的初始数据 + */ + data: { + widthScreen:null, + moveData:null, + rotateData:null, + alphaData:null, + scaleData:null, + skewData:null, + matrixData:null + }, + + moveClick: function(){ + var animation = wx.createAnimation({ + duration: 3000, + delay: 0, + timingFunction: "ease", + }); + + animation.translate((this.data.widthScreen - 60), 0).step({duration: 3000}) + this.setData({moveData: animation.export()}) + }, + + rotateClick: function(even) { + var animation = wx.createAnimation({}) + animation.rotate(180).step({duration:3000}) + this.setData({rotateData: animation.export()}) + }, + + alphaClick: function(even) { + var animation = wx.createAnimation({}) + animation.opacity(0.1).step({duration: 2000}) + this.setData({alphaData: animation.export()}) + }, + + scaleClick: function(even) { + var animation = wx.createAnimation({}) + animation.scale(1.6).step({duration: 2000}) + this.setData({scaleData: animation.export()}) + }, + + skewClick: function(even) { + var animation = wx.createAnimation({}) + animation.skew(160).step({duration: 2000}) + this.setData({skewData: animation.export()}) + }, + + matrixClick: function(even) { + var animation = wx.createAnimation({}) + animation.matrix(1,3,4,5,2,2).step({ duration: 2000 }) + this.setData({ matrixData: animation.export() }) + }, + + queueClick: function() { + var animation = wx.createAnimation({}); + animation.translate((this.data.widthScreen - 60), 0).scale(0.3).opacity(0.5).step({duration: 3000}) + this.setData({queueData: animation.export() }) + }, + + /** + * 生命周期函数--监听页面加载 + */ + onLoad: function (options) { + // 获取屏蔽宽 + var thisBlock = this; + wx.getSystemInfo({ + success: function(res) { + thisBlock.setData({ + widthScreen: res.screenWidth + }) + }, + }) + } +} + diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\240\207\351\242\230\346\240\217\345\222\214\345\257\274\350\210\252\346\240\217\347\232\204\350\256\276\347\275\256-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\2107\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\240\207\351\242\230\346\240\217\345\222\214\345\257\274\350\210\252\346\240\217\347\232\204\350\256\276\347\275\256-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\2107\357\274\211.md" new file mode 100644 index 0000000..467c66a --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\240\207\351\242\230\346\240\217\345\222\214\345\257\274\350\210\252\346\240\217\347\232\204\350\256\276\347\275\256-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\2107\357\274\211.md" @@ -0,0 +1,33 @@ +# 设置标题栏 + +标题栏window +在app.json文件里面,通过window对象里面的属性进行设置 +![](https://upload-images.jianshu.io/upload_images/19956127-86d3647e5d7b2af3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +示例: +app.json: +![](https://upload-images.jianshu.io/upload_images/19956127-1c4aa532eb870347.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +运行: +![](https://upload-images.jianshu.io/upload_images/19956127-106efc08daaf2c7d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +# 设置导航栏 + +导航栏TabBar +如果我们的小程序是一个多 tab 应用(客户端窗口的底部或顶部有 tab 栏可以切换页面),那么我们可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面。 + +Tip: 通过页面跳转(wx.navigateTo)或者页面重定向(wx.redirectTo)所到达的页面,即使它是定义在 tabBar 配置中的页面,也不会显示底部的 tab 栏。 + +tabBar 是一个数组,只能配置最少2个、最多5个 tab,tab 按数组的顺序排序。 +![](https://upload-images.jianshu.io/upload_images/19956127-65d26a3a45415bb4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +![](https://upload-images.jianshu.io/upload_images/19956127-5a1d76badf342052.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +示例: +app.json: +![](https://upload-images.jianshu.io/upload_images/19956127-d1931701990d815b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +运行: +![](https://upload-images.jianshu.io/upload_images/19956127-6459114cc94b22e9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/55045300 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206.md" new file mode 100644 index 0000000..36f5134 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206.md" @@ -0,0 +1,110 @@ + +### 构建页面 + +#### 在index.wxml + +``` + + + view1 + view2 + {{clickmsg}} + + +``` + +### index.wxss + +``` +.view-item { + text-align: center; + padding: 10px; + background-color: burlywood; + border-radius: 5px; + margin: 20px; +} + +``` + +![](//upload-images.jianshu.io/upload_images/1773276-407c1e28a5f18873.png?imageMogr2/auto-orient/strip|imageView2/2/w/638/format/webp) + +### index.js + +``` + clickMe:function(e) { + // 通过dataset来将wxml中的数据给传递过来 + console.log(e.currentTarget.dataset) + count++ + this.data.clickmsg = '点击了' + e.currentTarget.id + '当前已经点击了' + count + '次' + // 必须要这样写才能更新数据 + this.setData(this.data) + } + +``` + +![](//upload-images.jianshu.io/upload_images/1773276-cb8ed10a15349ab9.png?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp) + +> 注意: 我们可以通过dataset来将wxml中的数据给传递过来,其中的age和name都是在wxml中设置的,命名规范必须是data-xxx,如果我们要取具体的某个值(例如name),可以使用`console.log(e.currentTarget.dataset.name)`: + +![](//upload-images.jianshu.io/upload_images/1773276-95d1d5f30dd33d39.png?imageMogr2/auto-orient/strip|imageView2/2/w/972/format/webp) + +### 页面跳转共有两种方式 + +``` +clickMe(e) { + wx.redirectTo({ + url: '../home/home' + }) + } + + clickMe(e) { + wx.navigateTo({ + url: '../home/home' + }) + } + +``` + +#### 两者的区别: + +* `wx.navigateTo`的执行: + * 假使我们从A页面跳转到home页面,再从home页面跳转到user,再从user页面返回,日志打印如下: + + ![](//upload-images.jianshu.io/upload_images/1773276-2390ac7d09614c1a.png?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp) + +> home会依次执行onload---onshow---onready,当页面从home跳转到user时,会先调用home的onhide,然后加载user,执行onload---onshow---onready.当从user返回时,user页面会销毁,执行user的onUnload,然后home的页面出现,执行home的onshow + +* `wx.redirectTo`: + + ![](//upload-images.jianshu.io/upload_images/1773276-40aece0f410a810a.png?imageMogr2/auto-orient/strip|imageView2/2/w/696/format/webp) + +> 与wx.navigateTo的区别在于,当从home跳转到user时,会执行home的onUnload的方法,实际是home在跳转时被销毁了,"替换"成了user的页面,当从user返回时,不再返回的是home页面,而是原来home的上一级页面. + +### tabbar之间的切换来实现跳转 + +tabbar的切换与iOS的tabbar十分相似.假使home和user两个page分别为tabbar的两个模块,且默认选中home,当小程序启动后,我们从点击user,再点击home,可以看到如下日志: + +![](//upload-images.jianshu.io/upload_images/1773276-13dd03292d7fa786.png?imageMogr2/auto-orient/strip|imageView2/2/w/872/format/webp) + +> 小程序启动后,会执行home的onLoad----onshow---onready函数,当我们点击tabbar切换到user时,会先执行home的onhide,然后再执行user的onLoad----onshow---onready函数;当我们再次点击tabbar切换home时,会执行user的onhide,再执行home的onshow.说明:此时页面中home和user同时存在,点击哪个显示哪个执行onshow(当然是指不是第一次加载的情况),原先显示的将执行onhide来隐藏自己. + +### 在.wxml中实现页面的跳转 + +``` + + + + +``` + +如果是想通过redirect方式跳转,只需要在navigate组件后声明即可: + +``` + + + +``` + +作者:元宝是只小肥猫 +链接:https://www.jianshu.com/p/4e9f4a15a38d + diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\347\232\204\344\275\234\347\224\250\345\237\237\345\222\214\346\250\241\345\235\227\345\214\226-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\2108\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\347\232\204\344\275\234\347\224\250\345\237\237\345\222\214\346\250\241\345\235\227\345\214\226-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\2108\357\274\211.md" new file mode 100644 index 0000000..9daf33f --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\347\232\204\344\275\234\347\224\250\345\237\237\345\222\214\346\250\241\345\235\227\345\214\226-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\2108\357\274\211.md" @@ -0,0 +1,53 @@ +# 文件作用域 +在 JavaScript 文件中声明的变量和函数只在该文件中有效;不同的文件中可以声明相同名字的变量和函数,不会互相影响。 + +示例: +通过全局函数 getApp() 可以获取全局的应用实例,如果需要全局的数据可以在 App() 中设置,如: +``` +/* app.js */ +App({ + globalData: 1 +}) +``` +``` +/* a.js */ +// 这是局部变量localValue +var localValue = 'a' +// 获取app.js的实例 +var app = getApp() +// 通过app的示例来操作全局的变量 +app.globalData++ +``` +``` +/* b.js */ +// 在不同的文件中可以重复定义localValue这个变量 +var localValue = 'b' +// 如果a.js文件先执行,那么b.js获取到的就是a.js执行过的变量数值 +console.log(getApp().globalData) +``` +模块化 +我们可以将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过 module.exports 或者 exports 才能对外暴露接口。 + +示例: +``` +/* common.js */ +function sayHello(name) { + console.log(`Hello ${name} !`) +} + ``` +``` +module.exports = { sayHello : sayHello} +在需要使用这些模块的文件中,使用 require(path) 将公共代码引入 +/* a.js */ +var common = require('common.js') +Page({ + helloMINA: function() { + common.sayHello('MINA') + } +}) +``` + +注意:require()中传入的是一个js文件的相对路径 + +原文作者:michael_ouyang +原文链接:https://blog.csdn.net/michael_ouyang/article/details/55046458 diff --git "a/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\347\232\204\345\212\250\346\200\201\344\277\256\346\224\271\350\247\206\345\233\276\345\261\202\347\232\204\346\225\260\346\215\256-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\2103\357\274\211.md" "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\347\232\204\345\212\250\346\200\201\344\277\256\346\224\271\350\247\206\345\233\276\345\261\202\347\232\204\346\225\260\346\215\256-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\2103\357\274\211.md" new file mode 100644 index 0000000..9a20347 --- /dev/null +++ "b/\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\347\232\204\345\212\250\346\200\201\344\277\256\346\224\271\350\247\206\345\233\276\345\261\202\347\232\204\346\225\260\346\215\256-\342\200\224\342\200\224-\345\276\256\344\277\241\345\260\217\347\250\213\345\272\217\346\225\231\347\250\213\347\263\273\345\210\227\357\274\2103\357\274\211.md" @@ -0,0 +1,25 @@ +我们在正常的开发上,一般都比较少把视图层上面的数据写成固定形式的,很多都是通过动态获取数据时并更新页面上的数据显示出来 + +下面让我们来一些学习,如何动态修改视图层的数据 + +需求:创建一个按钮,点击这个按钮,改变视图层上面的数据 + +示例: + +新建一个微信小程序的Hello World项目,找到index.wxml文件 + +index.wxml: +使用一个