微信小程序實戰
微信小程序經過幾個月的內側,在今年的 1 月 9 日正式上線,在微信通訊錄頁面就可以搜索你想找的小程序,然后在發現頁最底部就會有你曾經瀏覽過的小程序的入口。
一番體驗后比橙子想象的效果好的多,所以自己起手也寫了一個。下面具體介紹細節。
想寫小程序的大家都知道只有企業賬戶可以發布,但是開發卻不需要企業賬號,但是我們需要實名認證我們的小程序賬號。
注冊賬號
直接給官網鏈接 https://mp.weixin.qq.com/debug/wxadoc/introduction/?t=201718#注冊小程序帳號
注意:沒有企業認證記得在 選擇主體類型 時選擇->其他組織,組織名稱自己起,機構代碼只要符合它的規則就行(輸入框下有提示直接復制粘貼),公章的掃描件上傳隨意圖片即可,管理員信息務必填寫真實信息(切記)
開發工具
在官網給出了下載入口 https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html?t=201715
安裝后會有掃碼登錄,然后按照這個鏈接執行 https://mp.weixin.qq.com/debug/wxadoc/introduction/?t=201718#登錄
記得你在官網注冊成功后小程序的 AppID,這里不用選擇本地開發目錄,為了起手方便當你添加項目時會問你是不是使用它的初始化模板(點擊使用)。
現在不出差錯的話你的頁面會出現 你的 頭像、用戶名、Hello world
如果顯示正常,恭喜你環境配置成功
有時卻不是那么順利,橙子在打開初始化項目報錯 Failed to load resource: net::ERR_NAME_NOT_RESOLVED
如果你有相同的錯誤解決辦法很簡單,關掉你的 V*N 即可(并不是所有 V*N 均存在問題,因為橙子咨詢其他人的 V*N 沒關也不會產生這個問題),記得重啟你的開發者工具。
起步
如果你了解幾種文件的作用可以跳過此步,不了解的可以看下官網起步教程, https://mp.weixin.qq.com/debug/wxadoc/dev/?t=201715
然后在上面鏈接仔細過一遍 框架、組件、API(切記認真閱讀)
也許你會問官網給的那么詳細我寫這個文章的意義在哪?
問的好,如果官網能給我一個完整的小程序我也不會費周折去自己寫,官網的 API 固然重要,都是人家開發的我們無權篡改,本文的目的是盡量讓大家少踩坑。
實戰
自己定義下產品詳情,一個展示視頻的 app,列表與播放頁,非常簡單的例子,上手簡單
這里涉及到網絡請求,首先去管理平臺,最下面的設置里配置你的服務器域名,你自己有接口最好,不必走本例的接口,根據官方文檔你可以寫出自己的程序
另外值得一提的就是 V2EX,知乎日報,豆瓣等都提供外部接口供大家使用,沒有接口的可以用本例的 https://api.idarex.com(填寫到**request合法域名**即可),每月只能修改三次謹慎使用
兩個頁面構成?倒也沒那個必要,增加整個小程序的體積,而且跨頁面傳輸數據多一層邏輯,這里采用 wx:if 實現條件渲染來實現。
我們只需要保留 index 文件夾下的文件
從全局文件改起 log 部分可以選擇保留,獲取用戶信息部份暫時用不到
app.js
App({
onLaunch: function(){
//調用API從本地緩存中獲取數據
var logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
}
})
全局的配置文件只需要 window 的基礎配置,這里修改 navigationBar 的內容樣式
app.json
{
"pages":[
"pages/index/index",
"pages/logs/logs"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#f8ac09",
"navigationBarTitleText": "敢玩原創視頻",
"navigationBarTextStyle":"black"
}
}
全局樣式沒有太多規則,這里避免后期的計算誤差問題注意兩點
app.wxss
/* 讓頁面高占滿全屏,類似給 html 設置 100% 讓子集元素的百分比為全屏的百分比 */
page {
height: 100%;
}
/* border-box 非常方便我們計算寬高 */
view, text {
box-sizing: border-box;
}
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
}
注: * 選擇器無效,強烈推薦使用 flex 進行布局,許多場景下普通的布局規則無效
主頁上面一個輪播,輪播圖改變時劇集也發生變化,默認的 player 隱藏,頁面結構如下
pages/index/index.wxml
<viewclass="container">
<swiperclass="swiper"bindchange="changeAlbum"indicator-dots="{{indicatorDots}}"autoplay="{{autoplay}}"duration="{{duration}}">
<blockwx:for="{{albums}}"wx:key="title">
<swiper-itemclass="swiper-item">
<imagesrc="{{item.cover}}"class="slide-image"/>
</swiper-item>
</block>
</swiper>
<scroll-viewclass="scroll-view"scroll-y="true"scroll-top="{{scrollTop}}">
<blockwx:for="{{videoList}}"wx:key="id">
<viewclass="video-item"data-id="{{index}}"catchtap="playVideo">
<imagesrc="{{item.cover}}"class="video-cover"></image>
<viewclass="video-info">
<textclass="video-title">{{item.title}}</text>
<textclass="video-play-count">{{item.play_count}}次播放</text>
</view>
</view>
</block>
</scroll-view>
<viewclass="player"wx:if="{{playerShow}}">
<iconclass="close"type="clear"size="45"color="rgba(255, 255, 255, 0.5)"catchtap="closeVideo"/>
<videoclass="video"src="{{videoUrl}}"autoplay="true"/>
<textclass="player-title">第{{videoIndex + 1}}集:{{videoTitle}}</text>
<viewclass="handle-bar">
<buttonclass="pre-btn"catchtap="preVideo">上一集</button>
<buttonclass="next-btn"catchtap="nextVideo">下一集</button>
</view>
<textclass="msg">沒看過癮?返回主頁側滑看更多炸裂專輯</text>
</view>
</view>
注: wx:for 建議寫到外層的 block 標簽中,而且必須加上 wx:key 定義你的標志字段,否則報錯。綁定事件如果為 tap,強烈建議使用 catchtap 而不采用 bindtap ,除非有特殊的冒泡觸發事件需求,否則使用 catchtap 避免冒泡。這里為什么使用 wx:if (首屏加載塊但切換成本大) 而不用官方建議的 hidden(首屏加載慢但切換成本小),在這個場景 player 層會頻繁切換適合使用 hidden,但 hidden 存在 bug,它隱藏不掉 view 層里面包含的元素,video 標簽依然暴露在且占據空間,破壞了我們的整體布局,實際測試 wx:if 在微應用場景無任何性能問題。
看下整體的樣式文件
pages/index/index.wxss
.swiper {
width: 100%;
height: 40%;
}
.swiper-item {
display: flex;
justify-content: center;
background: #dedede;
}
.slide-image {
width: 50%;
height: 100%;
}
.scroll-view {
height: 60%;
}
.video-item {
display: flex;
flex-direction: row;
justify-content: flex-start;
height: 115px;
padding: 10px;
background: rgba(255, 255, 255, 0.9);
border-bottom: 1px solid #dedede;
}
.video-cover {
display: block;
width: 150px;
height: 95px;
border-radius: 5px;
}
.video-info {
display: flex;
flex: 1;
flex-direction: column;
justify-content: space-between;
padding: 5px 0 5px 20px;
}
.video-title {
width: 100%;
line-height: 1.5;
font-size: 14px;
}
.video-play-count {
width: 100%;
display: flex;
justify-content: flex-end;
font-size: 12px;
}
.player {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 100;
background: #000;
}
.player-title {
width: 100%;
padding-left: 10px;
border-left: 3px solid #ccc;
overflow:hidden;
white-space:nowrap;
text-overflow:ellipsis;
color: #fff;
font-size: 14px;
}
.close {
position: fixed;
top: 20px;
right: 20px;
}
.video {
width: 100%;
margin-top: 80px;
}
.handle-bar {
display: flex;
flex-direction: row;
justify-content: space-around;
margin-top: 20px;
}
.pre-btn, .next-btn {
width: 40%;
background: #f49d0d;
color: #673806;
}
.button-hover {
background-color: #f9bd3a;
}
.msg {
width: 216px;
margin-left: -108px;
position: fixed;
bottom: 10px;
left: 50%;
font-size: 12px;
color: #999;
}
注:樣式以 flex + 百分比做整體布局,具體塊級元素和字體給 px 值
pages/index/index.js
//獲取應用實例
var app = getApp()
Page({
data: {
albums: [],
videoList: [],
scrollTop: 0,
indicatorDots: true,
autoplay: false,
duration: 1000,
playerShow: false,
videoUrl: '',
videoTitle: '',
videoIndex: 0
},
changeAlbum: function(e){
this.setData({
videoList: this.data.albums[e.detail.current].videos,
scrollTop: 0
})
},
playVideo: function(e){
let index = e.currentTarget.dataset.id
this.setData({
videoTitle: this.data.videoList[index].title,
videoUrl: this.data.videoList[index].play_url,
playerShow: true,
videoIndex: index
})
},
closeVideo: function(){
this.setData({
videoUrl: '',
playerShow: false
})
},
preVideo: function(){
let index = this.data.videoIndex
if (index === 0) {
wx.showToast({
title: '前面沒有啦!',
icon: 'loading',
duration: 10000
})
setTimeout(function(){
wx.hideToast()
},1000)
} else {
this.setData({
videoTitle: this.data.videoList[index - 1].title,
videoUrl: this.data.videoList[index - 1].play_url,
videoIndex: index - 1
})
}
},
nextVideo: function(){
let index = this.data.videoIndex
if (index === this.data.videoList.length - 1) {
wx.showToast({
title: '后面沒有啦!',
icon: 'loading',
duration: 10000
})
setTimeout(function(){
wx.hideToast()
},1000)
} else {
this.setData({
videoTitle: this.data.videoList[index + 1].title,
videoUrl: this.data.videoList[index + 1].play_url,
videoIndex: index + 1
})
}
},
onReady: function(){
var that = this
wx.request({
url: 'https://api.idarex.com/www/index',
success (res) {
that.setData({
albums: res.data.columns,
videoList: res.data.columns[0].videos
})
}
})
}
})
注: onReady 取代 onLoad 安卓 6.4.3 存在 bug,事件的傳參要通過 event.currentTarget.dataset 傳遞在 wxml 里通過定義 data-xxx 屬性綁定 key,其它代碼簡單易懂沒有高級語法,可以直接復制粘貼然后自定義修改
最后的效果如下
進階
如果你的小程序擁有一定的規模你一定會嘗試,模塊化開發、ES6,7 的高級語法、第三方庫等等。
實現原理就是按模塊化的開發去寫,npm 去安裝依賴庫,然后編譯成微信開發者工具可以識別的項目結構
映著需求簇生的 Github 項目列舉幾個, wepy 、 labrador
感興趣的可以點進去看看,使用與否取決于你項目的復雜程度,你的異步操作過多 ES6 的 promise 無法滿足你的需求,ES7 的 async/await 可以幫到你,或是你的狀態過多想使用 redux,你就可以嘗試微信小程序組件化開發框架。
本例中再封裝一層框架純屬沒事找事,沒有任何意義。
總結
小程序的評價褒貶不一,與其評價它存在的意義不如看下它的適用場景,對于功能性強的 App 很合適,本例不太合適但是人家騰訊視頻可以做小程序我們就可以做,說到以后的發展如何誰都說不準,最起碼穩定性可以保證,借著寫小程序可以加深對類 vue 框架的了解,內聯的事件寫法也是今后的一個趨勢,數據的綁定類 react 的 setData,如果你之前嘗試過這兩個框架開發小程序會非常得心應手。
來自:http://orangexc.xyz/2017/01/12/Wechat-small-app/