上周一,技术主管忽然分给我一个任务,是微信页面的开发任务,专门指明了让用 iView Weapp来做。
iView Weapp是一套高质量的微信小程序 UI 组件库
意思很明显了,是开发微信小程序呢,之前从没做过小程序项目,不过很久之前自己学过一点儿,上手起来不难,这里分享一下实现的过程。
首先,需要安装小程序开发者工具,如果已经装过了,直接用就可以了。
按照微信开放文档 你的第一个小程序 新建一个小程序,开发过程中,小程序的 AppID可以先试用测试号。
在vs code中进行代码编写,vs code需要安装以下插件:
1. minapp
支持微信小程序标签、属性的智能补全,并且提示中包含文档内容(同时支持原生小程序、mpvue 和 wepy 框架,并提供 snippets)。
2.wechat-snippet
这个插件主要的功能就是代码辅助,代码片段自动完成,可以作为上个插件的补充。
3.wxml
这款插件用于将wxml代码进行高亮显示,并且提供代码格式化的功能,可将代码格式化为较易阅读的样式。
4.vscode weapp api
为 VSCode 提供微信小程序 API 提示及代码片段。
小程序目录结构 这里不再赘述,看官方文档就好。
小程序配置 按照文档来配置小程序, 全局配置和页面配置等。
新建的小程序默认已经有index和logs,那么,我这里是将index,复制一份改为mine,新建list,删除logs,list的数据将直接使用logs的数据做为例子,所以,logs可以先留着自己看看。
然后,做如下修改:
在app.json
:
pages:
"pages": [ "pages/index/index", "pages/list/list", "pages/mine/mine" ],
先在根目录下新建images,将需要用的图标放在images/tabBar/下,然后在app.json
增加 tabBar:
"tabBar": { "color": "#333333", "selectedColor": "#2e75b6", "list": [ { "pagePath": "pages/index/index", "selectedIconPath": "images/tabBar/tabBar-s1.png", "iconPath": "images/tabBar/tabBar-s2.png", "text": "首页" }, { "pagePath": "pages/list/list", "selectedIconPath": "images/tabBar/tabBar-k1.png", "iconPath": "images/tabBar/tabBar-k2.png", "text": "列表" }, { "pagePath": "pages/mine/mine", "selectedIconPath": "images/tabBar/tabBar-w1.png", "iconPath": "images/tabBar/tabBar-w2.png", "text": "我的" } ] },
效果如图:
快速上手 - iView Weapp按照文档,到 GitHub 下载 iView Weapp 的代码,将 dist 目录拷贝到自己的项目中。然后按需引用组件。
首页上方先放一个轮播图,直接使用 组件中的视图容器—— swiper 滑块视图容器 即可实现轮播图,还是先把图片放置在images
中,然后在index.js中配置data,并设置swiper的属性。
index.js:
Page({ data: { imgUrls: [ '../../images/index/pic1.jpg', '../../images/index/pic2.png', '../../images/index/pic3.jpg' ], indicatorDots: true, // 是否显示面板指示点 autoplay: true, // 是否自动切换 interval: 2000, // 自动切换时间间隔 duration: 1000, // 滑动动画时长 }, })
在index.wxml中:
<swiper indicator-dots="{{indicatorDots}}" autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}" class="swiper"> <block wx:for="{{imgUrls}}" wx:key="index"> <swiper-item> <image src="{{item}}" class="slide-image" /> </swiper-item> </block> </swiper>
index.wxss:
/**index.wxss**/ .swiper { height: 300rpx; border-bottom: 1rpx solid #ccc; } .slide-image { width: 100%; height: 100%; }
图标宫格、通告栏、信息卡片这三个模块,直接使用 iView Weapp 的组件。
在index.json中:
{ "usingComponents": { "i-grid": "../../dist/grid/index", "i-grid-item": "../../dist/grid-item/index", "i-grid-icon": "../../dist/grid-icon/index", "i-grid-label": "../../dist/grid-label/index", "i-icon": "../../dist/icon/index", "i-row": "../../dist/row/index", "i-card": "../../dist/card/index", "i-panel": "../../dist/panel/index", "i-notice-bar": "../../dist/notice-bar/index" } }
在index.wxml中,swiper下继续写:
<i-grid> <i-row> <i-grid-item> <i-grid-icon> <i-icon size="24" type="activity" /> <i-grid-label>宫格</i-grid-label> </i-grid-icon> </i-grid-item> <i-grid-item> <i-grid-icon> <i-icon size="24" type="addressbook" /> <i-grid-label>宫格</i-grid-label> </i-grid-icon> </i-grid-item> <i-grid-item> <i-grid-icon> <i-icon size="24" type="barrage" /> <i-grid-label>宫格</i-grid-label> </i-grid-icon> </i-grid-item> </i-row> <i-row> <i-grid-item> <i-grid-icon> <i-icon size="24" type="collection" /> <i-grid-label>宫格</i-grid-label> </i-grid-icon> </i-grid-item> <i-grid-item> <i-grid-icon> <i-icon size="24" type="computer" /> <i-grid-label>宫格</i-grid-label> </i-grid-icon> </i-grid-item> <i-grid-item> <i-grid-icon> <i-icon size="24" type="coupons" /> <i-grid-label>宫格</i-grid-label> </i-grid-icon> </i-grid-item> </i-row> </i-grid> <i-panel title="滚动 通告栏"> <i-notice-bar icon="systemprompt" loop speed="800"> 2018年世界杯,将于6月14日至7月15日举行;2018年世界杯,将于6月14日至7月15日举行; </i-notice-bar> </i-panel> <view style="margin: 16px">标题</view> <i-card full title="卡片标题" extra="额外内容" thumb="![](file:///C:\Users\SSJ\AppData\Roaming\Tencent\QQTempSys\%W@GJ$ACOF(TYDYECOKVDYB.png)https://i.loli.net/2017/08/21/599a521472424.jpg"> <view slot="content">内容不错</view> <view slot="footer">尾部内容</view> </i-card>
首页布局就算是完成了,是不是还挺简单的呢?跟着做下去,你将得到一个简单的微信小程序Demo。
获取用户信息:名字、头像,及 功能列表,直接上代码:
mine.js:
//mine.js //获取应用实例 const app = getApp() Page({ data: { motto: 'Hello World', userInfo: {}, hasUserInfo: false, canIUse: wx.canIUse('button.open-type.getUserInfo') }, //事件处理函数 bindViewTap: function() { // 点击头像跳转 wx.navigateTo({ url: '../mine/mine' }) }, onLoad: function () { if (app.globalData.userInfo) { this.setData({ userInfo: app.globalData.userInfo, hasUserInfo: true }) } else if (this.data.canIUse){ // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 // 所以此处加入 callback 以防止这种情况 app.userInfoReadyCallback = res => { this.setData({ userInfo: res.userInfo, hasUserInfo: true }) } } else { // 在没有 open-type=getUserInfo 版本的兼容处理 wx.getUserInfo({ success: res => { app.globalData.userInfo = res.userInfo this.setData({ userInfo: res.userInfo, hasUserInfo: true }) }, fail: function () { //获取用户信息失败后。请跳转授权页面 wx.showModal({ title: '警告', content: '尚未进行授权,请点击确定跳转到授权页面进行授权。', success: function (res) { if (res.confirm) { console.log('用户点击确定') wx.navigateTo({ url: '../tologin/tologin', }) } } }) } }) } }, getUserInfo: function(e) { // console.log(e) app.globalData.userInfo = e.detail.userInfo this.setData({ userInfo: e.detail.userInfo, hasUserInfo: true }) } })
mine.json:
{ "navigationBarTitleText": "个人中心", "usingComponents": { "i-panel": "../../dist/panel/index", "i-cell-group": "../../dist/cell-group/index", "i-cell": "../../dist/cell/index" } }
mine.wxml :
<!--mine.wxml--> <view class="container"> <view class="userinfo"> <button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button> <block wx:else> <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image> <text class="userinfo-nickname">{{userInfo.nickName}}</text> </block> </view> <view class="usermotto"> <text class="user-motto">{{motto}}</text> </view> </view> <i-panel title="功能"> <i-cell-group> <i-cell title="我的xx" is-link url="pages/mine/mine"></i-cell> <i-cell title="xxxxxxx" is-link url="pages/mine/mine"></i-cell> <i-cell title="xxxxxxx" is-link url="pages/mine/mine"></i-cell> <i-cell title="消费记录" is-link url="pages/mine/mine"></i-cell> </i-cell-group> </i-panel>
mine.wxss:
/**mine.wxss**/ .container { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: space-between; padding: 20rpx 0; box-sizing: border-box; } .userinfo { display: flex; flex-direction: column; align-items: center; } .userinfo-avatar { width: 128rpx; height: 128rpx; margin: 20rpx; border-radius: 50%; } .userinfo-nickname { color: #aaa; } .usermotto { margin: 20px; }
list.json:
{ "navigationBarTitleText": "列表页", "enablePullDownRefresh": true, // 下拉刷新 "usingComponents": { "i-card": "../../dist/card/index", "i-spin": "../../dist/spin/index", "i-load-more": "../../dist/load-more/index" } }
list.js:
//list.js const util = require('../../utils/util.js') Page({ data: { logs: [], }, onLoad: function() { this.clearCache(); //清本页缓存 this.getArticles(0); //第一次加载数据 }, getArticles: function(pageno) { this.setData({ logs: (wx.getStorageSync('logs') || []).map(log => { return util.formatTime(new Date(log)) }) }) }, })
list.wxml:
<!-- list.wxml --> <view class="container data-list"> <block wx:for="{{logs}}" wx:for-item="log" wx:key="index"> <i-card full title="{{index + 1}}.卡片标题" extra="额外内容" thumb="https://i.loli.net/2017/08/21/599a521472424.jpg"> <view slot="content">{{index + 1}}.内容不错</view> <view slot="footer">{{log}}</view> </i-card> </block> </view>
实现原理:
1、下拉刷新:由于小程序数据是实时渲染的。我们把data{}内的数据清空重新加载即可实现下拉刷新。
2、上拉加载更多(页面上拉触底事件):新获取的数据追加到data{}内的原数据即可。由于小程序数据是实时渲染,小程序在保持原数据显示不变的基础上,自动追加渲染显示新数据。注意(小程序官方有说明):
1、上拉加载更多 不要用scroll-view,用普通的view即可。
2、下拉刷新需要在 当前页面.json 里配置{ "enablePullDownRefresh": true }page()属性里有两个属性是关于页面下拉刷新 和 上拉加载更多的:
onPullDownRefresh Function 页面相关事件处理函数–监听用户下拉动作 onReachBottom Function 页面上拉触底事件的处理函数
主要参考了以上思路。
实现代码:
在list.wxml里view
的视图容器内的底部增加:
<i-spin size="large" fix wx:if="{{ spinShow }}"></i-spin> <i-load-more tip="{{loadMoreTip}}" loading="{{ loadMore }}" />
list.js修改为如下:
//list.js const util = require('../../utils/util.js') var page = 0; //当前页 var totalPages = 3; //总页数 Page({ data: { logs: [], //加载样式是否显示 spinShow: true, loadMore: true, loadMoreTip: '加载中', allLoaded: false }, onLoad: function() { this.clearCache(); //清本页缓存 this.getArticles(0); //第一次加载数据 }, getArticles: function(pageno) { let vm = this setTimeout(function() { //要延时执行的代码 vm.setData({ spinShow: false }) var res = (wx.getStorageSync('logs') || []).map(log => { return util.formatTime(new Date(log)) }); var tmpArr = vm.data.logs; tmpArr.push.apply(tmpArr, res); vm.setData({ logs: tmpArr }) vm.loadMore = true }, 3000) //延迟时间 这里是3秒 }, // 下拉刷新 onPullDownRefresh: function() { this.setData({ spinShow: true }) this.clearCache(); this.getArticles(0); //第一次加载数据 }, // 页面上拉触底事件(上拉加载更多) onReachBottom: function() { page++; if (!this.allLoaded) { if (page > totalPages - 1) { this.setData({ loadMore: false, loadMoreTip: '没有更多了', allLoaded: true // 若数据已全部获取完毕 }) } else { this.setData({ loadMore: true, loadMoreTip: '加载中', allLoaded: false // 若数据未获取完毕 }) this.getArticles(page); //后台获取新数据并追加渲染 } } else { this.setData({ loadMore: false, loadMoreTip: '没有更多了', allLoaded: false // 若数据未获取完毕 }) } }, // 清缓存 clearCache: function() { page = 0; //分页标识归零 this.setData({ logs: [] //文章列表数组清空 }); }, })
list.wxss:
.loading{ display: inline-block; margin-right: 12px; vertical-align: middle; width: 20px; height: 20px; background: transparent; border-radius: 50%; border: 2px solid #2d8cf0; border-color: #2d8cf0 #2d8cf0 #2d8cf0 transparent; animation: loading-spin 0.6s linear; animation-iteration-count: infinite; }
这里下拉的效果没做处理,上拉加载效果也比较粗糙。可以根据项目要求再进行美观优化,例如你可以自己在下拉时增加下拉到底、松开刷新、刷新中....等动态效果。
如果,最开始,你在看本篇文章时,一步一步跟着做,那么你也将得到一个小程序,实现的最终效果,如下图:
微信开放文档 你的第一个小程序
微信开放文档 小程序配置
微信开放文档 小程序目录结构
微信开放文档 组件
微信开放文档 swiper 滑块视图容器
安利向:用Visual Studio Code编写微信小程序
vscode 小程序开发插件
小程序入坑(一)list列表以及item详情页,json传送时间戳转换成年月日
微信小程序 下拉刷新/上拉加载更多 (上拉加载更多怎么实现)