最近发现职场前端用的框架大多为vue,所以最近也跟着黑马程序员vue3的课程进行学习,以下是我的学习记录
视频网址:
Day2-17.Layout-Pinia优化重复请求_哔哩哔哩_bilibili
学习日记:
vue3学习日记1 - 环境搭建-CSDN博客
vue3学习日记2 - 组合式API基础学习-CSDN博客
vue3学习日记3 - 组合式API练习小案例-CSDN博客
vue3学习日记4 - Pinia-CSDN博客
vue3学习日记5 - 项目起步-CSDN博客
一、静态模板结构搭建
1、在Layout文件夹下新建以下文件夹及项目
2、将以下代码复制给对应文件
LauoutFooter.vue
<template><footer class="app_footer"><!-- 联系我们 --><div class="contact"><div class="container"><dl><dt>客户服务</dt><dd><i class="iconfont icon-kefu"></i> 在线客服</dd><dd><i class="iconfont icon-question"></i> 问题反馈</dd></dl><dl><dt>关注我们</dt><dd><i class="iconfont icon-weixin"></i> 公众号</dd><dd><i class="iconfont icon-weibo"></i> 微博</dd></dl><dl><dt>下载APP</dt><dd class="qrcode"><img src="@/assets/images/qrcode.jpg" /></dd><dd class="download"><span>扫描二维码</span><span>立马下载APP</span><a href="javascript:;">下载页面</a></dd></dl><dl><dt>服务热线</dt><dd class="hotline">400-0000-000 <small>周一至周日 8:00-18:00</small></dd></dl></div></div><!-- 其它 --><div class="extra"><div class="container"><div class="slogan"><a href="javascript:;"><i class="iconfont icon-footer01"></i><span>价格亲民</span></a><a href="javascript:;"><i class="iconfont icon-footer02"></i><span>物流快捷</span></a><a href="javascript:;"><i class="iconfont icon-footer03"></i><span>品质新鲜</span></a></div><!-- 版权信息 --><div class="copyright"><p><a href="javascript:;">关于我们</a><a href="javascript:;">帮助中心</a><a href="javascript:;">售后服务</a><a href="javascript:;">配送与验收</a><a href="javascript:;">商务合作</a><a href="javascript:;">搜索推荐</a><a href="javascript:;">友情链接</a></p><p>CopyRight © 小兔鲜儿</p></div></div></div></footer>
</template><style scoped lang='scss'>
.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;}}}
}
</style>
LayoutNav.vue
<script setup></script><template><nav class="app-topnav"><div class="container"><ul><template v-if="true"><li><a href="javascript:;"><i class="iconfont icon-user"></i>周杰伦</a></li><li><el-popconfirm title="确认退出吗?" confirm-button-text="确认" cancel-button-text="取消"><template #reference><a href="javascript:;">退出登录</a></template></el-popconfirm></li><li><a href="javascript:;">我的订单</a></li><li><a href="javascript:;">会员中心</a></li></template><template v-else><li><a href="javascript:;">请先登录</a></li><li><a href="javascript:;">帮助中心</a></li><li><a href="javascript:;">关于我们</a></li></template></ul></div></nav>
</template><style scoped lang="scss">
.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;}}}}
}
</style>
LayoutHeader.vue
<script setup></script><template><header class='app-header'><div class="container"><h1 class="logo"><RouterLink to="/">小兔鲜</RouterLink></h1><ul class="app-header-nav"><li class="home"><RouterLink to="/">首页</RouterLink></li><li> <RouterLink to="/">居家</RouterLink> </li><li> <RouterLink to="/">美食</RouterLink> </li><li> <RouterLink to="/">服饰</RouterLink> </li></ul><div class="search"><i class="iconfont icon-search"></i><input type="text" placeholder="搜一搜"></div><!-- 头部购物车 --></div></header>
</template><style scoped lang='scss'>
.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;}}}
}
</style>
index.vue
<script setup>
import LayoutNav from './componments/LayoutNav.vue'
import LayoutHeader from './componments/LayoutHeader.vue'
import LayoutFooter from './componments/LayoutFooter.vue'
</script><template><LayoutNav /><LayoutHeader /><RouterView /><LayoutFooter />
</template>
运行结果
如图所示,我的Nav和Header是在一行的,可以修改index.vue,使其换行
<script setup>
import LayoutNav from './componments/LayoutNav.vue'
import LayoutHeader from './componments/LayoutHeader.vue'
import LayoutFooter from './componments/LayoutFooter.vue'
</script><template><div><LayoutNav /><LayoutHeader /><RouterView /><LayoutFooter /></div>
</template>
二、字体图标引入
1、阿里巴巴矢量库的使用
官网:iconfont-阿里巴巴矢量图标库
教程:
1、搜索自己想要的图标,点击加入购物车
2、点击购物车 -> 添加至项目 -> 确定 -> 会跳转到我的项目
3、展开在线连接在代码中使用
2、项目使用
1、在index.html中引入链接
<link rel="stylesheet" href="//at.alicdn.com/t/font_2143783_iq6z4ey5vu.css">
2、使用
<i class="iconfont icon-kefu"></i>
3、运行结果
三、一级导航渲染
1、在api文件夹下建立文件Layout.js
文件内容
import httpInstance from "@/utils/http";export function getCategoryAPI(){return httpInstance({url:'home/category/head'})
}
2、修改LayoutHeader部分数据
<script setup>
import { onMounted, ref } from "vue";
// 引入定义的API方法
import {getCategoryAPI} from '@/apis/Layout'
// 定义一个响应式数据
const categoryList = ref([])
// 定义一个方法,访问接口,将获取到的数据赋值给categoryList
const getCategory = async()=>{const res = await getCategoryAPI()categoryList.value = res.result
}
// 挂载时访问接口
onMounted(()=>{getCategory()
})
</script><template><header class='app-header'><div class="container"><h1 class="logo"><RouterLink to="/">小兔鲜</RouterLink></h1><ul class="app-header-nav"><!-- 用v-for渲染页面 --><li class="home" v-for="item in categoryList" :key="item.id"><RouterLink to="/">{{ item.name}}</RouterLink></li></ul><div class="search"><i class="iconfont icon-search"></i><input type="text" placeholder="搜一搜"></div><!-- 头部购物车 --></div></header>
</template>
3、运行结果
四、吸顶导航交互实现
1、实现效果
浏览器再上下滚动的过程中,如果滚动距离顶部大于78px,吸顶导航显示,反之,隐藏
2、建立文件LayoutFixed
里面内容
<script setup></script><template><div class="app-header-sticky show"><div class="container"><RouterLink class="logo" to="/" /><!-- 导航区域 --><ul class="app-header-nav"><li class="home"><RouterLink to="/">首页</RouterLink></li><li><RouterLink to="/">居家</RouterLink></li><li><RouterLink to="/">美食</RouterLink></li><li><RouterLink to="/">服饰</RouterLink></li><li><RouterLink to="/">母婴</RouterLink></li><li><RouterLink to="/">个护</RouterLink></li><li><RouterLink to="/">严选</RouterLink></li><li><RouterLink to="/">数码</RouterLink></li><li><RouterLink to="/">运动</RouterLink></li><li><RouterLink to="/">杂项</RouterLink></li></ul><div class="right"><RouterLink to="/">品牌</RouterLink><RouterLink to="/">专题</RouterLink></div></div></div>
</template><style scoped lang='scss'>
.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;}}
}
</style>
3、vueUse的使用
官网:VueUse 中文网 (nodejs.cn)
1、安装
npm i @vueuse/core
2、使用
// 导入vueuse
import { useScroll } from '@vueuse/core'
// 使用useScroll获取竖向滚动距离,测试为window
const { y } = useScroll(window)
4、修改后的LayoutFixed页面
<script setup>
// 导入vueuse
import { useScroll } from '@vueuse/core'
// 使用useScroll获取竖向滚动距离,测试为window
const { y } = useScroll(window)
</script><template><div class="app-header-sticky" :class="{show : y >78}"><div class="container"><RouterLink class="logo" to="/" /><!-- 导航区域 --><ul class="app-header-nav"><li class="home"><RouterLink to="/">首页</RouterLink></li><li><RouterLink to="/">居家</RouterLink></li><li><RouterLink to="/">美食</RouterLink></li><li><RouterLink to="/">服饰</RouterLink></li><li><RouterLink to="/">母婴</RouterLink></li><li><RouterLink to="/">个护</RouterLink></li><li><RouterLink to="/">严选</RouterLink></li><li><RouterLink to="/">数码</RouterLink></li><li><RouterLink to="/">运动</RouterLink></li><li><RouterLink to="/">杂项</RouterLink></li></ul><div class="right"><RouterLink to="/">品牌</RouterLink><RouterLink to="/">专题</RouterLink></div></div></div>
</template><style scoped lang='scss'>
.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;}}
}
</style>
5、运行成功
五、Pinia优化重复请求
如图可知,导航渲染的内容都是一样的,也就是同一个接口访问了两次
为了优化代码,我想让其只访问一次接口就可以拿到数据
如果是我,我的方法是将拿到的数据保存到本地,然后用到的时候再从本地拿取使用
1、新建文件夹category.js
/*** Pinia优化重复请求*/
// 导入
import { defineStore} from 'pinia'
import { ref } from 'vue'
// 引入定义的API方法
import {getCategoryAPI} from '@/apis/Layout'
export const useCategoryStory = defineStore('category',() => {
// 定义一个响应式数据categoryList
const categoryList = ref([])
// 访问接口,获取数据
const getCategory = async() => {const res = await getCategoryAPI()categoryList.value = res.result
}
return{categoryList,getCategory
}
})
2、在Layout文件夹下的index.vue修改
<script setup>
import LayoutNav from './componments/LayoutNav.vue'
import LayoutHeader from './componments/LayoutHeader.vue'
import LayoutFooter from './componments/LayoutFooter.vue'
import LayoutFixed from './componments/LayoutFixed.vue'
// 触发获取导航列表的action
import {useCategoryStory} from '@/stores/category'
import { onMounted } from 'vue'
// 创建实例函数
const category = useCategoryStory()
// 在挂载时调用访问API的方法,给categoryList赋值
onMounted(()=>category.getCategory())
</script><template><div><div class="a"></div><LayoutFixed /><LayoutNav /><LayoutHeader /><RouterView /><LayoutFooter /></div>
</template>
<style scoped>
.a{height: 400px;
}
</style>
3、修改LayoutHeader的js部分
<script setup>
import { onMounted, ref } from "vue";
// 引入定义的API方法
import {getCategoryAPI} from '@/apis/Layout'
import {useCategoryStory} from '@/stores/category'
const category = useCategoryStory()
</script>html部分改为如下<!-- 用v-for渲染页面 --><li class="home" v-for="item in category.categoryList" :key="item.id"><RouterLink to="/">{{ item.name}}</RouterLink></li>
4、LayoutFixed和LayoutHeader做同样的修改
5、运行结果
六、遇到的问题
1、引入源码后,页面的样式排版和视频中不一样
1、原因前面
忘记引入common.scss
2、新建文件,如下
3、文件代码
// 重置样式
* {box-sizing: border-box;}html {height: 100%;font-size: 14px;}body {height: 100%;color: #333;min-width: 1240px;font: 1em/1.4 'Microsoft Yahei', 'PingFang SC', 'Avenir', 'Segoe UI','Hiragino Sans GB', 'STHeiti', 'Microsoft Sans Serif', 'WenQuanYi Micro Hei',sans-serif;}body,ul,h1,h3,h4,p,dl,dd {padding: 0;margin: 0;}a {text-decoration: none;color: #333;outline: none;}i {font-style: normal;}input[type='text'],input[type='search'],input[type='password'],input[type='checkbox'] {padding: 0;outline: none;border: none;-webkit-appearance: none;&::placeholder {color: #ccc;}}img {max-width: 100%;max-height: 100%;vertical-align: middle;background: #ebebeb url('@/assets/images/200.png') no-repeat center / contain;}ul {list-style: none;}#app {background: white;user-select: none;}.container {width: 1240px;margin: 0 auto;position: relative;}.ellipsis {white-space: nowrap;text-overflow: ellipsis;overflow: hidden;}.ellipsis-2 {word-break: break-all;text-overflow: ellipsis;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 2;overflow: hidden;}.fl {float: left;}.fr {float: right;}.clearfix:after {content: '.';display: block;visibility: hidden;height: 0;line-height: 0;clear: both;}// reset element.el-breadcrumb__inner.is-link {font-weight: 400 !important;}
4、在main.js中引入
import '@/styles/common.scss'
2、给Home设置高度让其滚动时,发现上面的Nav和Header没有在页面上显示
具体原因,我也没有搞清楚,但是如下修改index.vue页面代码,就可以解决
<script setup>
import LayoutNav from './componments/LayoutNav.vue'
import LayoutHeader from './componments/LayoutHeader.vue'
import LayoutFooter from './componments/LayoutFooter.vue'
import LayoutFixed from './componments/LayoutFixed.vue'
</script><template><div><div class="a"></div><LayoutFixed /><LayoutNav /><LayoutHeader /><RouterView /><LayoutFooter /></div>
</template>
<style scoped>
.a{height: 400px;
}
</style>
运行截图