|
模板結(jié)構(gòu):
<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(){
//此處為刷新頂部收藏欄數(shù)據(jù)
that.getColAutData();
},1000)
},
4處為欄目收藏區(qū)域,使用了scroll-view組件,左右滑動(dòng)方式方便用戶查看自己已經(jīng)收藏的欄目。需要注意的是需要在小程序onLoad或onShow時(shí),取到欄目的個(gè)數(shù),再計(jì)算組件整體寬度。 模板:
<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>
邏輯(請(qǐng)注意wWidhth值的計(jì)算):
...
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 個(gè)人中心功能個(gè)人中心主簡(jiǎn)單呈現(xiàn)個(gè)人信息、用戶收藏的作者/欄目統(tǒng)計(jì)、用戶已瀏覽的文章記錄。值得注意的是,頁(yè)面onShow周期時(shí)需要刷新用戶的收藏統(tǒng)計(jì)信息。 1.9 瀏覽記錄功能瀏覽記錄模塊在個(gè)人中心頁(yè)面中: 1.數(shù)據(jù)來(lái)源為用戶瀏覽文章時(shí)的上報(bào),服務(wù)端做時(shí)間戳記錄(瀏覽去重)等工作。 2.在開(kāi)發(fā)列表加載邏輯時(shí),需要注意驗(yàn)證一下拿到數(shù)據(jù)的一致性。因?yàn)檫\(yùn)營(yíng)端可能已經(jīng)刪掉某篇文章,而用戶的上報(bào)的瀏覽記錄又是過(guò)去時(shí),所以對(duì)于這種情況的發(fā)生,需要在數(shù)據(jù)字段做標(biāo)記、或者在刪稿流程上形成通知機(jī)制。 1.10 評(píng)論功能因?yàn)樾畔徍撕偷卿洃B(tài)的問(wèn)題,騰訊大家小程序評(píng)論功能折中選擇調(diào)用【珊瑚評(píng)論】記錄接口,僅做評(píng)論內(nèi)容展示。 1.11 分享功能(含首頁(yè))
分享功能都在onShareAppMessage()函數(shù)里,不同于右上角分享按鈕,如果在頁(yè)面中某個(gè)地方添加分享功能,需要button綁定屬性open-type=”share”。除此之外,還需要相關(guān)分享屬性如:
<button class="choice-share-b" catchtap="onShareAppMessage" open-type="share" data-title="{{item.title}}" data-tid="{{item.tid}}"></button>
1.12 評(píng)分功能
評(píng)分功能在文章底層頁(yè)中,用戶對(duì)文章的評(píng)分操作會(huì)形成:
1.這一篇文章的評(píng)分?jǐn)?shù)據(jù)依據(jù)。 在開(kāi)發(fā)中,評(píng)分功能由多個(gè)功能函數(shù)組成,大致可以分為渲染、用戶操作、服務(wù)器操作回調(diào)、還有數(shù)據(jù)換算等一些函數(shù)方法。 1.13 海報(bào)生成功能
此功能報(bào)用于單篇文章及作者朋友圈傳播海報(bào)生成。 生成功能需要注意以下: 1.海報(bào)的生成使用小程序canvas組件(canvas功能及api能力詳見(jiàn)官網(wǎng)文檔)。 2.對(duì)于圖片素材,例如背景,二維碼等圖標(biāo),需要wx.downloadFile()函數(shù)支持(詳見(jiàn)文后封裝的常用函數(shù))。 3.圖片保存使用wx.canvasToTempFilePath()方法,調(diào)試階段建議使用wx.previewImage()來(lái)調(diào)試。 4.對(duì)于二維碼及素材的加載時(shí)機(jī),根據(jù)自己業(yè)務(wù)場(chǎng)景來(lái)處理。 5.不同機(jī)型每行的文字大小及換行,需要用函數(shù)來(lái)處理。 6.熟悉理解scene參數(shù),理解小程序不同方式(如掃碼)打開(kāi)場(chǎng)景值。 7.理解wx.createSelectorQuery()接口。 8.對(duì)于圓角的頭像處理,最好交給后端進(jìn)行圖像處理。前端canvas處理的話需要考慮內(nèi)存開(kāi)銷(xiāo),當(dāng)圖片太大時(shí)不適合。 9.文中的小程序碼為B碼,微信官方給到的為圖片二進(jìn)制流,需要做接口類(lèi)型指定處理。 10.適當(dāng)將素材進(jìn)行base64,并進(jìn)行本地緩存。 對(duì)于文字類(lèi)型的canvas繪圖,需要經(jīng)常計(jì)算字符多少,換行計(jì)算。分享一下這兩個(gè)函數(shù):
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 消息模板(暫未上線)
消息模板根據(jù)產(chǎn)品的實(shí)際業(yè)務(wù)來(lái)做開(kāi)發(fā),建議低頻的推送用戶。 小程序模板功能中需要向接口傳遞formId。在發(fā)送給用戶id上,建議合理的進(jìn)行分組(如用戶訂閱欄目或者作者openid進(jìn)行分組)。如果發(fā)生文章更新,推送文章更新的消息模板。 二、樣式表現(xiàn)2.1 雪碧圖合并技巧小程序中出現(xiàn)了一個(gè)新單位rpx(responsive pixel),官方規(guī)定屏幕寬度為20rem,規(guī)定屏幕寬為750rpx。(在開(kāi)發(fā)前盡量和視覺(jué)設(shè)計(jì)老師約定好設(shè)計(jì)文稿,例如750像素寬的設(shè)計(jì)稿能方便我們開(kāi)展工作)。 雪碧圖:
雪碧圖自動(dòng)生成圖片及代碼(建議靈活使用,本工具用于移動(dòng)端項(xiàng)目雪碧圖生成):
工具鏈接: https://code.ahthw.com/tools/csssprite/ 2.2 tabBar導(dǎo)航欄圖標(biāo)大小建議tabBar常規(guī)為圖標(biāo)搭配標(biāo)題,具體配置可參考官方文檔:鏈接 https://developers.weixin.qq.com/miniprogram/dev/framework/config.html
對(duì)比官方參考,大家小程序略去了tabBar.list.text配置,這樣的處理方式主要是為還原設(shè)計(jì)稿。每個(gè)圖標(biāo)素材的像素大小為81px*81px,通過(guò)嘗試:文字區(qū)域建議35px。
2.3 wxml數(shù)據(jù)綁定中巧用三元運(yùn)算合理的使用三元運(yùn)算,使代碼更簡(jiǎn)潔。 樣式模板舉例:
<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>
內(nèi)容顯示:
<view ...>{{item.have == 1 ? '取消收藏:'收藏''}}</view>
2.4 wxss技巧1.text-align:justify;可以將內(nèi)容左右對(duì)齊,使內(nèi)容外觀更整齊。 2.原生組件層級(jí)特別高,例如canvas,在長(zhǎng)頁(yè)面時(shí)會(huì)留下陰影,巧用position:fixed屬性,在父層級(jí)可以使頁(yè)面整體長(zhǎng)度等于視窗高度,避免陰影出現(xiàn)。 3.巧用-webkit-line-clamp屬性,如 word-break:break-all; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; 表示當(dāng)一段文字超過(guò)2行時(shí),出現(xiàn)省略號(hào)。這樣在開(kāi)發(fā)時(shí)不擔(dān)心文字多少,也不要求接口數(shù)據(jù)對(duì)字符串長(zhǎng)度限制,并且不需要前端進(jìn)行函數(shù)截取。 4.當(dāng)頁(yè)面未加載成功時(shí),loading展示盡量以樣式、本地的base64文件及css3動(dòng)畫(huà)組成,提高頁(yè)面性能。 5.對(duì)于可以預(yù)處理的數(shù)據(jù),可以先提前加載渲染好,用樣式操控顯示隱藏。 6.rpx可以用在背景元素等css less屬性上。 7.@import “*.wxss”的使用能更好的進(jìn)行樣式復(fù)用。 8.為顯示的圖片view做一個(gè)背景樣式,容錯(cuò)圖片打不開(kāi)等意外因素。 9.使用image組件的mode=”widthFix”,可以保證文章底層中配圖寬度不變的情況下高度自適應(yīng)。 三、代碼開(kāi)發(fā)維護(hù)3.1 Wxpage框架騰訊大家小程序選用wxpage框架。【鏈接】 https://github.com/tvfe/wxpage WXPage 是一個(gè)極其輕量的微信小程序開(kāi)發(fā)框架,其中的API蘊(yùn)含了“極致頁(yè)面打開(kāi)速度的思想”,為可維護(hù)性與開(kāi)發(fā)效率而設(shè)計(jì)的功能,框架來(lái)自“騰訊視頻”小程序的項(xiàng)目沉淀。 框架對(duì)小程序生命周期的擴(kuò)展(如onNavigate、onAppLaunch等很多有意思的擴(kuò)展)、組件的依賴、實(shí)例方法(如 emit、$put)、實(shí)用函數(shù)等都有一系列獨(dú)特的包裝,適用于組件開(kāi)發(fā)。 特別感謝sendguan(關(guān)開(kāi)設(shè))在大家小程序開(kāi)發(fā)中無(wú)私支持。 3.2 工具方法模塊化管理這里的工具方法指的是一些公用的方法或代碼。通常根據(jù)業(yè)務(wù)的需要,我們可以建立一到多個(gè)模塊,在模塊里封裝一些公用方法,一來(lái)方便調(diào)用,二來(lái)方便維護(hù),如:
//Api.js let Api = {
fun1: function() {
...
},
fun2: function() {
...
},
};//接口module.exports = {
fun1: fun1
};
這里分享一些大家小程序開(kāi)發(fā)中封裝的方法:
function downFile(url, callback) {
wx.downloadFile({
url: url,
success: function(res) {
callback(res.tempFilePath)
}
})
}// get請(qǐng)求方法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請(qǐng)求方法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++) {
//判斷如果數(shù)組還有可以取出的元素,以防下標(biāo)越界
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,在大家小程序開(kāi)發(fā)過(guò)程中,實(shí)際結(jié)合了Wxpage對(duì)子模板、組件的定義方法。 模板示例(代碼來(lái)源:何潤(rùn)鋒工作室小程序):
<!-- 引入子組件模板 -->
<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}
|