一、前言
1.本项目基于vant4+vue3构建,默认友友们已具备相关知识,如不具备,请友友们先去了解相关该概念
2.项目数据来源于开源框架 新峰商城 在此指出
3.此项目目的在于帮助友友们了解基本的用法,没有涉及太多的逻辑操作。
二、项目介绍
首页
分类
我的
三、项目搭建
大家可以看看项目所需的依赖,具体的安装命令如下
axios
npm install axios --save
less(为了书写样式方便,不需要强制安装)
npm install less --save
mockjs(使用mockjs制造假数据)
npm install mockjs --save
vant(可以去官网看看组件的使用用法)
npm i vant
vue-router(必须要的哈,进行页面切换的)
npm install vue-router
安装为项目所需的依赖,我们需要将需要的依赖引入我们的项目中
在main.js中引入并使用安装好的vant
创建路由并加载到main.js
路由的配置
注意:路由文件所需要的home、user、cag组件自己先定义好,然后引入到路由文件中,大家也可以使用懒加载的方式,具体组件的创建就不演示了。
四、页面制作
在配置完路由之后,思考我们的配置的路由是做什么的。通常为了页面的切换,我们会需要一个固定在顶部的导航条,我们称之为tabbar,且所有的页面都能看到这个导航条
首页显示
路由配置结束,需要将其显示出来,路由出口配置在app.html页面
在本项目中,我将首页重定向到home页面,所有接下来的所有操作,我们去到home页面
这是home页面的结构,包括搜索框、轮播图、商品分类、商品显示,顶部导航,有经验的小伙伴可以看看view文件夹和components文件夹,这里我将具体的页面放在view下,其余组件拆分放到components
具体显示效果如下
现在我们拆分这个页面
搜索框
代码
<template>
<van-sticky>
<van-search
shape="round"
background="#1baeae"
placeholder="请输入搜索关键词"
>
</van-search>
</van-sticky>
</template>
van-sticky为黏性布局,也就是鼠标向下滑动,搜索框会固定在顶部
轮播图(swiper)
代码
<template>
<van-swipe :autoplay="3000" lazy-render>
<van-swipe-item v-for="(item,index) in newGoods.carousels" :key="index">
<img :src="item.carouselUrl" />
</van-swipe-item>
</van-swipe>
</template>
<script setup>
import {onMounted,reactive} from "vue"
import request from "../mock/request.js"
const newGoods = reactive(
{
carousels:[]
}
)
onMounted(async() =>{
let result = await request({
url:'/mock/getGoods',
method:'get'
})
if(result.data.code === 200){
newGoods.carousels = result.data.data.carousels
}
})
</script>
<style type="text/css" media="all" scoped>
img{
width: 100%;
height: 200px;
}
</style>
这里大家看看mock中我们写的假的json数据
{
"carousels": [
{
"carouselUrl": "https://res.vmallres.com/uomcdn/CN/cms/2024-05/6580fa613c574939a84e0a04e288292b.jpg",
"redirectUrl": "https://juejin.im/book/6844733826191589390"
},
{
"carouselUrl": "https://res.vmallres.com/uomcdn/CN/cms/202405/240051cba47c47d384142a253d50cb6d.png",
"redirectUrl": "https://juejin.im/book/6844733826191589390"
},
{
"carouselUrl": "https://res.vmallres.com/uomcdn/CN/cms/202406/c16311df062d43c49f9e692728b5efd4.jpg",
"redirectUrl": "https://juejin.im/book/6844733826191589390"
},
{
"carouselUrl": "https://res.vmallres.com/uomcdn/CN/cms/2024-05/1e56a1ce74b8447baaf08b87eaf007ec.jpg",
"redirectUrl": "https://juejin.im/book/6844733826191589390"
}
]
}
看看mockserver.js文件,如果小伙伴写过node的话,这里应该很好理解
这里写了三个接口,对于的三个页面数据,轮播图中用的数据都在goods中,在request文件中,只是简单的对超时做了限制
此项目不需要我们我们二次封装axios
了解完这些前置知识和后,我们在认真关注下我们的swiper组件中的内容
认真看完上面教程,给位友友们应该可以将轮播图正确显示出来了
商品分类
代码
<template>
<van-grid clickable :column-num="5">
<van-grid-item to="/cag" v-for="(value,index) in categoryList.list" :key="index" :text="value.name">
<van-image :src="value.imgUrl"></van-image>
<span>{{value.name}}</span>
</van-grid-item>
</van-grid>
</template>
<script setup>
import {onMounted,reactive} from "vue"
import request from "../mock/request.js"
const categoryList = reactive(
{
list:[]
}
)
onMounted(async() =>{
let result = await request({
url:'/mock/getCategoryList',
method:'get'
})
if(result.data.code === 200){
categoryList.list = result.data.data
}
})
</script>
<style type="text/css" media="all" >
.van-image__img{
width: 50px !important;
height: 50px !important;
}
span{
font-size: 20px !important;
}
</style>
我们看看这个页面的结构
mock中的数据
商品页面
代码
<template>
<header class="good-header">新品上线</header>
<div class="good-box" >
<div class="good-item" v-for="item in newGoods.newGoods" :key="item.goodsId" @click="goToDetail(item)">
<img :src="item.goodsCoverImg" alt="">
<div class="good-desc">
<div class="title">{{ item.goodsName }}</div>
<div class="price">¥ {{ item.sellingPrice }}</div>
</div>
</div>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
import {onMounted,reactive} from "vue"
import request from "../mock/request.js"
const router = useRouter();
const newGoods = reactive(
{
newGoods:[],
hots: [],
recommends: [],
}
)
onMounted(async() =>{
let result = await request({
url:'/mock/getGoods',
method:'get'
})
if(result.data.code === 200){
newGoods.newGoods = result.data.data.newGoodses
newGoods.hots = result.data.data.hotGoodses
newGoods.recommends = result.data.data.recommendGoodses
}
})
const goToDetail = (item) => {
router.push({ path: `/product/${item.goodsId}` })
}
</script>
<style scoped>
.good-header {
background: #f9f9f9;
height: 50px;
line-height: 50px;
text-align: center;
color: #1baeae;
font-size: 25px;
font-weight: 500;
}
.good-box {
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
}
.good-item {
box-sizing: border-box;
width: 50%;
border-bottom: 1PX solid #e9e9e9;
padding: 10px 10px;
}
.good-item:nth-child(2n + 1) {
border-right: 1PX solid #e9e9e9;
}
img {
display: block;
width: 120px;
margin: 0 auto;
}
.good-desc {
text-align: center;
font-size: 20px;
padding: 10px 0;
}
.title {
color: #222333;
}
.price {
color:#1baeae;
}
</style>
代码解释
点击挑转到商品详情
详情页面也是一致的,大家看情况编写。由于涉及到后续的购物车,所有我没有继续往下写了
底部导航
代码
<template>
<van-tabbar v-model="active" class="bar">
<van-tabbar-item icon="home-o" to="/home">首页</van-tabbar-item>
<van-tabbar-item icon="search" to="/cag">分类</van-tabbar-item>
<van-tabbar-item icon="friends-o" to="/user">个人</van-tabbar-item>
</van-tabbar>
</template>
<script setup>
import { ref} from "vue"
const active = ref('home');
</script>
<style type="text/css" >
.bar{
margin-top: 40px !important;
}
.van-tabbar-item{
font-size: 16px !important;
}
</style>
这里的代码就不做解释了,相信大家都能看懂
将所需要要的组件引入即可
分类页面
分类页面比较简单,经过首页一节的铺垫,现在我们将节奏快点
页面分为上中下三层。上层为搜索框;中间左侧为侧边栏,右边为商品;下层为导航条
代码
<template>
<TabNav></TabNav>
<div class="container">
<SliderNav></SliderNav>
<CagGoods></CagGoods>
</div>
<div style="width:100%;height:40px"></div>
<Tabbar></Tabbar>
</template>
<script setup>
import Tabbar from "../components/Tabbar.vue"
import TabNav from "../components/TabNav.vue"
import SliderNav from "../components/SliderNav.vue"
import CagGoods from "../components/CagGoods.vue"
</script>
<style scoped>
.container{
display: flex;
flex-direction: row;
}
.container .van-sidebar {
flex: 2;
}
.container .van-grid{
flex: 10;
}
</style>
这里贴出的代码是为了方便大家布局使用的
顶部导航
侧边栏
右侧goods
我的
<template>
<div class="user">
<Card></Card>
<div class="box">
<van-icon name="setting-o" class="setting"/>
<span>设置</span>
</div>
<div class="box1">
<van-icon name="service-o" class="service" ></van-icon>
<span>联系客服</span>
</div>
<MyOrder></MyOrder>
<MySerive></MySerive>
</div>
<Tabbar></Tabbar>
</template>
<script setup>
import Tabbar from "../components/Tabbar.vue"
import Card from "../components/Card.vue"
import MyOrder from "../components/MyOrder.vue"
import MySerive from "../components/MySerive.vue"
</script>
<style >
.user{
position: relative;
}
.van-card__title {
font-size: 20px !important;
margin-top: 10px;
height: 30px !important;
line-height: 30px;
}
.box{
display: flex;
position: absolute;
top: 10px;
right: 20px;
font-size: 25px;
flex-direction: column;
}
.box1{
display: flex;
position: absolute;
justify-content:center;
align-content: center;
top: 10px;
right: 80px;
font-size: 25px;
flex-direction: column;
}
.service{
text-align: center;
}
span{
font-size: 12px;
}
</style>
MyOrder
<template>
<div class="temp">
<div class="top">
<span class="order">我的订单</span>
<span class="all">全部></span>
</div>
<div class="content">
<div>
<van-icon name="shop-o" />
<span>待付款</span>
</div>
<div>
<van-icon name="gift-card-o" />
<span>待发货</span>
</div>
<div>
<van-icon name="setting-o" class="setting"/>
<span>待收货</span>
</div>
<div>
<van-icon name="chat-o" />
<span>待评价</span>
</div>
<div>
<van-icon name="balance-o" />
<span>退款/售后</span>
</div>
</div>
</div>
</template>
<script>
</script>
<style scoped>
*{
margin: 0;
padding: 0;
}
.temp{
display: flex;
flex-direction: column;
margin-top: 5px;
transition: 0.3s;
margin: 10px;
padding: 10px;
border-radius: 5px;
background: #1baeae;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
overflow: hidden;
}
.temp:hover{
box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
}
.top{
display: flex;
justify-content: space-between;
align-content: center;
}
.order{
font-size: 20px;
}
.all{
margin-right: 20px;
}
.content{
display: flex;
flex-direction: row;
justify-content: center;
}
.content div{
margin-top: 10px;
margin-left: 20px;
display: flex;
flex-direction: column;
flex: 1;
text-align: center;
}
.content div span{
margin-top: 5px;
}
</style>
这里大家掌握flex布局即可写出
MySerive
这个页面其实也是一样的,只是一个横向,一个纵向
写在最后
到这里就算写完了,希望各位友友们可以自己多加思考,清楚掌握。
同时也请大家多多点赞支持