为了学习 Vue3,我做了一个微信匿名朋友圈。
缘起
编程这种东西,必须要理论加实战,才能真正把技能学到。所以,笔者就想着通过一些实战应用来感受一下 Vue3 的设计哲学以及作者们的劳动结晶。那么,做点啥好呢?突然想到现在大家都不怎么爱发微信朋友圈了,毕竟微信这样一个体量的超级 APP,里边都是你的亲戚,同事,老板啥的,有点牢骚话,也不好意思发呀。既然如此,那么就做一个匿名的朋友圈吧,这样,不想让熟人圈子看到的东西,不就有地方藏了吗哈哈哈(想想都有点小激动了!)
撸码
说干就干,笔者迅速的就初始化了工程,开始了搬砖之旅。开发该项目使用的操作系统是 MBP,技术栈是 Vue3 + Vue Router + Axios 这套常用组合,UI 组件库选择了 Vant,另外,使用了 dayjs 进行日期处理,也用了 lodash 库,便于直接使用一些工具函数。
登录
既然是发朋友圈,那肯定是需要登录态的,为了不想有繁杂的登录注册流程,笔者打算直接接入微信公众号的 JSSDK, 实现微信的授权登录。当然,这里边坑还是有点多,笔者已另写文章用以记录。感兴趣的人可空降至 Vue 微信开发中授权登录的优雅实现。笔者在本项目中,接入的是微信静默授权方式,这种授权登录方式用户几乎无感知,但也无法获取用户微信的昵称和头像,不过既然咱主打的是匿名,那不正好匹配了需求嘛(自己当产品的感觉真舒服,需求说砍就砍了,哈哈哈哈)
获取不到用户的头像和昵称,在显示上,是不是会显的过于空洞了呢?是的,笔者考虑到了。这个问题好说,直接在服务端生成一个昵称库,每来一个用户就随机分配一个不就可以啦!至于头像嘛,本想着也按昵称那样,弄一个头像库的。结果在一次因缘巧合下,笔者发现了这样一个项目:
boringavatars
也可以在github上找到它。
这个项目可以根据一串随机 hash 值来生成一个对应的头像图片,贼有意思,使用也非常简单,类似如下:
1 2 3 4 5 6 7 8
| import Avatar from "boring-avatars";
<Avatar size={40} name="Maria Mitchell" variant="marble" colors={["#92A1C6", "#146A7C", "#F0AB3D", "#C271B4", "#C20D90"]} />;
|
我欣然的在项目中使用了它。
发布动态
用户登录后,第一件事自然是发布动态了。发动态这个功能其实不复杂,也就是填写表单后提交到服务端。界面我参考了一下微信发朋友圈的设计,然后增加了一个标签,大概如下:

这里涉及到了文件上传,考虑到服务器带宽有限,笔者使用了七牛云存储作为静态资源服务器,通过客户端直传的方式实现了图片上传。客户端直传其实很简单,不管是七牛云还是其他云厂商的文件管理服务,都可以使用表单上传的方式(也就是 直接 post 请求传递 formdata 的方式)上传,下边是笔者使用 Axios 进行上传的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const formData = new FormData(); formData.append("file", file); formData.append("token", token); formData.append("key", key); const uploadUrl = "http://up-z2.qiniu.com";
axios .request({ url: uploadUrl, method: "post", onUploadProgress(progressEvent) { }, data: formData, timeout: 0, headers: { "Content-Type": "multipart/form-data" }, }) .then((res) => { console.log(res.data); });
|
图片上传其实涉及的细节很多,包括上传体验优化啊,图片压缩啊,加水印啊,批量上传,断点续传,分片上传,访问鉴权啊等等。由于时间关系,笔者暂时没去一一实现,下次笔者一定单独详细分享下关于图片上传功能的各种细节。
动态列表
动态列表也很简单,在使用了 vant 组件库的情况下,很快就能开发出一个可以下拉刷新,上滑加载更多的信息流列表。大概逻辑实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| <template> <van-pull-refresh v-if="feedList.length" v-model="refreshing" :pull-distance="200" @refresh="onRefresh" > <van-list v-model:loading="isLoading" :finished="finished" finished-text="没有更多了" @load="fetchData" > <template v-for="feed in feedList" :key="feed.id" class="feed-list"> <FeedItem :data="feed"></FeedItem> </template> </van-list> </van-pull-refresh> </template>
<script lang="ts"> import { useAxios } from "@/hooks/useAxios"; import { defineComponent } from "vue"; import { PullRefresh, List } from "vant"; import FeedItem from "./FeedItem.vue"; export default defineComponent({ name: "FeedList", components: { [PullRefresh.name]: PullRefresh, [List.name]: List, FeedItem, }, data() { return { feedList: [], refreshing: false, isLoading: false, finished: false, page: 1, apiUrl: "/api/foo/bar", params: {}, }; }, mounted() { this.onRefresh(); }, methods: { fetchData() { const limit = 10; if (this.refreshing) { this.feedList = []; this.page = 1; this.refreshing = false; } const params = { p: this.page, limit, ...this.params, };
useAxios.get(this.apiUrl, params).then((res) => { this.isLoading = false; this.feedList = [...this.feedList, ...res]; this.page++; if (res.length < limit) { this.finished = true; } }); }, onRefresh() { this.finished = false; this.isLoading = true; this.fetchData(); }, }, }); </script>
|
最后,笔者再加了一个 tab 组件,用来展示所有动态和我的动态,实现效果如下:

写在最后
匿名朋友圈虽然只是很简单的一个小项目,但其实实现起来,还是真的有蛮多细节的。笔者除了完成了发布动态和刷动态以外,也实现了点赞和评论等功能,后续的迭代中,我会继续分享其他功能点的实现细节,希望能对读者有所启发。当然,也希望有大佬可以一起交流(给予指导)。笔者已将项目部署到服务器上,可以复制该链接到微信中打开访问,也可以扫码访问:
