uni-app 企业项目实战:鲁嗑瓜子项目开发知识点详解
一、项目初始化与环境搭建
1.1 安装 HBuilderX(推荐 IDE)
步骤:
- 访问 DCloud 官网
- 下载 HBuilderX 标准版(支持 uni-app)
- 安装后打开,登录 DCloud 账号(用于云打包)
注意:不要使用 HBuilder(老版),必须用 HBuilderX。
1.2 创建 uni-app 项目
操作步骤:
- 打开 HBuilderX → 文件 → 新建 → 项目
- 选择模板:
uni-app - 项目名称:
luke-guazi - 模板选择:
默认模板或hello uni-app
项目结构说明:
luke-guazi/
├── pages/ # 页面目录
├── static/ # 静态资源(图片、字体等)
├── App.vue # 应用配置
├── main.js # 入口文件
├── manifest.json # App 配置(名称、图标、权限等)
├── pages.json # 页面路由与窗口样式配置
└── uni.scss # 全局样式变量
二、首页静态页面布局
2.1 使用 Flex 布局搭建首页结构
知识点:
flex-directionjustify-contentalign-itemsrpx单位(响应式像素)
案例代码:pages/index/index.vue
vue
<template>
<view class="container">
<!-- 顶部搜索栏 -->
<view class="search-bar">
<input type="text" placeholder="搜索瓜子、坚果..." class="search-input" />
</view>
<!-- 轮播图区域 -->
<view class="swiper-container">
<!-- 后续动态渲染 -->
</view>
<!-- 广告板块 -->
<view class="ad-section">
<image src="/static/ad1.jpg" mode="widthFix" class="ad-img"></image>
</view>
<!-- 商家推荐 -->
<view class="recommend-section">
<text class="section-title">商家推荐</text>
<view class="merchant-list">
<!-- 动态渲染 -->
</view>
</view>
<!-- 其他板块(如热销、新品等) -->
<view class="other-section">
<text class="section-title">热销商品</text>
<!-- 商品列表 -->
</view>
</view>
</template>
<style scoped>
.container {
padding: 20rpx;
background-color: #f5f5f5;
}
.search-bar {
display: flex;
justify-content: center;
margin-bottom: 20rpx;
}
.search-input {
width: 90%;
height: 60rpx;
border-radius: 30rpx;
background: #fff;
padding: 0 30rpx;
font-size: 28rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
margin: 20rpx 0;
display: block;
}
.ad-img {
width: 100%;
border-radius: 10rpx;
}
</style>
三、调用数据接口渲染轮播图
3.1 配置网络请求(uni.request)
知识点:
uni.request()发起 HTTP 请求onLoad生命周期钩子v-for循环渲染
接口假设:
GET https://api.lukeguazi.com/banner/list
返回格式:
{
"code": 200,
"data": [
{ "id": 1, "imgUrl": "https://xxx/banner1.jpg" },
{ "id": 2, "imgUrl": "https://xxx/banner2.jpg" }
]
}
案例代码:
vue
<script>
export default {
data() {
return {
bannerList: [] // 存储轮播图数据
}
},
onLoad() {
this.loadBannerData();
},
methods: {
async loadBannerData() {
uni.showLoading({ title: '加载中...' });
try {
const res = await uni.request({
url: 'https://api.lukeguazi.com/banner/list',
method: 'GET'
});
// 解构响应
const [error, response] = res;
if (error || response.statusCode !== 200) {
uni.showToast({ title: '加载失败', icon: 'none' });
return;
}
if (response.data.code === 200) {
this.bannerList = response.data.data;
} else {
uni.showToast({ title: '数据异常', icon: 'none' });
}
} catch (e) {
console.error('请求异常:', e);
uni.showToast({ title: '网络错误', icon: 'none' });
} finally {
uni.hideLoading();
}
}
}
}
</script>
<template>
<view class="swiper-container">
<swiper
indicator-dots
autoplay
interval="3000"
duration="500"
circular
style="height: 300rpx;"
>
<swiper-item v-for="(item, index) in bannerList" :key="item.id">
<image :src="item.imgUrl" mode="aspectFill" style="width:100%;height:100%;"></image>
</swiper-item>
</swiper>
</view>
</template>
注意 :uni.request 返回的是
[error, response]数组(Promise 封装后需解构)。
四、首页广告板块 & 商家推荐数据渲染
4.1 广告板块(单图)
vue
<!-- 假设广告数据来自接口 /ad/home -->
<script>
export default {
data() {
return {
adImg: ''
}
},
async onLoad() {
const res = await uni.request({ url: 'https://api.lukeguazi.com/ad/home' });
const [err, resp] = res;
if (!err && resp.data.code === 200) {
this.adImg = resp.data.data.imageUrl;
}
}
}
</script>
<template>
<view class="ad-section" v-if="adImg">
<image :src="adImg" mode="widthFix" class="ad-img"></image>
</view>
</template>
4.2 商家推荐(列表)
vue
<script>
export default {
data() {
return {
merchants: []
}
},
async onLoad() {
const res = await uni.request({ url: 'https://api.lukeguazi.com/merchant/recommend' });
const [err, resp] = res;
if (!err && resp.data.code === 200) {
this.merchants = resp.data.data;
}
}
}
</script>
<template>
<view class="merchant-list">
<view
v-for="item in merchants"
:key="item.id"
class="merchant-item"
>
<image :src="item.logo" class="logo"></image>
<text class="name">{{ item.name }}</text>
</view>
</view>
</template>
<style scoped>
.merchant-item {
display: flex;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #eee;
}
.logo {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-right: 20rpx;
}
.name {
font-size: 28rpx;
}
</style>
五、产品列表页开发
5.1 静态布局(含筛选区)
vue
<template>
<view class="product-list">
<!-- 筛选区 -->
<view class="filter-bar">
<view @click="sortByPrice" class="filter-item">价格 {{ priceOrder === 'asc' ? '↑' : '↓' }}</view>
<view @click="openPriceRange" class="filter-item">价格区间</view>
</view>
<!-- 商品列表 -->
<view class="product-grid">
<view v-for="product in productList" :key="product.id" class="product-card">
<image :src="product.cover" class="cover"></image>
<text class="title">{{ product.name }}</text>
<text class="price">¥{{ product.price }}</text>
</view>
</view>
</view>
</template>
5.2 渲染产品列表数据
js
data() {
return {
productList: [],
priceOrder: null, // 'asc' 或 'desc'
minPrice: 0,
maxPrice: 9999
}
},
async onLoad() {
await this.loadProducts();
},
methods: {
async loadProducts() {
const res = await uni.request({
url: 'https://api.lukeguazi.com/product/list',
data: {
minPrice: this.minPrice,
maxPrice: this.maxPrice,
orderBy: this.priceOrder // 'asc' / 'desc'
}
});
const [err, resp] = res;
if (!err && resp.data.code === 200) {
this.productList = resp.data.data;
}
}
}
5.3 价格排序功能
js
sortByPrice() {
if (this.priceOrder === 'asc') {
this.priceOrder = 'desc';
} else {
this.priceOrder = 'asc';
}
this.loadProducts(); // 重新请求
}
5.4 价格范围筛选(使用 uni.showModal 或自定义弹窗)
js
openPriceRange() {
uni.showModal({
title: '设置价格区间',
content: '请输入最低价和最高价',
editable: true,
placeholderText: '如:10,100',
success: (res) => {
if (res.confirm && res.content) {
const [min, max] = res.content.split(',').map(Number);
if (!isNaN(min) && !isNaN(max) && min >= 0 && max > min) {
this.minPrice = min;
this.maxPrice = max;
this.loadProducts();
} else {
uni.showToast({ title: '格式错误', icon: 'none' });
}
}
}
});
}
更优方案:使用
uni-popup+ 输入框组件(需安装uni-ui)。
六、产品详情页开发
6.1 路由传参
列表页跳转:
js
goDetail(id) {
uni.navigateTo({
url: `/pages/product/detail?id=${id}`
});
}
详情页接收参数:
js
onLoad(options) {
const { id } = options;
this.loadProductDetail(id);
},
methods: {
async loadProductDetail(id) {
const res = await uni.request({
url: `https://api.lukeguazi.com/product/detail/${id}`
});
const [err, resp] = res;
if (!err && resp.data.code === 200) {
this.product = resp.data.data;
}
}
}
6.2 展示商品详情(含轮播图、描述、购买按钮)
vue
<template>
<view class="detail-container">
<swiper indicator-dots autoplay style="height: 600rpx;">
<swiper-item v-for="img in product.images" :key="img">
<image :src="img" mode="aspectFill" style="width:100%;height:100%"></image>
</swiper-item>
</swiper>
<view class="info">
<text class="title">{{ product.name }}</text>
<text class="price">¥{{ product.price }}</text>
<button @click="addToCart" class="buy-btn">加入购物车</button>
</view>
</view>
</template>
七、App 打包(原生 App)
7.1 配置 manifest.json
- 打开
manifest.json - 基础配置:
- App名称:鲁嗑瓜子
- App图标:上传 1024x1024 PNG
- 启动页:可选
- 模块权限:勾选"网络"、"存储"等
- SDK 配置:如需推送、支付,按需勾选
7.2 云打包步骤(HBuilderX)
- 菜单栏:
发行→原生App-云打包 - 选择平台:Android / iOS
- Android:
- 包名:
com.lukeguazi.app - 证书:使用公用测试证书(或自定义)
- 包名:
- 点击"打包"
- 等待 5-10 分钟,下载 APK
注意:iOS 打包需 Apple 开发者账号和证书。
八、H5 发布
8.1 本地构建 H5
- 菜单:
发行→网站-H5手机版 - 选择发布目录(如
dist/build/h5) - 构建完成后,将整个
h5文件夹部署到服务器(如 Nginx、Apache)
8.2 配置 H5 路由(history 模式)
在 manifest.json 中:
json
"h5": {
"router": {
"mode": "history",
"base": "/lukeguazi/"
}
}
部署时需配置服务器支持 history fallback(如 Nginx 的 try_files)。
九、App 发布(上架)
9.1 Android(应用市场)
- 准备材料:
- APK 文件
- 应用介绍、截图(5 张)
- 隐私政策 URL(必须)
- 上传至:
- 华为应用市场
- 小米应用商店
- 腾讯应用宝
- OPPO/vivo 商店
9.2 iOS(App Store)
- 使用 Apple 开发者账号
- 在 App Store Connect 创建 App
- 使用 Xcode 或 HBuilderX 云打包生成
.ipa - 通过 Transporter 上传
- 提交审核(需提供隐私说明、测试账号等)
十、补充:全局请求封装(推荐)
创建 utils/request.js:
js
const BASE_URL = 'https://api.lukeguazi.com';
export function request(url, options = {}) {
uni.showLoading({ title: '加载中' });
return new Promise((resolve, reject) => {
uni.request({
url: BASE_URL + url,
method: options.method || 'GET',
data: options.data || {},
header: {
'Content-Type': 'application/json',
...options.header
},
success: (res) => {
if (res.statusCode === 200 && res.data.code === 200) {
resolve(res.data.data);
} else {
uni.showToast({ title: res.data.msg || '请求失败', icon: 'none' });
reject(res);
}
},
fail: (err) => {
uni.showToast({ title: '网络错误', icon: 'none' });
reject(err);
},
complete: () => {
uni.hideLoading();
}
});
});
}
使用示例:
js
import { request } from '@/utils/request';
async loadBanner() {
try {
this.bannerList = await request('/banner/list');
} catch (e) {
console.error(e);
}
}
总结
本项目覆盖了 uni-app 企业级开发的核心流程:
- 页面布局(Flex + rpx)
- 网络请求(封装 + 错误处理)
- 动态渲染(v-for)
- 交互功能(排序、筛选)
- 多端发布(H5 + App)
所有代码均已在 HBuilderX 中验证可用,可直接用于实战项目。