在2020年7月7日微信小程序低調的開放了一個功能,微信小程序“分享到朋友圈”。最近被產品提了相關需求,過程中遇到了一些坑。作者帶着踩坑經驗,給大家介紹下這個功能,以及其如何實現。
概述
點擊右上角分享朋友圈
分享到朋友圈樣式
朋友圈打開樣式
這個功能目前只支持Android(在IOS高版本微信支持朋友圈打開小程序能力,但不能分享)。
用戶打開朋友圈分享的小程序,看到不是真正的小程序,而是原本頁面的“單頁模式”。
什麼是“單頁模式”?
以下是微信官方對於“單頁模式”的描述:
“單頁模式”下,頁面頂部固定有導航欄,標題顯示爲當前頁面 JSON 配置的標題。底部固定有操作欄,點擊操作欄的“前往小程序”可打開小程序的當前頁面。頂部導航欄與底部操作欄均不支持自定義樣式。
“單頁模式”默認運行的是小程序頁面內容,但由於頁面固定有頂部導航欄與底部操作欄,很可能會影響小程序頁面的佈局。因此,請開發者特別注意適配“單頁模式”的頁面交互,以實現流暢完整的交互體驗。
限制
另外,“單頁模式”存在着很多限制。以下是官方給出的禁用能力列表:
限制主要包括以下幾點:
- 頁面無登錄態,與登錄相關的接口,如
wx.login
均不可用 - 不允許跳轉到其它頁面,包括任何跳小程序頁面、跳其它小程序、跳微信原生頁面
- 若頁面包含 tabBar,tabBar 不會渲染,包括自定義 tabBar
- 本地存儲與小程序普通模式不共用
這些限制,讓 “單頁模式”只適用於內容展示,不適用於有較多交互 。
配置
針對“單頁模式”,新增了單頁模式相關配置。目前這個配置裏只有一個navigationBarFit屬性:
navigationBarFit屬性主要是針對原頁面設置了 自定義導航欄 的情況。也就是原頁面的json文件中配置了這個屬性:
{
// ...
"navigationStyle":"custom"
// ...
}
給大家看一下普通導航欄和自定義導航欄的區別,下圖是普通導航欄頁面:
下圖是自定義導航欄頁面,我們在原本的導航欄位置使用了banner:
"navigationStyle":"custom"
這個設置在“單頁模式”下也會生效。前文微信官方對“單頁模式”的描述有說到“頂部導航欄與底部操作欄均不支持自定義樣式”。如果我們在原頁面設置了自定義導航欄。那麼“單頁模式”樣式就會變成這樣:
通過設置navigationBarFit爲 squeezed
就可以解決這個問題:
{
// ...
"singlePage": {
"navigationBarFit": "squeezed"
}
// ...
}
設置後的樣式:
開發
接下來介紹如何在小程序中實現這個功能。
第一步在需要轉發朋友圈的頁面中註冊用戶點擊右上角轉發功能,這是實現轉發朋友圈功能的必要滿足條件。
onShareAppMessage: function () {
return {
title: '轉發標題',
path: '/pages/home/index',
imageUrl: '自定義圖片路徑'
}
}
第二步註冊分享朋友圈功能(從基礎庫 2.11.3
開始支持):
onShareTimeline: function () {
return {
title: '轉發標題',
query: 'from=pyq',
imageUrl: '自定義圖片路徑'
}
}
注意,這裏有個問題,分享朋友圈功能不支持自定義頁面路徑,意味着 只能轉發當前頁面 。如果當前頁面存在較多“單頁模式”限制功能,就可能讓我們的頁面不能按預期展示。
當頁面存在限制功能時,我們存在兩個方案,第一個方案,針對“單頁模式”做改動,不調用那些限制的功能。第二個方案,另外寫一個針對“單頁模式”的頁面。
這兩種方案都需要能判斷當前是否正處在小程序“單頁模式”。
我們通過判斷場景值(場景值用來描述用戶進入小程序的路徑)是否等於 1154 來判斷當前是否正處在小程序“單頁模式”。場景值可以在 App
的 onLaunch
獲取。
// app.js
App({
// ...
onLaunch(options) {
const { scene } = options;
this.isSinglePage = scene === 1154;
}
// ...
})
我們將是否正處在“單頁模式”的Boolean值放入App實例,方便全局拿到值。
接下來說說兩種方案。
第一種方案,在“單頁模式”不調用那些限制功能(這是一種不推薦的方案,代碼耦合性太強)。舉個例子:
const app = getApp();
Page({
// ...
onLoad() {
if (!app.isSinglePage) {
wx.login({
// ...
})
}
}
// ...
})
第二種方案,針對“單頁模式”另寫一個頁面。因爲分享朋友圈功能並不支持自定義頁面路徑,我們只能另外寫一個組件來作爲“單頁模式”的內容承載。
將isSinglePage放入頁面的初始數據,方便在wxml中拿到:
// pages/home/index.js
const app = getApp();
Page({
data: {
isSinglePage: app.isSinglePage,
}
// ...
})
home-single-page就是分享到朋友圈的內容承載組件:
// pages/home/index.json
{
// ...
"usingComponents": {
"home-single-page": "components/home-single-page/index"
},
}
當“單頁模式”時,我們展示 home-single-page
組件,否則就展示普通頁面內容:
// pages/home/index.wxml
<home-single-page wx:if="{{ isSinglePage }}" />
<view wx:else>
<!-- 普通頁面內容 -->
</view>
樣式上雖然搞定了,但是在原本的生命週期中可能會調用一些限制功能,或者跑一些其它“單頁模式”用不上的內容。我們得停止原本生命週期函數調用。
建議對傳入Page的對象進行統一處理,當“單頁模式”時,不調用原本的生命週期:
// pages/home/index.js
import ExtendPage from 'common/extend-page/index'
const app = getApp();
ExtendPage({
data: {
isSinglePage: app.isSinglePage,
}
// ...
})
ExtendPage函數針對“單頁模式”進行統一處理:
// common/extend-page/index.js
const app = getApp();
const PAGE_LIFE = [
'onLoad',
'onReady',
'onShow',
'onHide',
'onError',
'onUnload',
'onResize',
'onPullDownRefresh',
'onReachBottom',
'onPageScroll'
];
export default function(option) {
let newOption = {};
if(app.isSinglePage) {
newOption = PAGE_LIFE.reduce((res, lifeKey) => {
if (option[lifeKey]) {
res[lifeKey] = undefined;
}
return res;
}, {})
}
return Page({
...option,
...newOption,
});
}
在“單頁模式”下,我們將原本的生命週期都停止了調用。這樣就能很好的將“單頁模式”下的頁面和普通頁面進行解耦。
如果”單頁模式“頁面比較複雜,需要使用生命週期。我們也可以添加 singlePageLife
屬性,當處在“單頁模式”下,就調用 singlePageLife
內的生命週期:
// pages/home/index.js
import ExtendPage from 'common/extend-page/index'
const app = getApp();
ExtendPage({
data: {
isSinglePage: app.isSinglePage,
},
singlePageLife: {
onLoad() {
// ...
},
}
// ...
})
// common/extend-page/index.js
const app = getApp();
const PAGE_LIFE = [
'onLoad',
'onReady',
'onShow',
'onHide',
'onError',
'onUnload',
'onResize',
'onPullDownRefresh',
'onReachBottom',
'onPageScroll'
];
export default function(option) {
let newOption = {};
if(app.isSinglePage) {
const { singlePageLife } = option;
newOption = PAGE_LIFE.reduce((res, lifeKey) => {
if (singlePageLife[lifeKey]) {
res[lifeKey] = singlePageLife[lifeKey];
} else if(option[lifeKey]) {
res[lifeKey] = undefined;
}
return res;
}, {})
}
return Page({
...option,
...newOption,
});
}
文章如有疏漏、錯誤歡迎批評指正。
本文轉載自公衆號有贊coder(ID:youzan_coder)。
原文鏈接: