社区类目没有开放给个人开发者,所以没能上线。
预览
项目配置文件,更改appid
{
"description": "项目配置文件",
"setting": {
"urlCheck": true,
"es6": false,
"postcss": false,
"minified": false,
"newFeature": true
},
"miniprogramRoot": "./dist/",
"compileType": "miniprogram",
"appid": "",
"projectname": "mpvue",
"condition": {
"search": {
"current": -1,
"list": []
},
"conversation": {
"current": -1,
"list": []
},
"game": {
"currentL": -1,
"list": []
},
"miniprogram": {
"current": -1,
"list": []
}
}
}
网络请求封装
const BASE_URL = 'https://cnodejs.org/api/v1'
export default {
// 发出请求时的回调函数
config(config) {
config.url = BASE_URL + config.url
// 请求前设置token
// const accesstoken = wx.getStorageSync('accesstoken')
// if (accesstoken) {
// config.header = {
// 'X-Token': accesstoken
// }
// }
console.log('request before config: ', config);
// 必须返回OBJECT参数对象,否则无法发送请求到服务端
this.showLoading({
title: '加载中',
mask: true,
})
return config;
},
// 请求成功后的回调函数
async success(resp) {
let errorMesg = resp.data.error_msg || ''
// 可以在这里对收到的响应数据对象进行加工处理
switch (resp.statusCode) {
// case 200:
// const { success, error_msg: message } = resp.data
// if (!success) {
// errorMesg = message || '未知错误'
// }
// break
// case 401:
// console.log('未登陆,拦截重定向登陆界面')
// await this.redirectTo({
// url: 'login'
// })
// break
case 403:
console.log('未授权接口,拦截')
this.showModal({
title: '警告',
content: (resp.data.error && (resp.data.error.details || resp.data.error.message)) || '无权请联系管理员',
confirmText: '我知道了',
showCancel: false,
})
throw new Error(errorMesg)
case 500:
case 502:
errorMesg = (resp.data.error && (resp.data.error.details || resp.data.error.message)) || '服务器出错'
break
case 503:
errorMesg = '哦~服务器宕机了'
break
}
if (errorMesg.length > 0) {
this.showToast({
title: errorMesg,
icon: 'none',
})
// throw new Error(errorMesg)
}
return resp.data.data || resp.data
},
// 请求失败后的回调函数
fail(resp) {
console.log('request fail: ', resp);
// 必须返回响应数据对象,否则后续无法对响应数据进行处理
this.showToast({
title: resp.errMsg,
icon: 'none',
})
return resp;
},
// 请求完成时的回调函数(请求成功或失败都会被执行)
complete(resp) {
this.hideLoading()
},
}
主体代码
<style lang="less" scoped>
@import url("../../utils/vars");
.tabs {
padding: 20rpx;
.label {
font-size: 30rpx;
color: @maincolor;
background: transparent;
&.active {
color: white;
background: @maincolor;
}
}
}
.user-info {
padding: 20rpx;
.btn-login {
color: #666;
font-size: 26rpx;
}
.user-avatar {
width: 50rpx;
height: 50rpx;
border-radius: 50%;
}
}
</style>
<template>
<div class="container">
<div class="flex ai-center jc-between">
<div class="tabs">
<text class="label" v-for="(title,tab) in tabs" :key="tab" :class="{'active':currentTab===tab}" @click="switchTab(tab)">{{title}}</text>
</div>
<div class="user-info">
<img class="user-avatar" v-if="avatarUrl" :src="avatarUrl" />
<text class="btn-login" v-else @click="getUserInfo">登陆</text>
</div>
</div>
<topic-cell v-for="(t,i) in topics" :key="i" :topic="t"></topic-cell>
</div>
</template>
<script>
import TopicCell from '@/components/TopicCell'
import { mapState, mapActions } from 'vuex'
export default {
components: {
TopicCell,
},
data() {
return {
page: 1,
currentTab: 'all',
tabs: {
'all': '全部',
'good': '精华',
'share': '分享',
'ask': '问答',
'job': '招聘',
},
}
},
computed: {
...mapState({
topics: state => state.topics.topics,
avatarUrl: state => state.userInfo.avatar_url,
}),
},
methods: {
...mapActions({
getTopics: 'topics/getTopics',
getUserInfo: 'userInfo/getUserInfo',
}),
async getMore() {
// 每隔一定数据量清空一次列表, 因为小程序限制数据量的传入
const refresh = this.topics.length >= 100
await this.getTopics({
page: ++this.page,
tab: this.currentTab,
refresh,
})
// 回到顶部
if (refresh) {
wx.pageScrollTo({ scrollTop: 0, duration: 300 })
}
},
async switchTab(tab) {
await this.getTopics({
page: this.page = 1,
refresh: true,
tab: this.currentTab = tab,
})
},
},
created() {
this.getTopics({
page: 1,
tab: this.currentTab,
refresh: true, // 是否刷新列表, false表示添加到列表, 不能用page===1代替
})
const storagedaccesstoken = wx.getStorageSync('accesstoken')
storagedaccesstoken && this.getUserInfo({ storagedaccesstoken })
},
onReachBottom() {
this.getMore()
},
async onPullDownRefresh() {
await this.getTopics({
page: 1,
tab: this.currentTab,
refresh: true,
})
wx.stopPullDownRefresh()
},
}
</script>
TopicCell组件代码:
<template functional>
<div class="cell" @click="goDetail">
<img class="user_avatar" :src="topic.author.avatar_url">
<text class="label active" v-if="topic.top">置顶</text>
<text class="label active" v-else-if="topic.good">精华</text>
<text class="label" v-else-if="topic.tab==='ask'">问答</text>
<text class="label" v-else-if="topic.tab==='job'">招聘</text>
<text class="label" v-else>分享</text>
<text class="reply_count">{{topic.reply_count}}/{{topic.visit_count}}</text>
<text>{{topic.title}}</text>
</div>
</template>
<script>
export default {
props: ['topic'],
methods: {
goDetail() {
wx.navigateTo({
url: '/pages/topicdetail/topicdetail?id=' + this.topic.id,
})
},
},
}
</script>
<style lang="less">
.cell {
padding: 10px;
font-size: 28rpx;
// margin-bottom: 10rpx;
.user_avatar {
width: 40rpx;
height: 40rpx;
// margin-bottom: -4rpx;
margin-right: 10rpx;
vertical-align: middle;
}
.reply_count {
font-size: 20rpx;
color: #b4b4b4;
vertical-align: middle;
}
& + .cell {
border-top: 1rpx solid #ddd;
}
}
</style>
本地运行
# 代码获取
关注微信公众号【码农园区】,获取【uniapp源码】即可获取
# 在`project.config.json`下修改你的`appid`
# 将`https://cnodejs.org`添加到request合法域名列表
# 切换到项目目录
cd mpvue-cnode
# 安装依赖
npm i
# 启动脚本
npm run dev
# 然后用微信开发者工具打开本项目根目录即可。
其它脚本
# eslint 检查
npm run lint
# eslint 自动修复
npm run fix
# 生产环境 build
npm run build
说明
如果本项目对您有帮助,欢迎 “点赞,关注” 支持一下 谢谢~
源码获取关注公众号「码农园区」,回复 【uniapp源码】