vue 纵向滚动菜单, 点击滚动到选中菜单

1 背景

需要设计一个纵向滚动菜单,要求丝滑点,默认显示选中菜单

2 思路

  • 给定一个容器,样式包含overflow:hidden,默认高宽足够显示一个菜单(以下用图标代替菜单),鼠标悬浮时增大容器高度,显示更多图标
  • 设置两个div用于触发上下滚动(本意直接用每页第一和最后图标进行触发,但是这样会导致鼠标悬停时直接滚动,体验不好)
  • 鼠标点击时将点击图标滚动到当前页的第一个图标,鼠标没有点击,移出后菜单还原

3 实现

javascript 复制代码
<template>
  <div class="container" @mouseleave="handleMouseLeave">
    <div
      class="action up"
      v-if="scrollTop !== -1 * (totalHeight - pageHeight)"
      @mouseover="handleMouseOver('up')"
    ></div>
    <ul :style="{ transform: `translateY(${scrollTop}px)` }">
      <li
        v-for="(item, index) in imgs"
        :key="index"
        :style="{ padding: itemPadding + 'px' }"
      >
        <img
          :src="item"
          alt=""
          :style="{ width: iconSize[0] + 'px', height: iconSize[1] + 'px' }"
          @click="handleClick(index)"
        />
      </li>
    </ul>
    <div
      class="action dowm"
      v-if="scrollTop !== 0"
      @mouseover="handleMouseOver('down')"
    ></div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from "vue";

const props = defineProps({
  iconSize: {
    type: Array,
    default: () => [60, 60],
  },
  pageSize: {
    type: Number,
    default: 6,
  },
  itemPadding: {
    type: Number,
    default: 20,
  },
});
const list = [
  "vue.svg",
  "back.svg",
  "behance.svg",
  "down.svg",
  "hands.svg",
  "hdd.svg",
  "next.svg", //
  "one.svg",
  "snow.svg",
  "three.svg",
  "up.svg",
  "upload.svg",
  "vip.svg", //
  "dvi.svg",
  "bone.svg",
  "bird.svg",
  "ipad.svg",
  "duck.svg",
  "deer.svg", //
  "fish.svg",
  "clap.svg",
  "eagle.svg",
];
const imgs = ref(
  list.map((item) => new URL(`./assets/${item}`, import.meta.url).href)
);

const scrollTop = ref(0);
const baseIndex = ref(0);

const actionHeight = computed(() => {
  return props.itemPadding+ "px";
});

const itemHeight = computed(() => {
  return props.iconSize[1] + 2 * props.itemPadding;
});
const containerBaseSize = computed(() => {
  return itemHeight.value + "px";
});
const containerHeight = computed(() => {
  return itemHeight.value * props.pageSize + "px";
});
const pageHeight = computed(() => {
  return props.pageSize * itemHeight.value;
});
const totalHeight = computed(() => {
  return imgs.value.length * itemHeight.value;
});

const handleMouseOver = async (direction: string) => {
  if (direction === "up") {
    if (
      scrollTop.value + (totalHeight.value - pageHeight.value) >
      pageHeight.value
    ) {
      scrollTop.value += -1 * pageHeight.value;
    } else {
      scrollTop.value = -1 * (totalHeight.value - pageHeight.value);
    }
  } else {
    if (scrollTop.value + pageHeight.value >= 0) {
      scrollTop.value = 0;
    } else {
      scrollTop.value += pageHeight.value;
    }
  }
};

const handleClick = (index: number) => {
  scrollTop.value = -1 * index * itemHeight.value;
  baseIndex.value = index;
};
const handleMouseLeave = () => {
  handleClick(baseIndex.value);
};
</script>

<style scoped lang="scss">
.container {
  overflow: hidden;
  transition: all 0.5s;
  position: relative;
  width: v-bind(containerBaseSize);
  height: v-bind(containerBaseSize);
  &:hover {
    height: v-bind(containerHeight);
  }
  .action {
    cursor: pointer;
    position: absolute;
    width: 100%;
    height: v-bind(actionHeight);
    z-index: 10;
    &.up {
      top: 0;
    }
    &.dowm {
      bottom: 0;
    }
  }
  ul {
    box-sizing: content-box;
    margin: 0;
    padding: 0;
    height: 100%;
    transition: all ease-in-out 1s;
    list-style: none;
    li {
      line-height: 0;
      position: relative;

      img {
        cursor: pointer;
        transition: all 0.5s;
        &:hover {
          scale: 1.3;
        }
      }
    }
  }
}
</style>
相关推荐
神奇的程序员4 小时前
开发了一个管理本地开发环境的软件
前端·flutter
天若有情6734 小时前
程序员原创|借鉴JS事件冒泡,根治电脑文件混乱的“冒泡整理法”
开发语言·javascript·windows·ecmascript·电脑·办公·日常
XiYang-DING4 小时前
HTML 核心标签
前端·html
Csvn5 小时前
技术选型方法论
前端
Csvn5 小时前
前端架构演进:从页面到平台的十年变革
前端
李伟_Li慢慢5 小时前
ShaderToy-山峦+蓝天+白云
前端·webgl
小码哥_常5 小时前
Android字体字重设置全攻略:XML黑科技+Kotlin动态实现,告别.ttf臃肿
前端
FYKJ_20105 小时前
springboot校园兼职平台--附源码02041
java·javascript·spring boot·python·eclipse·django·php
言萧凡_CookieBoty7 小时前
AI 编程省 Token 实战:从 Spec、上下文工程到模型分层的降本策略
前端·ai编程
DFT计算杂谈7 小时前
wannier90 参数详解大全
java·前端·css·html·css3