Eric小屋

  • 编程思路
  • 一、分析结构
  • 二、准备模板
  • 三、编写组件
  • 四、接口调用
  • 五、运行测试
  • 首页
  • 学习笔记
    • JAVA
    • Spring
    • Node.js
    • Vue
  • 学习文档
  • 案例项目
  • 课程笔记
  • 问题解决
登录

小兔鲜 Home页

  • Eric
  • 2024-07-01
  • 0

主页原型图

主页文件夹

编程思路

一、分析结构

1、新建主文件夹 里面创建入口文件 组件文件 分模块

2、新建模块文件 在入口文件引入组件

<script setup>
import HomeBanner from './components/HomeBanner.vue';
import HomeCategory from './components/HomeCategory.vue';
import HomeProduct from './components/HomeProduct.vue';
import HomeNew from './components/HomeNew.vue';
import HomeHot from './components/HomeHot.vue';
</script>
<template>
    <div class="container">
        <HomeCategory />
        <HomeBanner />
    </div>
    <HomeNew />
    <HomeHot />
    <HomeProduct />
</template>
<style></style>

二、准备模板

三、编写组件

一个banner组件 一个商品推荐页组件

banner:

<script setup>
import { getBannerAPI } from '@/apis/home.js'
import { onMounted, ref } from 'vue';
const bannerList = ref([])
const getBanner = async () => {
  const res = await getBannerAPI()
  if (res.code !== '1') {
    return
  }
  bannerList.value = res.result
}
onMounted(() => getBanner())
</script>



<template>
  <div class="home-banner">
    <el-carousel height="500px">
      <el-carousel-item v-for="item in bannerList" :key="item.id">
        <img :src=item.imgUrl>
      </el-carousel-item>
    </el-carousel>
  </div>
</template>



<style scoped lang='scss'>
.home-banner {
  width: 1240px;
  height: 500px;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 98;

  img {
    width: 100%;
    height: 500px;
  }
}
</style>

商品推荐页:

<script setup>
defineProps({
    title: {
    type: String,
    default: ''
  },
  subTitle: {
    type: String,
    default: ''
  }
})
</script>


<template>
  <div class="home-panel">
    <div class="container">
      <div class="head">
         <!-- 主标题和副标题 -->
        <h3>
          {{title}}<small>{{subTitle}}</small>
        </h3>
      </div>
      <!-- 主体内容区域 -->
      <slot></slot>
    </div>
  </div>
</template>

<style scoped lang='scss'>
.home-panel {
  background-color: #fff;

  .head {
    padding: 40px 0;
    display: flex;
    align-items: flex-end;

    h3 {
      flex: 1;
      font-size: 32px;
      font-weight: normal;
      margin-left: 6px;
      height: 35px;
      line-height: 35px;

      small {
        font-size: 16px;
        color: #999;
        margin-left: 20px;
      }
    }
  }
}
</style>

商品推荐页的插槽:

<script setup>
import { onMounted, ref } from 'vue';
import HomePanel from './HomePanel.vue';
import { findNewAPI } from '@/apis/home'

const newList = ref([])

async function getNewList() {
  const res = await findNewAPI();
  if (res.code !== '1') {
    return
  }
  newList.value = res.result
}

onMounted(() => {
  getNewList()
})
</script>

<template>
  <HomePanel title="新鲜好物" sub-title="新鲜出炉 品质靠谱">
    <ul class="goods-list">
      <li v-for="item in newList" :key="item.id">
        <RouterLink :to="`/detail/${item.id}`">
          <img :src="item.picture" alt="" />
          <p class="name">{{ item.name }}</p>
          <p class="price">&yen;{{ item.price }}</p>
        </RouterLink>
      </li>
    </ul>
  </HomePanel>
</template>


<style scoped lang='scss'>
.goods-list {
  display: flex;
  justify-content: space-between;
  height: 406px;

  li {
    width: 306px;
    height: 406px;

    background: #f0f9f4;
    transition: all .5s;

    &:hover {
      transform: translate3d(0, -3px, 0);
      box-shadow: 0 3px 8px rgb(0 0 0 / 20%);
    }

    img {
      width: 306px;
      height: 306px;
    }

    p {
      font-size: 22px;
      padding-top: 12px;
      text-align: center;
      text-overflow: ellipsis;
      overflow: hidden;
      white-space: nowrap;
    }

    .price {
      color: $priceColor;
    }
  }
}
</style>

四、接口调用

编写拦截器(一般使用模板):

// axios基础封装
import axios from 'axios'

import { useUserStore } from '@/stores/userStore.js'
import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/el-message.css'
import router from '@/router'


// 创建axios实例
const httpInstance = axios.create({
    baseURL: 'http://pcapi-xiaotuxian-front-devtest.itheima.net',
    timeout: 5000,
})

// axios请求拦截器
httpInstance.interceptors.request.use(config => {
    // 1. 从pinia获取token数据
    const userStore = useUserStore()
    // 2. 按照后端的要求拼接token数据
    const token = userStore.userInfo.token
    if (token) {
        config.headers.Authorization = `Bearer ${token}`
    }
    return config
}, e => Promise.reject(e))

// axios响应式拦截器
httpInstance.interceptors.response.use(res => res.data, e => {
    // 处理响应失败 统一错误提示
    ElMessage({ type: 'warning', message: e.response.data.message || '系统错误' })
    // 401 token 错误处理
    if (e.response.status === 401) {
        const userStore = useUserStore()
        userStore.clearUserInfo()
        router.push('/login')
    }
    return Promise.reject(e)
})

export default httpInstance

接口编写模板:

import http from "@/utils/http";

export function getXXX( ) {


    return http({
        url: '/home/home',
    })
}

1、轮播图数据接口

2、获取新鲜好物接口

import httpInstance from "@/utils/http";

// 获取 轮播图 数据
export function getBannerAPI(params = {}) {
    // 默认为1 商品为2
    const { distributionSite = '1' } = params
    return httpInstance({
        url: '/home/banner',
        params: {
            distributionSite
        }
    })
}

/**
 * @description: 获取新鲜好物
 * @param {*}
 * @return {*}
 */
export const findNewAPI = () => {
    return httpInstance({
        url: '/home/new'
    })
}

/**
 * @description: 获取所有商品模块
 * @param {*}
 * @return {*}
 */
export const getGoodsAPI = () => {
    return httpInstance({
        url: '/home/goods'
    })
}

五、运行测试

联系作者:2572976830@qq.com
© 2025 Eric小屋
Theme by Wing
京ICP备2023032157号 京公网安备11011402053616号
  • {{ item.name }}
  • {{ item.name }}