基于mpvue实现的cnode社区demo(附精选源码32套,涵盖商城团购等)

社区类目没有开放给个人开发者,所以没能上线。

预览

基于mpvue实现的cnode社区demo(附精选源码32套,涵盖商城团购等)_第1张图片
基于mpvue实现的cnode社区demo(附精选源码32套,涵盖商城团购等)_第2张图片
项目配置文件,更改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

精选32套源码目录:

IT之家小程序版客户端(使用 Mpvue 开发,兼容 Web)ithome-lite-master.zip

mpvue 仿网易严选mpvue-shop-master.zip

mpvue-音乐播放器mpvue-music-master.zip

mpvue性能测试与体验miniweibo-master.zip

mpvue改造的日历.zip

mpvue框架仿滴滴出行didi-master.zip

mpVue高仿美团小程序教程mpvue-meituan-master.zip

uni APP自动更新并安装.vue

uni-app nvue沉浸式状态栏(线性渐变色).vue

uni-app 二维码生成器分享wxqrcode.zip

uni-app 侧边导航分类,适合商品分类页面uni-app-left-navigation-master.zip

uni-app 自定义底部导航栏uni-app-bottom-navigation-master.zip

uni-app全局变量的几种实现方式.zip

uni-app的markdown富文本编辑器插件uniapp-markdown-master.zip

uni-app自定义导航栏title-custom.zip

uniapp聊天实例,支持图片,语音,表情.zip

uniapp选择器,包含一级,二级级联,三级级联uniapp-picker-master.zip

vue-mpvue-ChatRobot聊天机器人vue-mpvue-ChatRobot-master.zip

【小程序】CNode社区mpvue-cnode-master.zip

【插件、图表】7种图表漂亮丰富uniCharts.zip

一款播课类小程序, 基于 mpvue 构建mp-podcast-mpvue-master.zip

云档新版小程序端,基于mpvue开发cloud-doc-v2-master.zip

仿uc浏览器列表.vue

仿扎克新闻mpZAKER-master.zip

仿网易云UImusic播放器mpvue-music-master.zip

仿追书神器的小说阅读器小程序wx-book-master.zip

参照米家APP布局和样式,编写的一款智能家居小程序smart-home-master.zip

商城实例mpvue-xbyjShop-master.zip

基于 mpvue 实现豆瓣电影微信小程序mpvue-douban-master.zip

基于mpvue的优酷mpvue-youku-master.zip

校园助手示例SHUhelper-master.zip

类似mui中的chat(聊天窗口)实现uniapp-chat-master.zip

美团外卖(第三方)开源程序mpvue-master.zip

美食搜索mpvue-FG-master.zip

豆瓣平分mpvue-douban-pingfen-master.zip

顶部tabbar.vue

源码截图:
在这里插入图片描述

说明

如果本项目对您有帮助,欢迎 “点赞,关注” 支持一下 谢谢~

源码获取关注公众号「码农园区」,回复 【uniapp源码】
在这里插入图片描述

你可能感兴趣的:(Uniapp,javascript,前端,开发语言)