仿京东分类栏组件
程序员文章站
2024-03-20 21:13:52
...
京东效果展示
功能描述:
1.底部进度条跟随左滑变化
2.可以规定单行展示个数,以及单行总个数
代码
1.index.vue 入口组件
<template>
<div class="container">
<div class="title">nav-show</div>
<!-- column-num 一行多少个 row-show 视口展示几个 -->
<nav-show :column-num="8" :row-show="3">
<nav-show-item v-for="item in list">
<div class="show_box">
<img :src="item.img" alt="" />
<div>{{ item.name }}</div>
</div>
</nav-show-item>
</nav-show>
</div>
</template>
<script>
import navShow from "./navShow.vue";
import navShowItem from "./navShowItem.vue";
export default {
components: {
navShow,
navShowItem,
},
data() {
return {
msg: "nav",
img: require("./girl.jpg"),
list: [
{
img: require("./girl.jpg"),
name: "看我1",
},
{
img: require("./girl.jpg"),
name: "看我2",
},
{
img: require("./girl.jpg"),
name: "看我3",
},
{
img: require("./girl.jpg"),
name: "看我4",
},
{
img: require("./girl.jpg"),
name: "看我5",
},
{
img: require("./girl.jpg"),
name: "看我6",
},
{
img: require("./girl.jpg"),
name: "看我7",
},
{
img: require("./girl.jpg"),
name: "看我8",
},
{
img: require("./girl.jpg"),
name: "看我9",
},
{
img: require("./girl.jpg"),
name: "看我10",
},
],
};
},
};
</script>
<style lang="less" scoped>
.container {
width: 100%;
height: 100vh;
padding-top: 50px;
.title {
text-align: center;
}
.show_box {
margin: auto;
width: 100%;
background: azure;
img {
width: 100%;
height: 50px;
}
div {
height: 50px;
line-height: 50px;
font-size: 16px;
color: aqua;
}
}
}
</style>
- NavShow.vue父容器组件
<template>
<!-- 最外层父容器 -->
<div class="nav_show">
<!-- :style="{ color: activeColor, fontSize: fontSize + 'px' }" -->
<!-- 栅格展示容器 -->
<div class="nav_show_top" ref="show_box" @scroll="move">
<!-- 背景容器 实际单行盛满的容器 -->
<div class="bg_box" ref="bg_box" :style="{ width: bgWidth + '%' }">
<!-- 使用者自定义单个子容器 -->
<slot></slot>
</div>
</div>
<!-- 进度条 -->
<div class="progress_bar" ref="bar">
<!-- 可移动浮标 -->
<div
class="buoy"
ref="buoy"
:style="{ left: buoyPer + 'px' }"
></div>
</div>
</div>
</template>
<script>
export default {
name: "navShow",
props: {
// 单行展示列数
columnNum: {
type: Number,
default: 5,
},
// 可视区内单行展示个数
rowShow: {
type: Number,
default: 5,
},
},
data() {
return {
itemWidth: "", //单个子组件宽度
scrollLeft: "", //滚动条向左滚动距离
buoyPer: "", //浮标可移动百分比
};
},
computed: {
// 按照 单行展示列数 计算单行宽度
bgWidth() {
let per = (100 / this.rowShow) * this.columnNum;
console.log("bg:" + per);
return per;
},
},
methods: {
// 滚动条事件
move(e) {
// 获取滚动距离
this.scrollLeft = e.target.scrollLeft;
// 公式:滚动条移动距离/滚动条可移动总长度 = 浮标移动距离/浮标可移动总长度
// 视图部分
let bgWidth = this.$refs.bg_box.offsetWidth; //实际背景宽度
let showWidth = this.$refs.show_box.offsetWidth; //展示窗口宽度
let moveWidth = e.target.scrollLeft; //移动距离
let moveMax = bgWidth - showWidth; //可移动宽度
// 浮标部分
this.movePer = moveWidth / moveMax; //滚动条移动比例
let barWidth = this.$refs.bar.offsetWidth; //进度条长度
let buoyWidth = this.$refs.buoy.offsetWidth; //浮标宽度
let buoyMax = barWidth - buoyWidth; //浮标可移动总长度
this.buoyPer = buoyMax * this.movePer; //浮标移动的距离
},
},
created() {
this.itemWidth = 100 / this.columnNum; // 计算单个子容器的宽度
},
mounted() {
console.log(this.$refs);
},
};
</script>
<style lang="less" scoped>
.nav_show {
position: relative;
padding-bottom: 20px;
// border: 1px dashed lightcoral;
width: 100%;
.nav_show_top::-webkit-scrollbar {
width: 0 !important;
}
.nav_show_top {
width: 100%;
overflow: scroll;
.bg_box {
display: flex;
flex-wrap: wrap;
height: 100%;
}
}
.progress_bar {
position: absolute;
width: 50%;
height: 5px;
background: #c3c3c3;
border-radius: 3%;
left: 50%;
bottom: 15px;
transform: translateX(-50%);
.buoy {
position: absolute;
width: 50%;
height: 100%;
background: lightblue;
border-radius: 3%;
}
}
}
</style>
3.子容器组件NavShowItem.vue
<template>
<div class="nav_show_item" :style="{ width: itemWidth + '%' }">
<!-- 使用者的每一个样式 -->
<slot></slot>
</div>
</template>
<script>
export default {
data() {
return {
itemWidth: "", //每一个子盒子的宽度
};
},
mounted() {
// 从父容器里面data中获取计算后的宽度
this.itemWidth = this.$parent.itemWidth; //从父容器获得子容器宽度
},
};
</script>
拓展功能
这两个拓展小编没有添加,难度不大,可根据业务添加
1.底部进度条可配置 显示/隐藏
2.进度条宽度、浮标宽度可配置
上一篇: vue+node实现前后端分离
下一篇: 仿淘宝固定侧边栏
推荐阅读