利益相關
無
聲明
這並不是掘金官方小程序(貌似沒有搜到掘金 APP
對應的官方小程序),完全為第三者開發者開發,僅用於學習交流,禁止用於其他用途。若要使用官方正版,可訪問掘金 官方網站,或下載掘金官方 APP,或訪問掘金官方其他途徑。
該小程序所有 API
均來自掘金官方 web
網站和官方 Android
版 APP
(以 web
為主),UI
是照抄參照的掘金官方 Android
版 APP(ver 5.4.3)
。部分靜態資源(icon
、圖片等)直接從掘金官方 apk
里拷出來的。
該小程序代碼已開源,點擊可查看源碼,可隨意 star。也可以先掃描下方的小程序碼直接體驗。
寫在前面
前段時間寫了一個簡單的小程序 QuietWeather,源碼在這里,具體實現相關可查看這篇文章:兩天擼一個天氣應用微信小程序。但是這個 掘金小程序 和 QuietWeather 完全不是一個數量級的。so,該文章梳理內容會有那么一點兒多,想跳過的可以直接拉到最下面。。。
這里先上效果圖,感興趣的也可以 查看源碼 。實際體驗可掃描👆上面的小程序碼。
效果圖
對應頁面可打開掘金官方
APP
對比
PC
開發者工具錄制,會有些卡頓
文章數據入口調整了,也保留了動畫,請酌情忽略
gif
卡頓
實現
過濾器
在 filter
目錄下創建了一個 wxs
,里面是用到的過濾器,需要注意的是,wxs
的語法只能是 es5
,而且部分 js
語法是不支持的,具體支持的語法可查看微信小程序開發文檔。
組件
細分的話,細分的話目前總共寫了 8 個組件:
- 頁面為空組件
empty
- 沸點
item
組件feidianItem
:分為上半部分feidianItemTop
和下半部分組件feidianItemBottom
,會在沸點、贊過的沸點等相關頁面復用 - 文章
item
:有兩種展現樣式,這里寫了獨立的兩個組件:postItemOne
、postItemTwo
- 標簽展現
item
tagItem
:會在標簽管理等相關頁面復用 - 小冊
item
xiaoceItem
:會在小冊tab
、購買的小冊等相關頁面復用
組件相對比較簡單,基本上是以展現為主,並沒有太多交互,可下載源碼 在微信開發者工具調試查看相關效果。
頁面
HOME 頁
HOME
頁主要展現兩部分:頂部熱門文章推薦和下面的推薦文章列表,使用了兩個上面提到的組件: postItemOne
、postItemTwo
。且未登錄時,會有一個登陸提示。實現如下:
<wxs module='filters' src='../../filter/filter.wxs'></wxs>
<view class='container'>
<navigator url='/pages/login/login' wx:if='{{!logined}}'>
<view class='card guide'>
<view class='l'>
<view class='t'>登錄賬號</view>
<view class='c'>收藏文章,同步閱讀記錄,數據永不丟失</view>
</view>
<view class='r'>登錄</view>
</view>
</navigator>
<view class='hot card' wx:if='{{hotRecomment.length && hotRrecommendShow}}'>
<view class='btitle'>
<view class='l'>
<image class='icon' src='/img/ic_hot_home.png'></image>
<view>熱門推薦</view>
</view>
<view class='r'>
<image catchtap='refreshHot' class='refresh {{rotate}}' src='/img/refresh_icon.png'></image>
<image catchtap='closeHot' class='close' src='/img/chart_close.png'></image>
</view>
</view>
<postItemOne list='{{hotRecomment}}' graphics='{{true}}'></postItemOne>
</view>
<view class='timeline'>
<postItemTwo list='{{timeline}}'></postItemTwo>
</view>
</view>
其中,頂部熱門推薦的刷新會有以下的實現效果,這里需要稍微注意下:
熱門推薦點擊刷新,將當前的 3 條文章 objectId 以 id|id|id 的格式發送請求,然后重新拉取熱門推薦列表
看抓包,熱門推薦只返回 20 條,刷新一次移除三條,所以簡單處理的話,user_filter_entry 之后直接將熱門推薦數組的前三條移除即可;上面方式更精確,以防服務端之后又有什么返回呢
同時,搜索 tab
的頂部 banner
列表也是在這個頁面預先請求,然后保存到本地。實現如下:
getBannerImgList() {
const auth = this.data.auth
wx.request({
url: `${config.bannerRequestUrl}/get_banner`,
data: {
position: 'explore',
page: 0,
pageSize: 20,
platform: 'android',
device_id: auth.clientId,
client_id: auth.clientId,
token: auth.token,
src: 'android',
},
success: (res) => {
let data = res.data
if (data.s === 1) {
let bannerImgList = (data.d && data.d.banner) || []
wx.setStorage({
key: 'bannerImgList',
data: bannerImgList,
})
} else {
wx.showToast({
title: data.m.toString(),
icon: 'none',
})
}
},
fail: () => {
wx.showToast({
title: '網路開小差,請稍后再試',
icon: 'none',
})
},
})
},
然后配合下拉刷新 onPullDownRefresh
重新獲取數據。
其他具體細節這里不再贅述可查看源碼。
搜索 TAB
搜索 tab
頁兩部分組成:頂部的 swiper
和下面的熱門文章列表,這里復用 postItemOne
組件即可。頂部的 swiper
在首頁已經預先獲取過了(見上面),這里直接讀取即可。實現如下:
<wxs module='filters' src='../../filter/filter.wxs'></wxs>
<view class='container'>
<swiper autoplay circular interval="3500" duration="500" wx:if='{{bannerImgList.length}}' style='height:{{swiperHeight}}'>
<block wx:for="{{bannerImgList}}" wx:key="{{index}}">
<swiper-item>
<image src='{{item.screenshot}}' class="banner" mode='widthFix'></image>
</swiper-item>
</block>
</swiper>
<view class='hot card'>
<view class='btitle'>
<view class='l'>
<image class='icon' src='/img/pin_hot.png'></image>
<view>熱門文章</view>
</view>
</view>
<recommendItem list='{{rankList}}' graphics='{{false}}'></recommendItem>
</view>
</view>
沸點 TAB
該頁面復用的組件是 feidianItem
,頂部的熱門沸點是使用的 swiper
實現的。
該頁面有一個小細節需要稍微注意下:如果頁面保持在頂部,那么切換 tab
后需要重新刷新獲取新數據,如果頁面已經往下滑動了,那么切換 tab
后就不需要刷新獲取新數據。實現如下:
wxml
:
<view class='container'>
<view class='recommendList'>
<swiper autoplay='{{false}}' circular='{{false}}' duration="500" wx:if='{{recommendList.length}}' next-margin='100rpx' style='height:{{swiperHeight}}'>
<block wx:for="{{recommendList}}" wx:key="{{index}}">
<swiper-item>
<view class='item'>
<view class='title' wx:if='{{item.isRecommend}}'>
<image class='icon' src='/img/ic_topic_star.png'></image>
<text>編輯推薦</text>
</view>
<view class='title' wx:else>
<image class='icon' src='/img/pin_hot.png'></image>
<text>熱門沸點</text>
</view>
<view class='content'>
<view class='text'>{{item.content}}</view>
<view class='img' wx:if='{{item.pictures && item.pictures.length}}'>
<image mode='aspectFill' src='{{item.pictures[0]}}'></image>
</view>
</view>
</view>
</swiper-item>
</block>
</swiper>
</view>
<view class='pinList'>
<feidianItem item='{{item}}' wx:for='{{list}}' wx:key='{{index}}'></feidianItem>
</view>
</view>
js
:
const config = getApp().globalData.config
const utils = require('../../utils/utils.js')
Page({
data: {
COUNT: 30,
swiperHeight: 'auto',
recommendList: [],
list: [],
auth: {},
scrollTop: 0,
},
onShow () {
// 如果 scrollTop 為 0,也 reload
if (utils.pageReload(this.data.auth, [this.data.list]) || !this.data.scrollTop) {
this.init()
}
},
onPullDownRefresh() {
this.init()
},
init() {
wx.showLoading({
title: '數據加載中',
})
this.setData({
auth: {},
})
let auth = utils.ifLogined()
this.setData({
auth,
})
this.initSwiper()
this.getHotRecommendList()
this.pinListRecommend(true)
},
initSwiper() {
wx.getSystemInfo({
success: (res) => {
this.setData({
swiperHeight: `${(res.windowWidth || res.screenWidth) / 375 * 135}px`
})
},
})
},
// 熱門推薦列表
getHotRecommendList() {
const auth = this.data.auth
wx.request({
url: `${config.shortMsgMsRequestUrl}/getHotRecommendList`,
data: {
uid: auth.uid,
device_id: auth.clientId,
client_id: auth.client_id,
token: auth.token,
src: 'web',
},
success: (res) => {
let data = res.data
if (data.s === 1) {
this.setData({
recommendList: (data.d && data.d.list) || [],
})
} else {
wx.showToast({
title: data.m.toString(),
icon: 'none',
})
}
},
fail: () => {
wx.showToast({
title: '網路開小差,請稍后再試',
icon: 'none',
})
},
})
},
// 沸點列表
pinListRecommend(reload) {
const auth = this.data.auth
let list = this.data.list
if (utils.isEmptyObject(list) || reload) {
list = [{ createdAt: '' }]
}
let createdAt = (list.slice(-1)[0].createdAt) || ''
wx.request({
url: `${config.shortMsgMsRequestUrl}/pinList/recommend`,
data: {
uid: auth.uid,
device_id: auth.clientId,
token: auth.token,
src: 'web',
limit: this.data.COUNT,
before: createdAt,
},
success: (res) => {
let data = res.data
if (data.s === 1) {
wx.hideLoading()
let list = (data.d && data.d.list) || []
this.setData({
list: reload ? list : this.data.list.concat(list),
})
} else {
wx.showToast({
title: data.m.toString(),
icon: 'none',
})
}
},
fail: () => {
wx.showToast({
title: '網路開小差,請稍后再試',
icon: 'none',
})
},
})
},
onReachBottom() {
this.pinListRecommend()
},
onPageScroll (e) {
this.setData({
scrollTop: e.scrollTop,
})
},
onShareAppMessage(res) {
return {}
},
})
小冊 TAB
小冊頁面基本上沒有什么可說的,只有小冊展現。。。組件復用 xiaoceItem
,實現如下:
<view class='lists'>
<xiaoceItem list='{{xiaoceList}}'></xiaoceItem>
</view>
我的 TAB
該頁面以簡單的數目展現(未讀消息條數、收藏集數目、閱讀過的文章數)和跳轉為主,調用相關的 API
即可,沒有什么難度。實現如下:
wxml
:
<view class='wrapper'>
<view class='card profile' catchtap='navigatItem' data-url='/pages/personal/personal'>
<view class='info'>
<image class='avatar' src='{{userInfo.avatarLarge}}' wx:if='{{userInfo.avatarLarge}}'></image>
<image class='avatar' src='/img/empty_avatar_user.png' wx:else></image>
<view class='text'>
<view class='name'>{{userInfo.username || '登錄/注冊'}}</view>
<view>{{userInfo.jobTitle || '添加職位'}} @ {{userInfo.company || '添加公司'}}</view>
</view>
</view>
<view class='more'>
<view class='reddot' wx:if='{{auth && !userInfo.company}}'></view>
<image src='/img/profile_arrow.png'></image>
</view>
</view>
<view class='card items'>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/infoCenter/infoCenter'>
<view class='title'>
<image src='/img/ic_notification.png'></image>
<view>消息中心</view>
</view>
<view class='count reddot' wx:if='{{userNotificationNum}}'>{{userNotificationNum}}</view>
</view>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/favorate/favorate'>
<view class='title'>
<image src='/img/ic_heart_entry_bottom_full.png'></image>
<view>我喜歡的</view>
</view>
<view class='count'>{{userInfo.collectedEntriesCount || 0}}篇</view>
</view>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/collectionSet/collectionSet'>
<view class='title'>
<image src='/img/ic_collection_set.png'></image>
<view>收藏集</view>
</view>
<view class='count'>{{userInfo.collectionSetCount || 0}}個</view>
</view>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/purchasedXiaoce/purchasedXiaoce'>
<view class='title'>
<image src='/img/user_buy.png'></image>
<view>已購小冊</view>
</view>
<view class='count'>{{userInfo.purchasedBookletCount
|| 0}}本</view>
</view>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/myPins/myPins?liked=1'>
<view class='title'>
<image src='/img/user_liked_pin.png'></image>
<view>贊過的沸點</view>
</view>
<view class='count'>{{userInfo.likedPinCount || 0}}個</view>
</view>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/readHistory/readHistory'>
<view class='title'>
<image src='/img/view.png'></image>
<view>閱讀過的文章</view>
</view>
<view class='count'>{{userInfo.viewedEntriesCount || 0}}篇</view>
</view>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/manageTag/manageTag'>
<view class='title'>
<image src='/img/tag.png'></image>
<view>標簽管理</view>
</view>
<view class='count'>{{userInfo.subscribedTagsCount || 0}}個</view>
</view>
</view>
<view class='card items'>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/feedback/feedback' data-open='true'>
<view class='title'>
<image src='/img/icon_feed_back.png'></image>
<view>意見反饋</view>
</view>
</view>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/setting/setting' data-open='true'>
<view class='title'>
<image src='/img/settings.png'></image>
<view>設置</view>
</view>
</view>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/miniqrcode/miniqrcode' data-open='true'>
<view class='title'>
<image src='/img/qrcode.png' style='width:28rpx;height:28rpx;padding:10rpx'></image>
<view>小程序碼</view>
</view>
</view>
</view>
</view>
js
:
const utils = require('../../utils/utils.js')
const config = getApp().globalData.config
Page({
data: {
userInfo: {},
userNotificationNum: 0,
auth: {},
},
onShow () {
let auth = utils.ifLogined()
this.setData({
auth,
})
if (auth) {
this.getUserInfo()
this.userNotificationNum()
} else {
this.setData({
userInfo: {},
userNotificationNum: 0,
})
}
},
navigatItem (e) {
return utils.navigatItem(e)
},
// 獲取用戶信息
getUserInfo() {
const auth = this.data.auth
wx.request({
url: `${config.apiRequestUrl}/getUserInfo`,
data: {
src: 'web',
device_id: auth.clientId,
uid: auth.uid,
token: auth.token,
current_uid: auth.uid,
},
success: (res) => {
let data = res.data
if (data.s === 1) {
this.setData({
userInfo: data.d,
})
} else {
wx.showToast({
title: data.m.toString(),
icon: 'none',
})
}
},
fail: () => {
wx.showToast({
title: '網路開小差,請稍后再試',
icon: 'none',
})
},
})
},
// 消息中心消息條數
userNotificationNum() {
const auth = this.data.auth
wx.request({
url: `${config.notifyRequestUrl}/getUserNotificationNum`,
data: {
src: 'web',
uid: auth.uid,
token: auth.token,
},
success: (res) => {
let data = res.data
if (data.s === 1) {
this.setData({
userNotificationNum: data.d && data.d.notification_num,
})
} else {
wx.showToast({
title: data.m.toString(),
icon: 'none',
})
}
},
fail: () => {
wx.showToast({
title: '網路開小差,請稍后再試',
icon: 'none',
})
},
})
},
})
文章詳情頁
文章詳情頁返回的數據是整篇文章的 html
格式,如果是瀏覽器的話,直接顯示即可,小程序里這里使用的是 wxParse
解析的。實現如下:
<wxs module='filters' src='../../filter/filter.wxs'></wxs>
<import src="../../wxParse/wxParse.wxml"/>
<view class='container'>
<image wx:if='{{postInfo.screenshot}}' style='width:100%;height:340rpx;' mode='aspectFill' src='{{postInfo.screenshot}}'></image>
<view class='content'>
<view class='user'>
<view class='avatar' catchtap='toPersonal'>
<image mode='aspectFill' src='{{(postInfo.user && postInfo.user.avatarLarge) || "/img/default_avatar.png"}}'></image>
</view>
<view class='info'>
<view class='name'>{{postInfo.user && postInfo.user.username}}</view>
<view class='others'>
<text class='time'>{{postInfo.createdAt}}</text>
<text>閱讀 {{postInfo.viewsCount}}</text>
</view>
</view>
</view>
<view class='title'>{{postInfo.title}}</view>
<template is="wxParse" data="{{wxParseData:article.nodes}}"/>
</view>
</view>
至於評論相關的,還沒有寫。。。
個人中心頁
個人中心頁和我的頁面展現差不多,也是顯示條目和頁面跳轉為主,調用相關的 API
即可,不再贅述。實現如下:
<view class='wrapper'>
<view class='card profile'>
<view class='info'>
<image class='avatar' mode='aspectFill' src='{{userInfo.avatarLarge}}' wx:if='{{userInfo.avatarLarge}}'></image>
<image class='avatar' src='/img/empty_avatar_user.png' wx:else></image>
<view class='text'>
<view class='name'>{{userInfo.username}}</view>
<view class='jobtitle'>{{userInfo.jobTitle}}</view>
<view class='others'>{{userInfo.selfDescription }}</view>
</view>
</view>
<view class='bottom'>
<view class='l'>
<view class='action'>
<view>{{userInfo.followeesCount}}</view>
<view class='key'>關注</view>
</view>
<view class='action'>
<view>{{userInfo.followersCount}}</view>
<view class='key'>關注者</view>
</view>
</view>
<!-- <view class='edit'>編輯</view> -->
<image src='/img/ic_dynamic_vote.png' class='trend' catchtap='showDataTrend'></image>
</view>
</view>
<view class='card items'>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/dynamic/dynamic?thirduid={{thirduid}}' data-open='true'>
<view class='title'>
<view>動態</view>
</view>
</view>
</view>
<view class='card items'>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/myPins/myPins?thirduid={{thirduid}}' data-open='true'>
<view class='title'>
<view>沸點</view>
</view>
<view class='count'>{{userInfo.pinCount || 0}}</view>
</view>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/originalPost/originalPost?thirduid={{thirduid}}' data-open='true'>
<view class='title'>
<view>原創文章</view>
</view>
<view class='count'>{{userInfo.postedPostsCount}}</view>
</view>
<view class='item' wx:if='{{userInfo.postedEntriesCount}}' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/sharePost/sharePost?thirduid={{thirduid}}' data-open='true'>
<view class='title'>
<view>分享文章</view>
</view>
<view class='count'>{{userInfo.postedEntriesCount}}</view>
</view>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/collectionSet/collectionSet?thirduid={{thirduid}}' data-open='true'>
<view class='title'>
<view>收藏集</view>
</view>
<view class='count'>{{userInfo.collectionSetCount}}</view>
</view>
</view>
<view class='card items'>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/favorate/favorate?thirduid={{thirduid}}' data-open='true'>
<view class='title'>
<view>喜歡的文章</view>
</view>
<view class='count'>{{userInfo.collectedEntriesCount}}</view>
</view>
<view class='item' hover-class='hover-class' catchtap='navigatItem' data-url='/pages/subscribedTag/subscribedTag?thirduid={{thirduid}}' data-open='true'>
<view class='title'>
<view>關注的標簽</view>
</view>
<view class='count'>{{userInfo.subscribedTagsCount}}</view>
</view>
</view>
<view class='card items'>
<view class='item' wx:if='{{userInfo.community && userInfo.community.weibo && userInfo.community.weibo.username}}'>
<view class='title'>
<image src='/img/icon_profile_weibo.png'></image>
<view class='val'>{{userInfo.community.weibo.username}}</view>
</view>
</view>
<view class='item' wx:if='{{userInfo.blogAddress}}'>
<view class='title'>
<image src='/img/icon_profile_blog.png'></image>
<view class='val'>{{userInfo.blogAddress}}</view>
</view>
</view>
</view>
</view>
文章數據頁
文章數據頁就是顯示你的文章獲得了多少收藏、多少評論、多少閱讀相關的數據,該頁面主要是數字滾動動畫的實現。這里的實現思路是這樣的:
將數字從 0 到 N 縱向排列,然后 translateY
到相應的數字即可,主要的實現如下:
<view class='countInner' style='transform:translateY(-{{100*(item.length-1)/item.length}}%)' wx:for='{{filters.strToNumArr(userInfo.totalCollectionsCount)}}' wx:key='{{index}}' wx:for-item='item' wx:for-index='index'>
<view wx:for='{{item}}' wx:key='{{idx}}' wx:for-item='i' wx:for-index='idx'>{{i}}</view>
</view>
// 按照長度生成 0 字符串
generateZeroArr (len) {
Array.apply(null, Array(len)).map(function (item, i) {
return 0
})
}
其他細節不再贅述,可查看源碼。
消息中心頁
消息中心有兩個 tab
,可以點擊、滑動切換,這里的實現是 swiper
。這里需要注意的是:消息分為不同的 category
,不同的 category
展現的內容是不一樣的,所以這里需要區分下,目前我獲取到的 category
只有幾種,是否全部覆蓋所有的 category
只能等遇到沒有覆蓋的時候隨手補上了。。。實現如下:
<wxs module='filters' src='../../filter/filter.wxs'></wxs>
<view class='container'>
<view class='top tabs'>
<view class='inner'>
<view class='tab {{currentSwiper === "0" ? "active" : ""}}' data-index='0' catchtap='switchSwiper'>用戶消息</view>
<view class='tab {{currentSwiper === "1" ? "active" : ""}}' data-index='1' catchtap='switchSwiper'>系統消息</view>
</view>
<view class='bar' style='left:{{currentSwiper*50}}%'></view>
</view>
<swiper class='swiper' autoplay='{{false}}' indicator-dots='{{false}}' bindchange='swiperChanged' current='{{currentSwiper}}'>
<swiper-item item-id='0'>
<scroll-view scroll-y bindscrolltolower='getMoreUserNotification'>
<view class='item' wx:for='{{list}}' wx:key='{{index}}'>
<view class='avatar' data-id='{{item.users[0].objectId}}' catchtap='toPersonal'>
<image mode='aspectFill' src='{{item.users[0].avatarLarge || "/img/default_avatar.png"}}'></image>
</view>
<view class='content' wx:if='{{item.category==="collection"}}'>
<view>{{item.users[0].username}}等{{item.count}}人 喜歡了你的文章 <text data-id='{{item.entry && item.entry.objectId}}' catchtap='toPostDetail'>{{item.entry && item.entry.title}}</text></view>
<view class='time'>{{filters.timeBefore(item.updatedAtString)}}</view>
</view>
<view class='content' wx:elif='{{item.category==="comment"}}'>
<view>{{item.users[0].username}}回復了你在文章 <text data-id='{{item.entry && item.entry.objectId}}' catchtap='toPostDetail'>{{item.entry && item.entry.title}}</text> 的評論</view>
<view class='comment'>{{(item.reply && item.reply.content) || (item.comment && item.comment.content)}}</view>
<view class='time'>{{filters.timeBefore(item.updatedAtString)}}</view>
</view>
<view class='content' wx:elif='{{item.category==="follow"}}'>
<view>{{item.users[0] && item.users[0].username}} 關注了你</view>
<view class='time'>{{item.users[0] && item.users[0].jobTitle}}</view>
</view>
<view class='content' wx:elif='{{item.category==="comment-like"}}'>
<view>{{item.users[0] && item.users[0].username}} 贊了你在 <text>{{item.entry && item.entry.title}}</text> 的評論</view>
</view>
<view class='content' wx:elif='{{item.category==="pin-like"}}'>
<view>{{item.users[0] && item.users[0].username}} 贊了你的 <text>沸點</text></view>
<view class='time'>{{filters.timeBefore(item.updatedAtString)}}</view>
</view>
<view class='content' wx:elif='{{item.category==="pin-comment"}}'>
<view>{{item.users[0] && item.users[0].username}} 回復了你的 <text>沸點</text></view>
<view class='comment'>{{(item.reply && item.reply.content) || (item.pinComment && item.pinComment.content)}}</view>
<view class='time'>{{filters.timeBefore(item.updatedAtString)}}</view>
</view>
<view class='content' wx:else>未知狀態,可提交給開發者</view>
</view>
</scroll-view>
<empty wx:if='{{!list.length}}' tip='暫無消息'></empty>
</swiper-item>
<swiper-item item-id='1'>
<view wx:if='{{systemInfoList.length}}'>
不好意思,我沒有系統消息,所以看不到系統消息 API 的數據結構,也看不到樣式。。。
</view>
<empty wx:if='{{!systemInfoList.length}}' tip='暫時沒有系統通知'></empty>
</swiper-item>
</swiper>
</view>
動態頁
動態頁也需要稍微注意一點,動態頁分不同的 category
,這里覆蓋的有 follow
、collection
、subscribe
,如果遇到未覆蓋的只能順手補上。實現如下:
<wxs module='filters' src='../../filter/filter.wxs'></wxs>
<view class='container'>
<view class='item' wx:for='{{list}}' wx:key='{{index}}'>
<view class='inner' wx:if='{{item.category === "follow"}}'>
<view class='top'>
<view class='l'>
<image mode='widthFix' src='/img/ic_dynamic_user.png'></image>
<view>關注了:</view>
</view>
<view class='r'>{{filters.timeBefore(item.createdAtString)}}</view>
</view>
<view class='bottom'>
<view class='tagcard'>
<image mode='aspectFill' src='{{item.users[0].avatarLarge || "/img/entry_image_default.png"}}'></image>
<view class='others'>
<view class='title'>{{item.users && item.users[0].username}}</view>
<view class='info' wx:if='{{item.users && item.users[0].jobTitle && item.users[0].company}}'>{{item.users && item.users[0].jobTitle}} @ {{item.users && item.users[0].company}}</view>
</view>
</view>
</view>
</view>
<view class='inner' wx:if='{{item.category === "collection"}}'>
<view class='top'>
<view class='l'>
<image mode='widthFix' src='/img/ic_dynamic_collect.png'></image>
<view>喜歡了:</view>
</view>
<view class='r'>{{filters.timeBefore(item.createdAtString)}}</view>
</view>
<view class='bottom'>
<view class='tagcard' data-id='{{item.entry && item.entry.objectId}}' catchtap='toPostDetail'>
<image mode='aspectFill' src='{{item.entry.screenshotUrl || "/img/entry_image_default.png"}}'></image>
<view class='others'>
<view class='title'>{{item.entry && item.entry.title}}</view>
</view>
</view>
</view>
</view>
<view class='inner' wx:if='{{item.category === "subscribe"}}'>
<view class='top'>
<view class='l'>
<image mode='widthFix' src='/img/ic_dynamic_tag.png'></image>
<view>關注了 {{item.tags && item.tags[0].title}} 等 {{item.tags && item.tags.length}} 個標簽</view>
</view>
<view class='r'>{{filters.timeBefore(item.createdAtString)}}</view>
</view>
<view class='bottom'>
<view class='imglist'>
<image mode='aspectFill' wx:for='{{item.tags}}' wx:key='{{idx}}' wx:for-index='idx' wx:for-item='i' src='{{i.icon}}'></image>
</view>
</view>
</view>
</view>
</view>
標簽管理頁
這個頁面的 tab
也是用 swiper
實現的,復用的組件是 tagItem
。實現如下:
<view class='container'>
<view class='top tabs'>
<view class='inner'>
<view class='tab {{currentSwiper === "0" ? "active" : ""}}' data-index='0' catchtap='switchSwiper'>已關注標簽</view>
<view class='tab {{currentSwiper === "1" ? "active" : ""}}' data-index='1' catchtap='switchSwiper'>所有標簽</view>
</view>
<view class='bar' style='left:{{currentSwiper*50}}%'></view>
</view>
<swiper class='swiper' autoplay='{{false}}' indicator-dots='{{false}}' bindchange='swiperChanged' current='{{currentSwiper}}'>
<swiper-item item-id='0'>
<view>
<tagItem list='{{tagList}}'></tagItem>
</view>
<empty wx:if='{{!tagList.length}}' tip='暫無消息'></empty>
</swiper-item>
<swiper-item item-id='1'>
<scroll-view scroll-y bindscrolltolower='getMoreRecommendTags'>
<view class='hot' wx:if='{{hotTagList.length}}'>
<view class='title'>推薦標簽</view>
<tagItem list='{{hotTagList}}'></tagItem>
</view>
<view class='suggest' wx:if='{{recommendTagList.length}}'>
<view class='title'>你可能感興趣的標簽</view>
<tagItem list='{{recommendTagList}}'></tagItem>
</view>
</scroll-view>
<empty wx:if='{{!hotTagList.length && recommendTagList.length}}' tip='暫時沒有系統通知'></empty>
</swiper-item>
</swiper>
</view>
原創文章頁、喜歡的文章頁、閱讀過的文章頁、贊過的沸點頁、關注的標簽頁
這幾個頁面都是組件的復用,沒有太多要說的。
意見反饋頁、設置頁
這兩個頁面只是一個關於頁面而已。。。
完成度
APP
里面的東西實在是不少,包括頁面和交互,要完全照抄實現確實需要一些時間和精力,UI
之類的都是簡單測量+肉眼調試實現的,下面列出頁面和交互的完成度,這里應該只是列出了絕大部分(還是上面那句話,APP
里面的東西實在是不少),未列出、未實現的后續會根據時間、精力來實現。
實際完成度請以代碼為主(線上小程序也會持續更新)。
頁面完成度
貌似不支持 markdown
待辦事宜寫法?QAQ
- [x] 啟動頁
- [x] 登錄、未登錄跳轉邏輯和頁面數據刷新邏輯等
- [x] HOME、搜索、沸點、小冊 TAB 涉及到的上拉、下拉刷新
- [x] POST、ENTRY(文章類型不同) 詳情頁
- [ ] HOME TAB
- [x] 首頁
- [x] 熱門推薦
- [x] 下部列表
- [ ] 標簽展示相關
- [x] 首頁
- [ ] 搜索 TAB
- [x] 頂部輪播
- [x] 熱門文章
- [ ] 搜索功能相關
- [ ] 本周最熱
- [ ] 收藏集
- [ ] ...
- [ ] 活動
- [ ] ...
- [ ] 沸點 TAB
- [ ] 推薦
- [x] 頂部熱門沸點
- [x] 沸點列表
- [x] 沸點詳情
- [ ] 話題
- [ ] 動態
- [ ] 發布沸點
- [ ] 推薦
- [ ] 小冊 TAB
- [x] 小冊列表
- [ ] 小冊詳情
- [ ] 我的 TAB
- [ ] 個人主頁
- [x] 文章數據
- [ ] 編輯
- [ ] 關注、被關注列表
- [x] 動態頁
- [x] 沸點頁
- [x] 原創文章頁
- [x] 收藏集
- [ ] 收藏集詳情頁
- [x] 喜歡的文章
- [x] 關注的標簽
- [ ] 標簽詳情頁
- [x] 我喜歡的
- [x] 收藏集
- [ ] 已購小冊
- [x] 贊過的沸點
- [x] 閱讀過的文章
- [x] 標簽管理
- [x] 已關注標簽
- [x] 所有標簽
- [x] 推薦標簽
- [x] 所有標簽
- [ ] 夜間模式
- [x] 意見反饋(和官方 APP 有差異,這里是個簡單的關於頁)
- [ ] 設置
- [ ] ...
- [ ] 個人主頁
- [x] 登錄頁
- [ ] 注冊頁
- [ ] 修改密碼頁
- [x] 其他完成部分...
- [ ] 未完待續部分...
交互完成度
評論、留言、關注、添加到收藏集、喜歡、發表沸點等暫時均沒有實現,因為 APP 里面的東西實在是不少......
- [ ] 評論
- [ ] 留言
- [ ] 關注
- [ ] 喜歡
- [ ] 未完待續部分...
說明
- 1、話說掘金的
API
域名(二級)真是多啊,小程序后台域名白名單最多只能配20
個,現在已經占了16
個了,感覺要完整抄完實現掘金APP
版小程序,配額不夠啊。不行的話,就只能搭個server
代理了; - 2、個別接口只有
APP
用到了,請求字段需要按照web
的略作調整;個別接口也要設置對應的header
; - 3、文章詳情頁返回的是整片文章的
html
格式的content
,這里使用的是開源的 wxParse 進行富文本解析; - 4、由於小程序的限制,第三方的
url
不能在webview
中打開,所以文章里面的外鏈能點開算我輸; - 5、開發時,個別細節需要稍微注意,比如:沸點
tab
頁,如果已經滑到了頂部,onShow
獲取新數據,否則,不刷新;未登錄時,首頁APP
調用的 API 是get_recommended_entry
,就是懶為了方便小程序里仍然使用get_entry_by_timeline
;其他的不一一贅述,詳情可 查看源碼; - 6、由於
賬號權限等問題有些API
需要天時地利人和,部分API
返回的數據格式沒有拿到,所以對應的頁面也沒有寫,比如:系統消息頁面(最近一直沒有系統消息)等; - 7、部分數據可能未完全覆蓋,比如:用戶消息這塊,目前列舉出的
category
有collection
、comment
、follow
、comment-like
、pin-like
、pin-comment
,可能還會有其他消息類型,遇到了會一一補上;還有動態頁,也是同樣的問題;可能還有其他沒有完全覆蓋的數據; - 8、點擊某些文章進入詳情頁會提示
illegal token
,亦或文章沒有正常顯示出來,應該是請求參數需要略作調整,或者文章類型需要判斷。類似這樣的小問題,后續會調整補充; - 9、小程序(非小游戲)在於一個 小 字,應該是一個應用的濃縮精華版,而不應該是一個內容豐富多彩的
APP
的100%
的復制版,這樣會顯得比較臃腫,此處應該有but
,該小程序僅僅是出於學習交流的目的,所以這個問題不在我們的考慮范圍內; - 10、登錄現在只能手機號登錄,郵箱登錄給忘記了,回頭一並加上;
- 11、我也是有人生夢想的人;
轉載請注明出處