03-顶级类目-批量注册组件
目的: 自动的批量注册组件。
大致步骤:
- 使用
require
提供的函数context
加载某一个目录下的所有.vue
后缀的文件。 - 然后
context
函数会返回一个导入函数importFn
- 它又一个属性
keys()
获取所有的文件路径
- 它又一个属性
- 通过文件路径数组,通过遍历数组,再使用
importFn
根据路径导入组件对象 - 遍历的同时进行全局注册即可
落的代码:
src/components/library/index.js
// 其实就是vue插件,扩展vue功能,全局组件、指令、函数 (vue.30取消过滤器)
// 当你在mian.js导入,使用Vue.use() (vue3.0 app)的时候就会执行install函数
// import XtxSkeleton from './xtx-skeleton.vue'
// import XtxCarousel from './xtx-carousel.vue'
// import XtxMore from './xtx-more.vue'
// import XtxBread from './xtx-bread.vue'
// import XtxBreadItem from './xtx-bread-item.vue'
// 导入library文件夹下的所有组件
// 批量导入需要使用一个函数 require.context(dir,deep,matching)
// 参数:1. 目录 2. 是否加载子目录 3. 加载的正则匹配
const importFn = require.context('./', false, /\.vue$/)
// console.dir(importFn.keys()) 文件名称数组
export default {
install (app) {
// app.component(XtxSkeleton.name, XtxSkeleton)
// app.component(XtxCarousel.name, XtxCarousel)
// app.component(XtxMore.name, XtxMore)
// app.component(XtxBread.name, XtxBread)
// app.component(XtxBreadItem.name, XtxBreadItem)
// 批量注册全局组件
importFn.keys().forEach(key => {
// 导入组件
const component = importFn(key).default
// 注册组件
app.component(component.name, component)
})
// 定义指令
defineDirective(app)
}
}
const defineDirective = (app) => {
// 图片懒加载指令 v-lazyload
app.directive('lazyload', {
// vue2.0 inserted函数,元素渲染后
// vue3.0 mounted函数,元素渲染后
mounted (el, binding) {
// 元素插入后才能获取到dom元素,才能使用 intersectionobserve进行监听进入可视区
// el 是图片元素 binding.value 图片地址
const observe = new IntersectionObserver(([{ isIntersecting }]) => {
if (isIntersecting) {
el.src = binding.value
// 取消观察
observe.unobserve(el)
}
}, {
threshold: 0.01
})
// 进行观察
observe.observe(el)
}
})
}
总结,知识点:
- require.context() 是webpack提供的一个自动导入的API
- 参数1:加载的文件目录
- 参数2:是否加载子目录
- 参数3:正则,匹配文件
- 返回值:导入函数 fn
- keys() 获取读取到的所有文件列表
04-顶级类目-基础布局搭建。
目的: 完成顶级分类的,面包屑+轮播图+所属全部子级分类展示。
大致步骤:
- 准备基础结构,获取轮播图数据给组件使用
- 获取面包屑和所有分类数据给子级分类展示使用
落的代码:
- 基本结构和轮播图渲染
src/views/category/index.vue
<template>
<div class="top-category">
<div class="container">
<!-- 面包屑 -->
<XtxBread>
<XtxBreadItem to="/">首页</XtxBreadItem>
<XtxBreadItem>空调</XtxBreadItem>
</XtxBread>
<!-- 轮播图 -->
<XtxCarousel :sliders="sliders" style="height:500px" />
<!-- 所有二级分类 -->
<div class="sub-list">
<h3>全部分类</h3>
<ul>
<li v-for="i in 8" :key="i">
<a href="javascript:;">
<img src="http://zhoushugang.gitee.io/erabbit-client-pc-static/uploads/img/category%20(9).png" >
<p>空调</p>
</a>
</li>
</ul>
</div>
<!-- 不同分类商品 -->
</div>
</div>
</template>
<script>
import { findBanner } from '@/api/home'
export default {
name: 'TopCategory',
setup () {
// 轮播图
const sliders = ref([])
findBanner().then(data => {
sliders.value = data.result
})
return { sliders }
}
}
</script>
<style scoped lang="less">
.top-category {
h3 {
font-size: 28px;
color: #666;
font-weight: normal;
text-align: center;
line-height: 100px;
}
.sub-list {
margin-top: 20px;
background-color: #fff;
ul {
display: flex;
padding: 0 32px;
flex-wrap: wrap;
li {
width: 168px;
height: 160px;
a {
text-align: center;
display: block;
font-size: 16px;
img {
width: 100px;
height: 100px;
}
p {
line-height: 40px;
}
&:hover {
color: @xtxColor;
}
}
}
}
}
}
</style>
- 从vuex获取分类数据,进行渲染。
import { useStore } from 'vuex'
import { useRoute } from 'vue-router'
import { computed, ref } from 'vue'
// 面包屑+所有分类
const store = useStore()
const route = useRoute()
const topCategory = computed(() => {
let cate = {}
const item = store.state.category.list.find(item => {
return item.id === route.params.id
})
if (item) cate = item
return cate
})
return {
sliders,
topCategory,
}
<template>
<div class="top-category">
<div class="container">
<!-- 面包屑 -->
<XtxBread>
<XtxBreadItem to="/">首页</XtxBreadItem>
<XtxBreadItem>{{topCategory.name}}</XtxBreadItem>
</XtxBread>
<!-- 轮播图 -->
<XtxCarousel :sliders="sliders" style="height:500px" />
<!-- 所有二级分类 -->
<div class="sub-list">
<h3>全部分类</h3>
<ul>
<li v-for="item in topCategory.children" :key="item.id">
<a href="javascript:;">
<img :src="item.picture" >
<p>{{item.name}}</p>
</a>
</li>
</ul>
</div>
<!-- 不同分类商品 -->
</div>
</div>
</template>
05-顶级类目-分类商品-布局
目的: 展示各个子级分类下推荐的商品基础布局
大致步骤:
- 准备单个商品组件
- 完成推荐商品区块布局
落的代码:
- 商品信息组件
src/views/category/components/goods-item.vue
<template>
<RouterLink to="/" class='goods-item'>
<img src="http://zhoushugang.gitee.io/erabbit-client-pc-static/uploads/fresh_goods_2.jpg" alt="">
<p class="name ellipsis">红功夫 麻辣小龙虾 19.99/500g 实惠到家</p>
<p class="desc ellipsis">火锅食材</p>
<p class="price">¥19.99</p>
</RouterLink>
</template>
<script>
export default {
name: 'GoodsItem'
}
</script>
<style scoped lang='less'>
.goods-item {
display: block;
width: 220px;
padding: 20px 30px;
text-align: center;
.hoverShadow();
img {
width: 160px;
height: 160px;
}
p {
padding-top: 10px;
}
.name {
font-size: 16px;
}
.desc {
color: #999;
height: 29px;
}
.price {
color: @priceColor;
font-size: 20px;
}
}
</style>
- 顶级分类组件,进行布局
src/views/category/index.vue
+import GoodsItem from './components/goods-item'
export default {
name: 'TopCategory',
components: {
+ GoodsItem
},
<!-- 分类关联商品 -->
<div class="ref-goods">
<div class="head">
<h3>- 海鲜 -</h3>
<p class="tag">温暖柔软,品质之选</p>
<XtxMore />
</div>
<div class="body">
<GoodsItem v-for="i in 5" :key="i" />
</div>
</div>
.ref-goods {
background-color: #fff;
margin-top: 20px;
position: relative;
.head {
.xtx-more {
position: absolute;
top: 20px;
right: 20px;
}
.tag {
text-align: center;
color: #999;
font-size: 20px;
position: relative;
top: -20px;
}
}
.body {
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
padding: 0 65px 30px;
}
}