一、项目架构设计
技术栈组成:
- UniApp:跨端开发框架
- Vue3:前端框架
- Pinia:状态管理
- uView UI:UI组件库
- Node.js:后端服务
二、核心功能实现
1. 仿微信聊天界面
<template>
<view class="chat-container">
<scroll-view
scroll-y
:scroll-top="scrollTop"
@scrolltoupper="loadMore"
class="message-list"
>
<view
v-for="(msg, index) in messages"
:key="msg.id"
:class="['message-item', msg.isMe ? 'me' : 'other']"
>
<image
v-if="!msg.isMe"
class="avatar"
:src="msg.avatar"
mode="aspectFill"
/>
<view class="content">
<text class="text">{{ msg.content }}</text>
<text class="time">{{ formatTime(msg.time) }}</text>
</view>
</view>
</scroll-view>
<view class="input-area">
<input
v-model="inputMsg"
placeholder="输入消息..."
@confirm="sendMessage"
/>
<button @click="sendMessage">发送</button>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useChatStore } from '@/stores/chat'
const chatStore = useChatStore()
const messages = ref([])
const inputMsg = ref('')
const scrollTop = ref(0)
onMounted(() => {
loadMessages()
})
const loadMessages = async () => {
messages.value = await chatStore.getMessages()
}
const sendMessage = () => {
if (!inputMsg.value.trim()) return
chatStore.sendMessage({
content: inputMsg.value,
isMe: true,
time: Date.now()
})
inputMsg.value = ''
scrollToBottom()
}
const scrollToBottom = () => {
uni.createSelectorQuery()
.select('.message-list')
.boundingClientRect(res => {
scrollTop.value = res.height
})
.exec()
}
</script>
2. 朋友圈功能实现
<template>
<view class="moment-list">
<view
v-for="moment in moments"
:key="moment.id"
class="moment-item"
>
<view class="user-info">
<image class="avatar" :src="moment.avatar"/>
<text class="name">{{ moment.name }}</text>
</view>
<text class="content">{{ moment.content }}</text>
<view class="image-list" v-if="moment.images.length">
<image
v-for="(img, index) in moment.images"
:key="index"
:src="img"
mode="aspectFill"
@click="previewImage(moment.images, index)"
/>
</view>
<view class="footer">
<text class="time">{{ formatTime(moment.time) }}</text>
<view class="actions">
<text @click="toggleLike(moment)">
{{ moment.liked ? '取消' : '' }}点赞
</text>
<text @click="showComment(moment)">评论</text>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { useMomentStore } from '@/stores/moment'
const momentStore = useMomentStore()
const moments = ref([])
const loadMoments = async () => {
moments.value = await momentStore.getMoments()
}
const previewImage = (urls, current) => {
uni.previewImage({
urls,
current
})
}
const toggleLike = async (moment) => {
await momentStore.toggleLike(moment.id)
loadMoments()
}
</script>
三、性能优化方案
1. 图片懒加载
<template>
<image
v-for="img in imageList"
:key="img.id"
:src="placeholder"
:data-src="img.url"
lazy-load
@load="onImageLoad"
/>
</template>
<script>
export default {
data() {
return {
placeholder: '/static/placeholder.png',
imageList: [] // 从接口获取的图片列表
}
},
methods: {
onImageLoad(e) {
const img = e.target
const src = img.dataset.src
if (src) {
img.src = src
img.removeAttribute('data-src')
}
}
}
}
</script>
2. 数据分页加载
// 分页加载实现
export function usePagination(api, params = {}) {
const loading = ref(false)
const finished = ref(false)
const list = ref([])
const pagination = reactive({
page: 1,
pageSize: 10,
total: 0
})
const loadData = async () => {
if (loading.value || finished.value) return
loading.value = true
try {
const res = await api({
...params,
page: pagination.page,
pageSize: pagination.pageSize
})
list.value = [...list.value, ...res.list]
pagination.total = res.total
if (list.value.length >= pagination.total) {
finished.value = true
} else {
pagination.page++
}
} finally {
loading.value = false
}
}
return {
loading,
finished,
list,
loadData,
refresh: () => {
list.value = []
pagination.page = 1
finished.value = false
loadData()
}
}
}