Vue3 小兔鲜4:Layout-静态模版结构搭建
Date: May 31, 2023
目标效果:
分成Nav、Heade、二级路由出口、Footer区域
组件结构快速搭建
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
import LayoutNav from './components/LayoutNav.vue'
import LayoutHeader from './components/LayoutHeader.vue'
import LayoutFooter from './components/LayoutFooter.vue'
字体图标渲染
效果:
具体操作:
-
在index.html中导入图标库
字体图标采用的是阿里的字体图标库,样式文件已经准备好,在 index.html文件中引入即可
link rel="stylesheet" href="//at.alicdn.com/t/font_2143783_iq6z4ey5vu.css">
- 在标签中具体使用即可
一级导航渲染
使用后端接口渲染一级路由导航:
实现步骤
- 封装接口函数
- 调用接口函数
- v-for渲染模版
代码落地
import httpInstance from '@/utils/http'
export function getCategoryAPI () {
return httpInstance({
url: '/home/category/head'
})
}
import { getCategoryAPI } from '@/apis/layout'
import { onMounted, ref } from 'vue'
const categoryList = ref([])
const getCategory = async () => {
const res = await getCategoryAPI()
categoryList.value = res.result
}
onMounted(() => getCategory())
小兔鲜
-
{{ item.name }}
吸顶导航交互实现
吸顶交互要求:
页面在上下滚动的过程中,如果距离顶部的滚动距离大手78pX,吸顶导航显示,小于78px隐藏
实现思路:
准备吸顶导航组件⇒获取滚动距离⇒以滚动距离做判断条件控制组件盒子展示隐藏
1. 准备组件静态结构
实现步骤:
- 搞定顶吸组件:LayoutFixed.vue
// vueUse
import { useScroll } from '@vueuse/core'
const { y } = useScroll(window) // 这里的y就是滚动时的实时距离
效果:
2. 渲染基础数据
原始代码:
-
Code
- 首页
- 居家
- 美食
- 服饰
- 母婴
- 个护
- 严选
- 数码
- 运动
- 杂项
品牌 专题
这里我们修改一下,通过v-for进行循环:
LayoutFixed.vue
{{ item.name }}
3. 实现吸顶交互
核心逻辑:根据滚动距离判断当前show类名是否显示,大于78显示,小于78,不显示
import LayoutHeaderUl from './LayoutHeaderUl.vue'
// vueUse
import { useScroll } from '@vueuse/core'
const { y } = useScroll(window)
Pinia优化重复请求
问题:
两个导航中的列表是完全一致的,但是要发送两次网络请求,存在浪费。
优化方式:
通过Pinia集中管理数据,再把数据给组件使用。值的注意的是,我们会在两个子组件的公共父组件中把action触发起来,这样能够保证这个action只会触发一次。
代码:
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()
categoryList.value = res.result
}
return {
categoryList, getCategory
}
})
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
Supported countries and regions Here are the countries, regions, and territories we can currently support access from: Albania Alg…