免费资源下载
一、项目概述与技术选型
在移动应用开发领域,跨平台解决方案已成为提升开发效率的关键。UniApp作为基于Vue.js的跨端开发框架,允许开发者使用一套代码同时发布到iOS、Android、Web以及各小程序平台。本文将带领大家实战开发一个短视频瀑布流应用,该应用将同时支持微信小程序、H5和App端。
1.1 技术栈配置
// package.json核心依赖
{
"dependencies": {
"@dcloudio/uni-app": "^3.0.0",
"vue": "^2.6.11",
"vuex": "^3.4.0"
},
"devDependencies": {
"@dcloudio/uni-ui": "^1.4.0",
"sass": "^1.32.0"
}
}
二、项目初始化与工程配置
2.1 创建UniApp项目
使用HBuilderX创建项目:
- 打开HBuilderX,选择”文件” → “新建” → “项目”
- 选择”uni-app”类型,使用默认模板
- 项目名称:ShortVideoFlow
- 勾选”微信小程序”、”H5″、”App”三个平台
2.2 目录结构优化
ShortVideoFlow/
├── components/ # 自定义组件
│ ├── video-card/ # 视频卡片组件
│ ├── loading-more/ # 加载更多组件
│ └── tab-bar/ # 自定义标签栏
├── pages/ # 页面文件
│ ├── index/ # 首页
│ ├── discover/ # 发现页
│ └── profile/ # 个人中心
├── static/ # 静态资源
│ ├── icons/ # 图标资源
│ └── images/ # 图片资源
├── store/ # Vuex状态管理
│ ├── modules/ # 模块化store
│ └── index.js # store入口
├── utils/ # 工具函数
│ ├── request.js # 网络请求封装
│ ├── validator.js # 表单验证
│ └── platform.js # 平台判断
└── uni.scss # 全局样式变量
三、核心功能实现
3.1 视频瀑布流组件开发
创建components/video-waterfall/video-waterfall.vue:
<template>
<view class="video-waterfall">
<!-- 两列布局 -->
<view class="column" v-for="(col, colIndex) in columns" :key="colIndex">
<video-card
v-for="item in col"
:key="item.id"
:video-data="item"
@tap="handleVideoTap(item)"
/>
</view>
<!-- 加载状态 -->
<loading-more
:status="loadingStatus"
@load-more="loadMoreVideos"
/>
</view>
</template>
<script>
export default {
name: 'VideoWaterfall',
props: {
initialData: {
type: Array,
default: () => []
}
},
data() {
return {
columns: [[], []], // 两列数据
videoList: [],
loadingStatus: 'more',
page: 1,
pageSize: 10
}
},
methods: {
// 智能分配算法:将视频分配到高度较小的列
distributeVideos(videos) {
const columnHeights = [0, 0];
videos.forEach(video => {
// 计算视频高度(根据宽高比)
const videoHeight = 300 * (video.height / video.width);
// 找到高度较小的列
const targetColumn = columnHeights[0] <= columnHeights[1] ? 0 : 1;
this.columns[targetColumn].push(video);
columnHeights[targetColumn] += videoHeight;
});
},
// 加载更多视频
async loadMoreVideos() {
if (this.loadingStatus === 'loading') return;
this.loadingStatus = 'loading';
try {
const newVideos = await this.fetchVideos(this.page, this.pageSize);
if (newVideos.length > 0) {
this.distributeVideos(newVideos);
this.videoList = [...this.videoList, ...newVideos];
this.page++;
this.loadingStatus = 'more';
} else {
this.loadingStatus = 'noMore';
}
} catch (error) {
console.error('加载视频失败:', error);
this.loadingStatus = 'error';
}
},
// 视频点击处理
handleVideoTap(video) {
uni.navigateTo({
url: `/pages/video-detail/video-detail?id=${video.id}`
});
}
}
}
</script>
3.2 视频播放器封装
考虑到不同平台的视频播放器差异,我们需要封装一个统一的视频组件:
// components/video-player/video-player.vue
export default {
props: {
src: String,
autoplay: Boolean,
controls: Boolean
},
computed: {
// 平台适配
isWeapp() {
return uni.getSystemInfoSync().platform === 'wechat'
},
isApp() {
return uni.getSystemInfoSync().platform === 'app'
}
},
methods: {
// 统一播放控制
play() {
if (this.isWeapp) {
this.$refs.videoContext.play()
} else if (this.isApp) {
// App端特殊处理
this.$emit('play')
}
},
// 性能优化:懒加载
onVideoLoad() {
const observer = uni.createIntersectionObserver(this)
observer.relativeToViewport({
top: 500,
bottom: 500
}).observe('.video-container', (res) => {
if (res.intersectionRatio > 0) {
this.loadVideo()
}
})
}
}
}
四、性能优化策略
4.1 图片懒加载优化
// utils/lazy-load.js
export const lazyLoad = {
install(Vue) {
Vue.directive('lazy', {
inserted(el, binding) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target
img.src = binding.value
observer.unobserve(img)
}
})
})
observer.observe(el)
}
})
}
}
// 在main.js中使用
import { lazyLoad } from './utils/lazy-load'
Vue.use(lazyLoad)
4.2 请求防抖与缓存
// utils/request.js
class RequestManager {
constructor() {
this.cache = new Map()
this.pendingRequests = new Map()
}
async request(url, options = {}) {
const cacheKey = this.generateCacheKey(url, options)
// 检查缓存
if (options.cache && this.cache.has(cacheKey)) {
const { data, timestamp } = this.cache.get(cacheKey)
if (Date.now() - timestamp < options.cacheTime) {
return Promise.resolve(data)
}
}
// 防止重复请求
if (this.pendingRequests.has(cacheKey)) {
return this.pendingRequests.get(cacheKey)
}
const requestPromise = uni.request({
url,
...options
}).then(response => {
if (options.cache) {
this.cache.set(cacheKey, {
data: response.data,
timestamp: Date.now()
})
}
return response.data
}).finally(() => {
this.pendingRequests.delete(cacheKey)
})
this.pendingRequests.set(cacheKey, requestPromise)
return requestPromise
}
}
五、多平台适配技巧
5.1 条件编译处理
// 平台特定代码
export const getVideoPlayerConfig = () => {
// #ifdef MP-WEIXIN
return {
component: 'wx-video',
autoplay: false,
controls: true
}
// #endif
// #ifdef H5
return {
component: 'video',
autoplay: true,
controls: true
}
// #endif
// #ifdef APP-PLUS
return {
component: 'uni-video',
autoplay: false,
controls: false
}
// #endif
}
// 样式适配
const platformStyle = {
// #ifdef MP-WEIXIN
'video-container': {
width: '100vw',
height: 'calc(100vh - 50px)'
},
// #endif
// #ifdef H5
'video-container': {
width: '100%',
height: '400px'
}
// #endif
}
5.2 导航栏适配
// pages.json配置
{
"pages": [{
"path": "pages/index/index",
"style": {
// #ifdef MP-WEIXIN
"navigationBarTitleText": "短视频",
"enablePullDownRefresh": true,
// #endif
// #ifdef H5
"titleNView": {
"titleText": "短视频瀑布流",
"autoBackButton": true
},
// #endif
// #ifdef APP-PLUS
"navigationBar": {
"titleText": "短视频",
"backgroundColor": "#ffffff"
}
// #endif
}
}]
}
六、项目构建与发布
6.1 生产环境构建
// package.json脚本配置
{
"scripts": {
"build:h5": "uni-build --platform h5",
"build:mp-weixin": "uni-build --platform mp-weixin",
"build:app": "uni-build --platform app",
"build:all": "npm run build:h5 && npm run build:mp-weixin"
}
}
// manifest.json生产配置
{
"h5": {
"title": "短视频瀑布流",
"router": {
"mode": "history"
},
"optimization": {
"treeShaking": {
"enable": true
}
}
},
"mp-weixin": {
"appid": "your-wechat-appid",
"setting": {
"urlCheck": false,
"es6": true,
"postcss": true
}
}
}
6.2 性能监控与错误追踪
// utils/monitor.js
class PerformanceMonitor {
static init() {
// 页面加载性能
uni.onAppRoute(route => {
this.recordPageLoad(route.path)
})
// 错误监控
uni.onError(error => {
this.reportError(error)
})
// 网络请求监控
this.interceptRequest()
}
static recordPageLoad(pagePath) {
const startTime = Date.now()
uni.onPageShow(() => {
const loadTime = Date.now() - startTime
console.log(`页面 ${pagePath} 加载耗时: ${loadTime}ms`)
// 上报到监控平台
if (loadTime > 2000) {
this.reportPerformance({
page: pagePath,
loadTime,
type: 'slow_load'
})
}
})
}
}
七、总结与最佳实践
7.1 开发经验总结
- 组件化开发:将可复用的UI和功能封装成组件,提高代码复用率
- 状态管理:合理使用Vuex管理全局状态,避免props层层传递
- 性能优先:始终关注应用性能,特别是列表渲染和图片加载
- 平台特性:充分利用各平台特性,同时保持代码统一性
- 错误处理:完善的错误捕获和用户友好的错误提示
7.2 扩展建议
项目后续可以扩展的功能:
- 添加视频上传和编辑功能
- 实现社交互动(点赞、评论、分享)
- 集成推荐算法
- 添加直播功能
- 实现离线缓存
结语
通过本教程,我们完整实现了一个基于UniApp的跨平台短视频瀑布流应用。从项目初始化到多平台发布,涵盖了实际开发中的关键技术点。UniApp的强大之处在于其”一次开发,多端发布”的能力,结合Vue.js的优雅语法,能够显著提升开发效率。
在实际开发中,建议开发者:
- 深入理解各平台差异,合理使用条件编译
- 重视性能优化,特别是移动端用户体验
- 保持代码的可维护性和可扩展性
- 充分利用UniApp生态中的插件和组件
希望本文能为你的UniApp开发之旅提供有价值的参考!

