目录

写在前面

预览

明确实现步骤

实现

代码(轮播图区域,不包含头部以及导航)

布局解读

轮播图事项

鼠标移除关闭子分类,不同情况右侧盒子的间距调整

鼠标悬停显示子分类

改进

源码地址:


写在前面

前段时间笔者不是专科毕业了么,当时写的毕业设计,是一个商城系统。原先的ui界面过于丑陋,于是就打算修改一下。

实现功能:在轮播图上显示商品分类、其他自定义内容。鼠标划过一级分类。显示子分类。子分类可点击进入搜索页面

预览

修改后:

修改前:

是不是好看多了?

明确实现步骤

  • 准备轮播图:使用elementplus的走马灯
  • 准备分类列表:一个垂直结构的列表
  • 将分类列表显示到轮播图上:使用相对定位
  • 鼠标划过分类列表,发送请求,并显示子分类列表:使用鼠标事件,变量结合v-show控制
  • 鼠标划出分类列表和子分类列表,子分类列表关闭:鼠标事件,变量结合v-show
  • 显示子分类和关闭子分类时,右侧盒子位置要保持不变:控制显示和不显示时的位置切换

我不会一步一步循序渐进的粘代码,因为步骤有点多,我相信读者也不想看又臭又长的代码,我想你只是想怎么快速读懂案例,并且能够快速找到不符合自己要求的部分,对其进行修改。

本文多次使用elementplus的layout布局

实现

先粘代码

代码(轮播图区域,不包含头部以及导航)

<template>
  <div class="carousel-container">
    <el-carousel height="500px" motion-blur arrow="always">
      <el-carousel-item v-for="item in homeAdvList" :key="item">
        <el-image :src="$img+item.pic" fit="fill" @click="goDetail(item.skuId)" style="height: 500px;width: 1440px"/>
      </el-carousel-item>
    </el-carousel>
    <div class="overlay-content" @mouseleave="showCate=false" @click="showCate=false">
      <el-row :gutter="10" style="height: 90%">
        <el-col :offset="2" :span="4">
          <el-card>
            <el-space direction="vertical" alignment="flex-start" fill style="width: 100%">
              <div v-for="item in categoryListData" :key="item.id">
                <div @mouseover="getLevel1Category(item.id)" class="category_item_box">
                  <span style="font-size: 18px"> {{ item.name }}</span>
                  <div style="height: 20px;width: 20px">
                    <ArrowRight/>
                  </div>
                </div>
              </div>
            </el-space>
          </el-card>
        </el-col>
        <el-col :span="8" v-show="showCate">
          <el-card>
            <div v-for="item in Level1CategoryItem" style="padding: 10px 0" :key="item.id" class="category_item_box">
                 <span style="font-weight: 600;font-size: 16px">
                   {{ item.name }}
                 </span>
              <br>
              <div style="padding-left: 30px">
                    <span v-for="third in item.children" :key="third.id"
                          @click="goCommodityCategoryView(third.id,third.name)">
                      {{ third.name }}
                      <el-divider direction="vertical"/>
                    </span>
              </div>
              <hr>
            </div>
          </el-card>
        </el-col>
        <el-col :offset="showCate ? 4 : 12" :span="4">
          <el-card style="height: 98%;">
            <template #header>
              <div class="card-header">
                <span>系统公告</span>
              </div>
            </template>
            <div>
              xxx
            </div>
          </el-card>
        </el-col>
      </el-row>
    </div>
  </div>
  <div style="padding-left: 150px">
    <h2>最新上架</h2>
    <el-divider/>
  </div>
  <div class="selected_father">
    <div class="selected_class">
      <el-scrollbar>
        <div class="scrollbar-flex-content">
          <div v-for="(item,index) in newSkuList" :key="item.id" class="scrollbar-demo-item" @click="toDetail(item.id)">
            <el-image style="width: 150px; height: 150px" :src="$img+item.skuDefaultImg" fit="fill">
              <template #error>
                <div class="image-slot">
                  <el-icon>
                    <icon-picture/>
                  </el-icon>
                </div>
              </template>
            </el-image>
            <div v-if="index!==newSkuList.length-1">
              <el-divider direction="vertical" style="height: 150px"/>
            </div>
          </div>
        </div>
      </el-scrollbar>
    </div>
  </div>
  <div class="commodity_list_box_father">
    <commodity-list></commodity-list>
  </div>
</template>
<script setup>
import CommodityList from "@/components/home/CommodityList";
import {getCategoryByParent, getTreCategoryByParent} from "@/api/category";
import {getNewSkuListApi} from '@/api/goods'
import {onMounted, reactive, ref} from "vue";
import {useRouter} from "vue-router";
import {getUsingHomeAdvList} from "@/api";

let categoryListData = ref([])
let router = useRouter()
let pageInfo = reactive({
  pageNum: 1,
  pageSize: 5,
  total: Number
})
let newSkuList = ref([])
let homeAdvList = ref([])

function getHomeAdv() {
  getUsingHomeAdvList().then(res => {
    homeAdvList.value = res.data
  })
}

function goDetail(skuId) {
  router.push({
    path: '/detail',
    query: {
      skuId
    }
  })
}

onMounted(() => {
  /*获取一级分类*/
  getLevelCategoryList()
  //获取首页轮播广澳
  getHomeAdv()
  //获取最新上架的商品
  getNewSkuList()
})

/**
 * 获取以一级分类
 */
function getLevelCategoryList() {
  getCategoryByParent(0).then((res) => {
    categoryListData.value = res.data
  })
}

/*
获取最新上架sku
 */
function getNewSkuList() {
  getNewSkuListApi(pageInfo).then(res => {
    newSkuList.value = res.data.records
  })
}

/**
 * 前往商品详情
 * @param skuId
 */
function toDetail(skuId) {
  router.push({
    path: '/detail',
    query: {
      skuId: skuId
    }
  })
}

//是否显示分类信息
let showCate = ref(false)
let Level1CategoryItem = ref([])//一级分类下的所有子分类
/**
 * 前往该分类下的搜索页面
 * @param categoryId
 */
function goCommodityCategoryView(categoryId, categoryName) {
  router.push({
    path: '/commodity-search',
    query: {
      categoryId,
      categoryName
    }
  })
}

/**
 * 获取选择的以及分类下的子分类(树结构)
 * @param selectCategory
 */
function getLevel1Category(selectCategory) {
  getTreCategoryByParent(selectCategory).then(res => {
    Level1CategoryItem.value = res.data
  }).finally(()=>{
    showCate.value = true
  })
}
</script>

<style scoped>
.carousel-container {
  height: 500px;
  position: relative; /* 确保子元素可以使用绝对定位 */
  width: 100%; /* 根据需要调整 */
  overflow: hidden; /* 如果需要隐藏超出轮播图的内容 */
}

.overlay-content {
  position: absolute;
  margin-top: 20px;
  top: 0;/*此处可根据需要调整,但必须有 */
  color: white; /* 根据背景色调整文本颜色 */
  width: 100%; /* 根据需要调整宽度 */
  z-index: 10; /* 确保内容在轮播图之上 */
}
.selected_father {
  display: flex;
  justify-content: center;
}

.category_item_box:hover {
  background-color: #d3dce6;
  color: #098CC0;
}

.category_item_box {
  display: flex;
  justify-content: space-between;
}

.commodity_list_box_father {
  display: flex;
  justify-content: center;
}

.selected_class {
  width: 80%;
}

.scrollbar-flex-content {
  display: flex;
}

.scrollbar-demo-item {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  border-radius: 4px;
  padding: 5px;
}

.card-header {
  background-color: orange;
}
</style>

布局解读

样式如下:

轮播图事项

指定高度,使用elemntplus提供的height属性指定大小;图片设置大小,并且使用fill值(即使图片不够宽高,也能自动拉伸填充指定的大小);$img是我后端服务器响应图片的接口地址,在此处可以更改为你图片路径

鼠标移除关闭子分类,不同情况右侧盒子的间距调整

由于这个class为overlay-content的div宽度范围比较大,导致鼠标横向滑动很难将shoCate的值转为false,所以此处可以添加一个点击事件,点击就关闭。这样如果你不想显示的时候随便点击就能关闭子分类的显示

鼠标悬停显示子分类

改进

上面的布局存在两个问题:

  1. 分类盒子过大,鼠标左右移动难以触发鼠标移出事件
  2. 显示子分类和不显示子分类时,右侧的盒子需要计算位置

总的来说就是布局不合理,这里我采用多次嵌套elmentplus的el-row和el-col解决。上面的代码因为有讲解,我就不删了。毕竟又不是什么大问题

改进后代码如下:

<template>
  <div class="carousel-container">
    <el-carousel height="500px" motion-blur arrow="always">
      <el-carousel-item v-for="item in homeAdvList" :key="item">
        <el-image :src="$img+item.pic" fit="fill" @click="goDetail(item.skuId)" style="height: 500px;width: 1440px"/>
      </el-carousel-item>
    </el-carousel>
    <div class="overlay-content" @click="showCate=false">
      <el-row :gutter="10" style="height: 90%">
        <el-col :offset="2" :span="12" @mouseleave="showCate=false">
          <el-row>
            <el-col :span="8">
              <el-card>
                <el-space direction="vertical" alignment="flex-start" fill style="width: 100%">
                  <div v-for="item in categoryListData" :key="item.id">
                    <div @mouseover="getLevel1Category(item.id)" class="category_item_box">
                      <span style="font-size: 18px"> {{ item.name }}</span>
                      <div style="height: 20px;width: 20px">
                        <ArrowRight/>
                      </div>
                    </div>
                  </div>
                </el-space>
              </el-card>
            </el-col>
            <el-col :span="16" v-show="showCate">
              <el-card>
                <div v-for="item in Level1CategoryItem" style="padding: 10px 0" :key="item.id"
                     class="category_item_box">
                 <span style="font-weight: 600;font-size: 16px">
                   {{ item.name }}
                 </span>
                  <br>
                  <div style="padding-left: 30px">
                    <span v-for="third in item.children" :key="third.id"
                          @click="goCommodityCategoryView(third.id,third.name)">
                      {{ third.name }}
                      <el-divider direction="vertical"/>
                    </span>
                  </div>
                  <hr>
                </div>
              </el-card>
            </el-col>
          </el-row>
        </el-col>
        <el-col :offset="5" :span="4">
          <el-card style="height: 98%;">
            <template #header>
              <div class="card-header">
                <span>系统公告</span>
              </div>
            </template>
            <div>
              xxx
            </div>
          </el-card>
        </el-col>
      </el-row>
    </div>
  </div>
  <div style="padding-left: 150px">
    <h2>最新上架</h2>
    <el-divider/>
  </div>
  <div class="selected_father">
    <div class="selected_class">
      <el-scrollbar>
        <div class="scrollbar-flex-content">
          <div v-for="(item,index) in newSkuList" :key="item.id" class="scrollbar-demo-item" @click="toDetail(item.id)">
            <el-image style="width: 150px; height: 150px" :src="$img+item.skuDefaultImg" fit="fill">
              <template #error>
                <div class="image-slot">
                  <el-icon>
                    <icon-picture/>
                  </el-icon>
                </div>
              </template>
            </el-image>
            <div v-if="index!==newSkuList.length-1">
              <el-divider direction="vertical" style="height: 150px"/>
            </div>
          </div>
        </div>
      </el-scrollbar>
    </div>
  </div>
  <div class="commodity_list_box_father">
    <commodity-list></commodity-list>
  </div>
</template>
<script setup>
import CommodityList from "@/components/home/CommodityList";
import {getCategoryByParent, getTreCategoryByParent} from "@/api/category";
import {getNewSkuListApi} from '@/api/goods'
import {onMounted, reactive, ref} from "vue";
import {useRouter} from "vue-router";
import {getUsingHomeAdvList} from "@/api";

let categoryListData = ref([])
let router = useRouter()
let pageInfo = reactive({
  pageNum: 1,
  pageSize: 5,
  total: Number
})
let newSkuList = ref([])
let homeAdvList = ref([])

function getHomeAdv() {
  getUsingHomeAdvList().then(res => {
    homeAdvList.value = res.data
  })
}

function goDetail(skuId) {
  router.push({
    path: '/detail',
    query: {
      skuId
    }
  })
}

onMounted(() => {
  /*获取一级分类*/
  getLevelCategoryList()
  //获取首页轮播广澳
  getHomeAdv()
  //获取最新上架的商品
  getNewSkuList()
})

/**
 * 获取以一级分类
 */
function getLevelCategoryList() {
  getCategoryByParent(0).then((res) => {
    categoryListData.value = res.data
  })
}

/*
获取最新上架sku
 */
function getNewSkuList() {
  getNewSkuListApi(pageInfo).then(res => {
    newSkuList.value = res.data.records
  })
}

/**
 * 前往商品详情
 * @param skuId
 */
function toDetail(skuId) {
  router.push({
    path: '/detail',
    query: {
      skuId: skuId
    }
  })
}

//是否显示分类信息
let showCate = ref(false)
let Level1CategoryItem = ref([])//一级分类下的所有子分类
/**
 * 前往该分类下的搜索页面
 * @param categoryId
 */
function goCommodityCategoryView(categoryId, categoryName) {
  router.push({
    path: '/home/commodity-search',
    query: {
      categoryId,
      categoryName
    }
  })
}

/**
 * 获取选择的以及分类下的子分类(树结构)
 * @param selectCategory
 */
function getLevel1Category(selectCategory) {
  getTreCategoryByParent(selectCategory).then(res => {
    Level1CategoryItem.value = res.data
  }).finally(() => {
    showCate.value = true
  })
}
</script>

<style scoped>
.carousel-container {
  height: 500px;
  position: relative; /* 确保子元素可以使用绝对定位 */
  width: 100%; /* 根据需要调整 */
  overflow: hidden; /* 如果需要隐藏超出轮播图的内容 */
}

.overlay-content {
  position: absolute;
  margin-top: 20px;
  top: 0; /*此处可根据需要调整,但必须有 */
  color: white; /* 根据背景色调整文本颜色 */
  width: 100%; /* 根据需要调整宽度 */
  z-index: 10; /* 确保内容在轮播图之上 */
}

.selected_father {
  display: flex;
  justify-content: center;
}

.category_item_box:hover {
  background-color: #d3dce6;
  color: #098CC0;
}

.category_item_box {
  display: flex;
  justify-content: space-between;
}

.commodity_list_box_father {
  display: flex;
  justify-content: center;
}

.selected_class {
  width: 80%;
}

.scrollbar-flex-content {
  display: flex;
}

.scrollbar-demo-item {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  border-radius: 4px;
  padding: 5px;
}

.card-header {
  background-color: orange;
}
</style>

源码地址:

毕业设计:轻松购: 使用vue3+springboot构建的商城系统,集前台用户和后台管理于一体,本项目已经部署在云服务器上,访问地址:前台系统:123.207.205.51 后台系统:123.207.205.51:8080

找到

GitHub 加速计划 / eleme / element
54.07 K
14.63 K
下载
A Vue.js 2.0 UI Toolkit for Web
最近提交(Master分支:3 个月前 )
c345bb45 7 个月前
a07f3a59 * Update transition.md * Update table.md * Update transition.md * Update table.md * Update transition.md * Update table.md * Update table.md * Update transition.md * Update popover.md 8 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐