黑马程序员前端 Vue3 小兔鲜电商项目——(三)Layout 首页页面布局
文章目录
- 组件结构快速搭建
- 首页组件结构
- Nav 组件
- Header 组件
- Footer 组件
- index.vue 中添加组件
- 字体图标渲染
- 一级导航渲染
- 封装接口函数
- 渲染数据
- 吸顶导航交互实现
- 安装 VueUser 插件
- 组件静态结构
- 添加组件
- 实现吸顶交互
- Pinia优化重复请求
组件结构快速搭建
首页组件结构
页面效果如下:
可以将页面分为四个部分:Nav、Header、二级页面、Footer。
分别在下面创建三个vue文件:
Nav 组件
添加代码:
.app-topnav {
background: #333;
ul {
display: flex;
height: 53px;
justify-content: flex-end;
align-items: center;
li {
a {
padding: 0 15px;
color: #cdcdcd;
line-height: 1;
display: inline-block;
i {
font-size: 14px;
margin-right: 2px;
}
&:hover {
color: $xtxColor;
}
}
~li {
a {
border-left: 2px solid #666;
}
}
}
}
}
Header 组件
添加代码:
小兔鲜
-
首页
-
居家
-
美食
-
服饰
.app-header {
background: #fff;
.container {
display: flex;
align-items: center;
}
.logo {
width: 200px;
a {
display: block;
height: 132px;
width: 100%;
text-indent: -9999px;
background: url('@/assets/images/logo.png') no-repeat center 18px / contain;
}
}
.app-header-nav {
width: 820px;
display: flex;
padding-left: 40px;
position: relative;
z-index: 998;
li {
margin-right: 40px;
width: 38px;
text-align: center;
a {
font-size: 16px;
line-height: 32px;
height: 32px;
display: inline-block;
&:hover {
color: $xtxColor;
border-bottom: 1px solid $xtxColor;
}
}
.active {
color: $xtxColor;
border-bottom: 1px solid $xtxColor;
}
}
}
.search {
width: 170px;
height: 32px;
position: relative;
border-bottom: 1px solid #e7e7e7;
line-height: 32px;
.icon-search {
font-size: 18px;
margin-left: 5px;
}
input {
width: 140px;
padding-left: 5px;
color: #666;
}
}
.cart {
width: 50px;
.curr {
height: 32px;
line-height: 32px;
text-align: center;
position: relative;
display: block;
.icon-cart {
font-size: 22px;
}
em {
font-style: normal;
position: absolute;
right: 0;
top: 0;
padding: 1px 6px;
line-height: 1;
background: $helpColor;
color: #fff;
font-size: 12px;
border-radius: 10px;
font-family: Arial;
}
}
}
}
Footer 组件
添加代码:
.app_footer {
overflow: hidden;
background-color: #f5f5f5;
padding-top: 20px;
.contact {
background: #fff;
.container {
padding: 60px 0 40px 25px;
display: flex;
}
dl {
height: 190px;
text-align: center;
padding: 0 72px;
border-right: 1px solid #f2f2f2;
color: #999;
&:first-child {
padding-left: 0;
}
&:last-child {
border-right: none;
padding-right: 0;
}
}
dt {
line-height: 1;
font-size: 18px;
}
dd {
margin: 36px 12px 0 0;
float: left;
width: 92px;
height: 92px;
padding-top: 10px;
border: 1px solid #ededed;
.iconfont {
font-size: 36px;
display: block;
color: #666;
}
&:hover {
.iconfont {
color: $xtxColor;
}
}
&:last-child {
margin-right: 0;
}
}
.qrcode {
width: 92px;
height: 92px;
padding: 7px;
border: 1px solid #ededed;
}
.download {
padding-top: 5px;
font-size: 14px;
width: auto;
height: auto;
border: none;
span {
display: block;
}
a {
display: block;
line-height: 1;
padding: 10px 25px;
margin-top: 5px;
color: #fff;
border-radius: 2px;
background-color: $xtxColor;
}
}
.hotline {
padding-top: 20px;
font-size: 22px;
color: #666;
width: auto;
height: auto;
border: none;
small {
display: block;
font-size: 15px;
color: #999;
}
}
}
.extra {
background-color: #333;
}
.slogan {
height: 178px;
line-height: 58px;
padding: 60px 100px;
border-bottom: 1px solid #434343;
display: flex;
justify-content: space-between;
a {
height: 58px;
line-height: 58px;
color: #fff;
font-size: 28px;
i {
font-size: 50px;
vertical-align: middle;
margin-right: 10px;
font-weight: 100;
}
span {
vertical-align: middle;
text-shadow: 0 0 1px #333;
}
}
}
.copyright {
height: 170px;
padding-top: 40px;
text-align: center;
color: #999;
font-size: 15px;
p {
line-height: 1;
margin-bottom: 20px;
}
a {
color: #999;
line-height: 1;
padding: 0 10px;
border-right: 1px solid #999;
&:last-child {
border-right: none;
}
}
}
}
index.vue 中添加组件
字体图标渲染
字体图标采用的是阿里的字体图标库,样式文件已经准备好,在
index.html
文件中引入即可
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小兔鲜儿</title>
<link rel="stylesheet" href="//at.alicdn.com/t/font_2143783_iq6z4ey5vu.css">
</head>
一级导航渲染
导航栏效果如图显示:
封装接口函数
在 src/apis 目录下创建 layout.js 文件:
在其中编写函数使用 Axios 访问导航栏接口 Api:
import http from '@/utils/http'
export function getCategoryAPI () {
return http({
url: 'home/category/head'
})
渲染数据
在 LayoutHeader.vue 文件的
并在 html 中使用 v-for
标签进行遍历输出。
-
首页
-
{{ item.name }}
吸顶导航交互实现
要求:浏览器在上下滚动的过程中,如果距离顶部的滚动距离大于78印X,吸顶导航显示,小于78px隐藏
安装 VueUser 插件
VueUse 是一个基于 Composition API 的实用程序函数集合。
npm i @vueuse/core
组件静态结构
-
首页
-
居家
-
美食
-
服饰
-
母婴
-
个护
-
严选
-
数码
-
运动
-
杂项
品牌
专题
.app-header-sticky {
width: 100%;
height: 80px;
position: fixed;
left: 0;
top: 0;
z-index: 999;
background-color: #fff;
border-bottom: 1px solid #e4e4e4;
// 此处为关键样式!!!
// 状态一:往上平移自身高度 + 完全透明
transform: translateY(-100%);
opacity: 0;
// 状态二:移除平移 + 完全不透明
&.show {
transition: all 0.3s linear;
transform: none;
opacity: 1;
}
.container {
display: flex;
align-items: center;
}
.logo {
width: 200px;
height: 80px;
background: url("@/assets/images/logo.png") no-repeat right 2px;
background-size: 160px auto;
}
.right {
width: 220px;
display: flex;
text-align: center;
padding-left: 40px;
border-left: 2px solid $xtxColor;
a {
width: 38px;
margin-right: 40px;
font-size: 16px;
line-height: 1;
&:hover {
color: $xtxColor;
}
}
}
}
.app-header-nav {
width: 820px;
display: flex;
padding-left: 40px;
position: relative;
z-index: 998;
li {
margin-right: 40px;
width: 38px;
text-align: center;
a {
font-size: 16px;
line-height: 32px;
height: 32px;
display: inline-block;
&:hover {
color: $xtxColor;
border-bottom: 1px solid $xtxColor;
}
}
.active {
color: $xtxColor;
border-bottom: 1px solid $xtxColor;
}
}
}
添加组件
在 index.vue 中添加吸顶导航栏组件:
// 吸顶导航栏组件
实现吸顶交互
核心逻辑:根据滚动距离判断当前show类名是否显示,大于78显示,小于78,不显示
78 }">
Pinia优化重复请求
吸顶导航栏和一级导航栏获取数据的逻辑是一模一样的,但是一样的数据会调用两次接口,所以使用 Pinia 优化重复请求。
在 stores 目录下创建 category.js 文件:
import { ref } from 'vue'
import { defineStore } from 'pinia'
import { getCategoryAPI } from '@/apis/layout'
export const useCategoryStore = defineStore('category', () => {
// 导航列表数据管理
//state 导航列表数据
const categoryList = ref([])
// action 获取导航数据的方法
const getCategory = async () => {
const res = await getCategoryAPI();
console.log(res);
categoryList.value = res.result;
}
return {
categoryList, getCategory
}
})
在 Layout/index.vue 中调用 useCategoryStore
获取数据的方法:
import { useCategoryStore } from '@/stores/category'
import { onMounted } from 'vue'
const categoryStore = useCategoryStore()
onMounted(() => {
categoryStore.getCategory()
})
之后在 LayoutHeader.vue 中导入方法直接访问 useCategoryStore
中存储数据的 categoryList
即可。同理,LayoutFixed.vue 也是如此:
//导入方法
import { useCategoryStore } from '@/stores/category'
const categoryStore = useCategoryStore()
-
首页
-
{{ item.name }}