模板結構: <view class="box_start {{item.have == 1 ? 'on':'out'}}" catchtap="onRecommStart" data-id="{{item.id}}" data-parentid="{{item.first_letter}}" data-have="{{item.have}}"></view> 收藏按鈕處理方法: onRecommStart:function(e){ let that = this; let user = wx.getStorageSync('user') || {}; let id = e.currentTarget.dataset.id; let parentid = e.currentTarget.dataset.parentid; let have = e.currentTarget.dataset.have; let list = vm.$data().authors; //新增 let alist = {"pid":parentid,"aid":id} wx.showLoading({ title: '正在處理', }); if (!have){ Api.fetchPost(Api.collection,{userid:user.openid,id:id,type:1,have:1}, (err, res) => { if (res.ret == 200){ wx.hideLoading(); } else {...} }); }else{ Api.fetchPost(Api.collection,{userid:user.openid,id:id,type:1,have:0}, (err, res) => { if (res.ret == 200){ wx.hideLoading(); } else {...} }); } //此處找到操作的元素位置 list[parentid].map(item => { if(item.id == id){ item.have = !item.have; } return item }); vm.$set({authors:list}); setTimeout(function(){ //此處為刷新頂部收藏欄數據 that.getColAutData(); },1000) }, 4處為欄目收藏區域,使用了scroll-view組件,左右滑動方式方便用戶查看自己已經收藏的欄目。需要注意的是需要在小程序onLoad或onShow時,取到欄目的個數,再計算組件整體寬度。 模板: <scroll-view scroll-x class="scrollcolumns"> <view class="scroll-view" style="width:{{wWidhth}}rpx"> <view class="first"></view> <block wx:for="{{columnColtDatas}}" wx:key="item"> .... </block> </view> </scroll-view> 邏輯(請注意wWidhth值的計算): ... colData.data.map(item => { Api.fetchGet(Api.column + item, (err, res) => { if (res.data) { columnAutData.push(res.data.channel); if (columnAutData.length == colData.data.length) { vm.$set({ columnColtDatas: columnAutData, wWidhth: (colData.data.length * 694) + 44, dataReady: true }); }; }; }); }); ... 1.8 個人中心功能個人中心主簡單呈現個人信息、用戶收藏的作者/欄目統計、用戶已瀏覽的文章記錄。值得注意的是,頁面onShow周期時需要刷新用戶的收藏統計信息。 1.9 瀏覽記錄功能瀏覽記錄模塊在個人中心頁面中: 1.數據來源為用戶瀏覽文章時的上報,服務端做時間戳記錄(瀏覽去重)等工作。 2.在開發列表加載邏輯時,需要注意驗證一下拿到數據的一致性。因為運營端可能已經刪掉某篇文章,而用戶的上報的瀏覽記錄又是過去時,所以對于這種情況的發生,需要在數據字段做標記、或者在刪稿流程上形成通知機制。 1.10 評論功能因為信息審核和登錄態的問題,騰訊大家小程序評論功能折中選擇調用【珊瑚評論】記錄接口,僅做評論內容展示。 1.11 分享功能(含首頁)
分享功能都在onShareAppMessage()函數里,不同于右上角分享按鈕,如果在頁面中某個地方添加分享功能,需要button綁定屬性open-type=”share”。除此之外,還需要相關分享屬性如: <button class="choice-share-b" catchtap="onShareAppMessage" open-type="share" data-title="{{item.title}}" data-tid="{{item.tid}}"></button> 1.12 評分功能
評分功能在文章底層頁中,用戶對文章的評分操作會形成:
1.這一篇文章的評分數據依據。 在開發中,評分功能由多個功能函數組成,大致可以分為渲染、用戶操作、服務器操作回調、還有數據換算等一些函數方法。 1.13 海報生成功能
此功能報用于單篇文章及作者朋友圈傳播海報生成。 生成功能需要注意以下: 1.海報的生成使用小程序canvas組件(canvas功能及api能力詳見官網文檔)。 2.對于圖片素材,例如背景,二維碼等圖標,需要wx.downloadFile()函數支持(詳見文后封裝的常用函數)。 3.圖片保存使用wx.canvasToTempFilePath()方法,調試階段建議使用wx.previewImage()來調試。 4.對于二維碼及素材的加載時機,根據自己業務場景來處理。 5.不同機型每行的文字大小及換行,需要用函數來處理。 6.熟悉理解scene參數,理解小程序不同方式(如掃碼)打開場景值。 7.理解wx.createSelectorQuery()接口。 8.對于圓角的頭像處理,最好交給后端進行圖像處理。前端canvas處理的話需要考慮內存開銷,當圖片太大時不適合。 9.文中的小程序碼為B碼,微信官方給到的為圖片二進制流,需要做接口類型指定處理。 10.適當將素材進行base64,并進行本地緩存。 對于文字類型的canvas繪圖,需要經常計算字符多少,換行計算。分享一下這兩個函數: getTrueLength: function(str) { let len = str.length, truelen = 0; for (let x = 0; x < len; x++) { if (str.charCodeAt(x) > 128) { truelen += 2; } else { truelen += 1; } } return truelen; }, cutString: function(str, leng) { let len = str.length, tlen = len, nlen = 0; for (let x = 0; x < len; x++) { if (str.charCodeAt(x) > 128) { if (nlen + 2 < leng) { nlen += 2; } else { tlen = x; break; } } else { if (nlen + 1 < leng) { nlen += 1; } else { tlen = x; break; } } } return tlen; } 1.14 消息模板(暫未上線)
消息模板根據產品的實際業務來做開發,建議低頻的推送用戶。 小程序模板功能中需要向接口傳遞formId。在發送給用戶id上,建議合理的進行分組(如用戶訂閱欄目或者作者openid進行分組)。如果發生文章更新,推送文章更新的消息模板。 二、樣式表現2.1 雪碧圖合并技巧小程序中出現了一個新單位rpx(responsive pixel),官方規定屏幕寬度為20rem,規定屏幕寬為750rpx。(在開發前盡量和視覺設計老師約定好設計文稿,例如750像素寬的設計稿能方便我們開展工作)。 雪碧圖:
雪碧圖自動生成圖片及代碼(建議靈活使用,本工具用于移動端項目雪碧圖生成):
工具鏈接: https://code.ahthw.com/tools/csssprite/ 2.2 tabBar導航欄圖標大小建議tabBar常規為圖標搭配標題,具體配置可參考官方文檔:鏈接 https://developers.weixin.qq.com/miniprogram/dev/framework/config.html
對比官方參考,大家小程序略去了tabBar.list.text配置,這樣的處理方式主要是為還原設計稿。每個圖標素材的像素大小為81px*81px,通過嘗試:文字區域建議35px。
2.3 wxml數據綁定中巧用三元運算合理的使用三元運算,使代碼更簡潔。 樣式模板舉例: <view class="box_start {{item.have == 1 ? 'on':'out'}}" catchtap="onRecommStart">...</view> <view wx:if="{{item.tag == 'title' || item.tag == 'text'}}" class="{{item.tag}} {{item['level'] ? 'h2' : ''}}">...</view> <view class="choice-dajia-view" style='height:{{viewIsshow == false ? windowHeight:"auto"}}' wx:if="{{!choiceWarp}}">...</view> 內容顯示: <view ...>{{item.have == 1 ? '取消收藏:'收藏''}}</view> 2.4 wxss技巧1.text-align:justify;可以將內容左右對齊,使內容外觀更整齊。 2.原生組件層級特別高,例如canvas,在長頁面時會留下陰影,巧用position:fixed屬性,在父層級可以使頁面整體長度等于視窗高度,避免陰影出現。 3.巧用-webkit-line-clamp屬性,如 word-break:break-all; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; 表示當一段文字超過2行時,出現省略號。這樣在開發時不擔心文字多少,也不要求接口數據對字符串長度限制,并且不需要前端進行函數截取。 4.當頁面未加載成功時,loading展示盡量以樣式、本地的base64文件及css3動畫組成,提高頁面性能。 5.對于可以預處理的數據,可以先提前加載渲染好,用樣式操控顯示隱藏。 6.rpx可以用在背景元素等css less屬性上。 7.@import “*.wxss”的使用能更好的進行樣式復用。 8.為顯示的圖片view做一個背景樣式,容錯圖片打不開等意外因素。 9.使用image組件的mode=”widthFix”,可以保證文章底層中配圖寬度不變的情況下高度自適應。 三、代碼開發維護3.1 Wxpage框架騰訊大家小程序選用wxpage框架。【鏈接】 https://github.com/tvfe/wxpage WXPage 是一個極其輕量的微信小程序開發框架,其中的API蘊含了“極致頁面打開速度的思想”,為可維護性與開發效率而設計的功能,框架來自“騰訊視頻”小程序的項目沉淀。 框架對小程序生命周期的擴展(如onNavigate、onAppLaunch等很多有意思的擴展)、組件的依賴、實例方法(如 emit、$put)、實用函數等都有一系列獨特的包裝,適用于組件開發。 特別感謝sendguan(關開設)在大家小程序開發中無私支持。 3.2 工具方法模塊化管理這里的工具方法指的是一些公用的方法或代碼。通常根據業務的需要,我們可以建立一到多個模塊,在模塊里封裝一些公用方法,一來方便調用,二來方便維護,如: //Api.js let Api = { fun1: function() { ... }, fun2: function() { ... }, };//接口module.exports = { fun1: fun1 }; 這里分享一些大家小程序開發中封裝的方法: function downFile(url, callback) { wx.downloadFile({ url: url, success: function(res) { callback(res.tempFilePath) } }) }// get請求方法function fetchGet(url, callback) { wx.request({ url: url, header: { 'Content-Type': 'application/json' }, success(res) { callback(null, res.data) }, fail(e) { console.error(e) callback(e) } }) }// post請求方法function fetchPost(url, data, callback) { wx.request({ url: url, method: 'POST', header: { "Content-Type": "application/x-www-form-urlencoded" }, data: data, success(res) { callback(null, res.data) }, fail(e) { console.error(e) callback(e) } }) }function fetchData(url, data, callback) { wx.request({ method: 'GET', url: url, data: data, success(res) { callback(res.data) }, fail(e) { console.error(e) callback(e) } }) } function removeBlock(s) { let regex = "\\((.+?)\\)"; return s.match(regex)[1] }; function removeAt(target, index) { return !!target.splice(index, 1).length; } function remove(target, item) { let index = target.indexOf(item); return index > -1 ? removeAt(target, index) : false; } function getDateDay(str) { let string = str.toString().substr(0, 10) return string.replace(/-/g, '.'); } function sliceArray(array, size) { let result = []; for (let x = 0; x < Math.ceil(array.length / size); x++) { let start = x * size; let end = start + size; result.push(array.slice(start, end)); } return result; }; function getArrayItems(arr, num) { let temp_array = new Array(); for (let index in arr) { temp_array.push(arr[index]); } let return_array = new Array(); for (let i = 0; i < num; i++) { //判斷如果數組還有可以取出的元素,以防下標越界 if (temp_array.length > 0) { let arrIndex = Math.floor(Math.random() * temp_array.length); return_array[i] = temp_array[arrIndex]; temp_array.splice(arrIndex, 1); } else { break; } } return return_array; } function reWirteUrl(url) { //console.log(url); if (url !== null) { if (!/^(http:\/\/)/i.exec(url)) { return url.replace(/(http:)?(?=\/\/img1\.gtimg\.com\/)/g, 'https:'); } else if (url.indexOf("https://") == -1) { return url.replace("http://", "https://"); } } else { return 'https://mat1.gtimg.com/news/images/static/weixin/wxss/basicprofile_r3.png'; } } 3.3 巧用wxml模板wxml支持import,在大家小程序開發過程中,實際結合了Wxpage對子模板、組件的定義方法。 模板示例(代碼來源:何潤鋒工作室小程序): <!-- 引入子組件模板 --> <import src="/comps/header.wxml" /> <import src="/comps/player.wxml" /> <import src="/comps/playerintro.wxml" /> <import src="/comps/recommvideo.wxml" /> <import src="/comps/recommnote.wxml" /> <import src="/comps/comment.wxml" /> <view class="wxpage" style="height:{{windowHeight} |