前段时间,微信公布了这样一个重磅炸弹 – 小程序。从没想过,原本作为平台之上的产物向上提升成为平台,因为原本的android应用容量不大,作为小程序这样的存在再次存于微信这样的大体量应用上。
文档中介绍的说法是:
微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验。
我还是太年轻了,毕竟是微信,敢想也敢做,不得不说腾讯的野心真是大。
原本在他刚出现时就想体验一把了,结果并不是所有人都能体验,而且毕竟刚刚开始还是有许多问题的,所以等到现在~
安装
-
小程序有自己的开发软件:
微信开发者工具
功能还是很齐全的除了还有些坑以外还是很不错的。当然用webstorm,vscode,甚至atom,sublime也能进行开发。
他的文件使用了自己的一套格式名称,但依旧是以js进行开发。 -
安装之后还需要一些其他的操作才能进入开发
首先是需要在微信公众平台中进行注册。
注册完成后进入小程序管理平台,在这里可以管理小程序的权限,查看数据报表,发布小程序等操作。
接下来在菜单中的进行如下操作:
保存AppID,等会儿会用到的。
以及第四步,将需要开发的接口保存在request合法域名内,否则开发时无法进行网络访问。本次还是使用gank的接口进行开发,感谢代码家大大。当然其实这一步不需要也可以,在开发时可以进行一些设置的修改
开发
那么首先,安装完微信开发者工具后打开并登陆,右下角点击添加新项目,这里除了项目目录项目名称外还需要上面步骤中获取到的appId,新建项目。
- 目录结构:
本次使用干货集中营的api。
├── pages 页面文件夹
│ ├── index 首页文件夹
│ │ └── index.js 首页js
│ │ └── index.wxml 首页html
│ │ └── index.wxss 首页style
│ ├── main 主页文件夹
│ │ └── main.js 主页js
│ │ └── main.wxml 主页html
│ │ └── main.wxss 主页style
│ ├── article 文章页文件夹
│ │ └── article.js 文章页js
│ │ └── article.wxml 文章页html
│ │ └── article.wxss 文章页style
├── utils 工具文件夹
│ └── Constants.js 全局共享常量
│ └── util.js 工具类
├── app.js 配置js
├── app.json 小程序配置页
├── app.wxss 配置style
└── project.config.json 工具配置
- 首先是首页:
效果:
点击banner上的图片后:
-
index.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}}" background-size="cover"></image> <text class="userinfo-nickname">{{userInfo.nickName}}\n小程序试手小Demo</text> </block> </view> <modal no-cancel="true" hidden="{{modalHidden}}" bindconfirm="onConfirmClick"> <view > <image class="modalImage" src="{{meizhi[current].url}}" mode="widthFix"></image> </view> </modal> <swiper class='banner' indicator-dots="true" autoplay="{{isScroll}}" bindchange="EventHandle"> <block wx:for="{{meizhi}}"> <swiper-item> <image src="{{item.url}}" mode="aspectFit" class="banner-image" bindtap="onImageClick" binderror="imageError"/> </swiper-item> </block> </swiper> <button class="enter-main" bindtap="enterMain">进入主页 → </button> </view>
上方获取微信头像和昵称是新疆项目时本身自带的内容,修改了一些显示方式和位置,在下方留下足够空间添加了一个banner和一个进入主页的按钮,并且点击banner时能够跳出一个浏览大图的dialog。
-
index.js:
const app = getApp() var Constants = require('../../utils/Constants.js'); var Util = require('../../utils/util.js'); Page({ data: { userInfo: {}, hasUserInfo: false, modalHidden: true, canIUse: wx.canIUse('button.open-type.getUserInfo'), meizhi: [], current: 0, isScroll: true, }, //事件处理函数 bindViewTap: function() { wx.navigateTo({ url: '../logs/logs' }) }, onLoad: function () { that = this; 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 }) } }) } requestMeizhi(); }, getUserInfo: function(e) { console.log(e) app.globalData.userInfo = e.detail.userInfo this.setData({ userInfo: e.detail.userInfo, hasUserInfo: true }) }, imageError: function (e) { this.setData({ meizhi: ['../logo.png', '../logo.png', '../logo.png', '../logo.png', '../logo.png'] }) }, EventHandle:function(event){ console.info(event) this.setData({ current: event.detail.current, }) }, onImageClick: function (event) { this.setData({ modalHidden: false, isScroll: false, }) }, onConfirmClick: function (event) { this.setData({ modalHidden: true, isScroll: true }); }, enterMain: function(e) { wx.navigateTo({ url: Constants.PAGE_MAIN, }) }, /** * 生命周期函数--监听页面显示 */ onShow: function () { this.setData({ isScroll: true, }) }, /** * 生命周期函数--监听页面隐藏 */ onHide: function () { this.setData({ isScroll: false, }) }, }); var that; function requestMeizhi() { wx.request({ url: "https://gank.io/api/data/福利/8/1", header: { "Content-Type": "application/json" }, success: function (res) { if (res == null || res.data == null || res.data.results == null || res.data.results.length <= 0) { console.error(Constants.ERROR_DATA_IS_NULL); return; } that.setData({ meizhi: res.data.results, }) } }); }
包括几个部分,一个是userinfo,这是自带的部分,请求也写好了的。然后是下方banner的请求,数据保存于meizhi数组中,每次只请求前8张。然后是dialog显示的部分,显示时获取当前的资源用于dialog显示,以及停止banner的自动播放。最后是一些点击事件。
-
index.wxss:
.userinfo { display: flex; flex-direction: row; align-items: center; margin-top: -50px; } .userinfo-avatar { width: 128rpx; height: 128rpx; margin: 10rpx; border-radius: 50%; align-items: right; } .userinfo-nickname { margin-left: 15px; font-size: 15px; color: #666666; } .usermotto { margin-top: 50px; } .banner-image{ display: initial } .banner{ box-shadow: 1px 0px 6px #cccccc; padding: 5px; border-radius: 1%; margin: 10px; margin-top: 40px; width: 70%; height: 600rpx; position: center; } .modalImage{ margin: auto; width: 100%; height: 1000rpx } .enter-main{ box-shadow: 1px 1px 1px #cccccc; position: relative; border-radius: 0; color: #fff; font-size: 14px; margin-top: 40px; background-color: #26a69a; }
android里有的cardview,同样这里也可以使用一些style属性表现出来。
- 列表主页:
效果预览:
-
main.wxml:
<view> <loading hidden="{{hidden}}"> 加载中... </loading> <view class="card" wx:for="{{AndroidList}}"> <view class="title-container" id="{{item.url}}&title={{item.desc}}" bindtap="onItemClick"> <image class="tag" src="./text.png" ></image> <text class="title">{{item.desc}}</text> </view> <view class="text-container" id="{{item.url}}&title={{item.desc}}" bindtap="onItemClick"> <text class="author">作者:{{item.who}}</text> <text class="time">发布时间:{{item.publishedAt}}</text> </view> </view> </view>
一个请求时显示的加载中的loading组件,主页上为一个列表。
-
main.js:
const app = getApp() var Constants = require('../../utils/Constants.js'); var Util = require('../../utils/util.js'); Page({ data: { AndroidList: [], hidden: false, nextPage: 1, }, onLoad: function () { that = this; this.setData({ nextPage: 1, }) requestAndroid(this.data.nextPage); }, onPullDownRefresh(){ console.info(e.detail) this.setData({ hidden: false, }) requestAndroid(this.data.nextPage); }, onReachBottom(){ this.setData({ hidden: false, }) requestAndroid(this.data.nextPage); }, onItemClick(event){ console.info(event.currentTarget.id) wx.navigateTo({ url: Constants.PAGE_ARTICLE + '?id=' + event.currentTarget.id }); } }) var that; function requestAndroid(page){ console.info(page); wx.request({ url: 'https://gank.io/api/data/Android/20/' + page, header: {}, success: function (res) { res.data.results = modifyTime(res.data.results); if (page == 1) { that.setData({ AndroidList: res.data.results, nextPage: page + 1, hidden: true, }) } else { that.setData({ AndroidList: that.data.AndroidList.concat(res.data.results), nextPage: page + 1, hidden: true, }) } } }) } function modifyTime(AndroidList){ for(var i=0;i<AndroidList.length;i++){ AndroidList[i].publishedAt = AndroidList[i].publishedAt.substring(5,10); } return AndroidList; }
主要是列表的请求以及loading是否显示的标志位,另外添加了一个上拉加载功能。
-
main.wxss:
.card{ box-shadow: 0px 1px 2px #999; margin: 15px; padding: 10px; } .title-container{ flex-direction: row; } .tag{ width:14px; height: 14px; margin-right: 5px; margin-top: 2px; } .text-container{ margin-top: 10px; display: flex; flex-direction: row; justify-content: space-between; align-items: center; } .title{ font-size: 15px; } .author{ color: #999999; font-size: 12px; } .time{ color: #999999; position: right; font-size: 12px; }
同样列表页使用一个card的样式显示,这里遇到了一个问题,单个item内标题前添加一个小的图标,没有找到text自带的方法,就自己添加了一个image,又想做到标题长度超过两行省略的动作,但是这样的代码会导致图标和标题不在同一行,暂时还未解决这个问题。
- 文章页面:
小程序非常坑爹的不能打开外链,就是他并没有webview这个功能。很气,又拿他没办法。
效果预览:
-
article.wxml:
<view class="container"> <text class="description">小程序不能打开外链,这有啥用??</text> <text class="title">标题:{{title}}</text> <image class="imangry" src="./shengqi.jpg" mode="widthFix"></image> <text class="url">链接:{{url}}</text> <button class="copy" bindtap='onClick'>{{isCopy?"已复制":"复制"}}</button> </view>
-
article.js:
Page({ data: { url: '', title: '', isCopy: false, }, onLoad: function (options) { console.info(options.id); console.info(options.title); this.setData({ url: options.id, title: options.title, }) }, onClick: function(event){ wx.setClipboardData({ data: this.data.url, }) this.setData({ isCopy: true, }) wx.getClipboardData({ success: function(res) { console.info(res) }, fail: function(res) {}, complete: function(res) {}, }) } })
将列表页由点击事件传递过来的url和标题显示于本页,并提供复制。
-
article.wxss:
.container{ padding: 10px; } .description{ margin: 20px; font-size: 18px; color: #555; align-items: left; } .title{ font-size: 14px; align-items: left; margin: 10px; color: #555; } .imangry{ width: 70%; } .url{ font-size: 12px; color: #777; margin: 20px; } .copy{ box-shadow: 1px 1px 1px #cccccc; position: relative; width: 70%; border-radius: 0; color: #fff; font-size: 14px; margin-top: 20px; background-color: #26a69a; }
无奈的添加一个表情。
- 各个配置页面
只列出修改了的文件:
-
Constants.js:
//url相关 var BASE_URL = "https://gank.io/api"; //error相关 var ERROR_DATA_IS_NULL = "获取数据为空,请重试"; //各个page的URL var PAGE_MAIN = "/pages/main/main"; var PAGE_INDEX = "/pages/index/index"; var PAGE_ARTICLE = "/pages/article/article"; module.exports = { BASE_URL: BASE_URL, ERROR_DATA_IS_NULL: ERROR_DATA_IS_NULL, PAGE_MAIN: PAGE_MAIN, PAGE_INDEX: PAGE_INDEX, PAGE_ARTICLE: PAGE_ARTICLE }
一些全局共享的常量。
-
app.json
{ "pages":[ "pages/index/index", "pages/main/main", "pages/article/article" ], "window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor": "#26a69a", "navigationBarTitleText": "干货集中营", "navigationBarTextStyle":"white" }, "networkTimeout": { "request": 10000, "connectSocket": 10000, "uploadFile": 10000, "downloadFile": 10000 }, "debug": true }
总结
总的来说,小程序开发还是很方便的,作为纯安卓开发者入手也是很快,只需要一些js基础,不过js和java在逻辑上还是很像的。当然他提供的功能还有许多尚未完善,也有许多的坑还没有填上,期待其发展。