赞
踩
先上总代码:
子组件:
<!-- LeftSidebar.vue --> <template> <div class="left-sidebar"> <a v-for="(item, index) in sidebarItems" :key="index" @click="scrollToAnchor(item.anchor)"> <!-- 竖线 --> <div :class="isSelected(item.anchor) ? 'activeLine' : 'line'" /> <!-- 图标 --> <img :src="isSelected(item.anchor) ? item.activeIcon : item.icon" :alt="item.label"> <span>{{ item.label }}</span> </a> </div> </template> <script> export default { name: 'LeftSidebar', props: ['selectedAnchor'], data() { return { sidebarItems: [ { anchor: 'sidebar1', icon: require('@/assets/image/main/sidebarIcon/sidebar1.png'), activeIcon: require('@/assets/image/main/sidebarIcon/sidebarActive1.png'), label: '菜单1' }, { anchor: 'sidebar2', icon: require('@/assets/image/main/sidebarIcon/sidebar2.png'), activeIcon: require('@/assets/image/main/sidebarIcon/sidebarActive2.png'), label: '菜单2' }, { anchor: 'sidebar3', icon: require('@/assets/image/main/sidebarIcon/sidebar3.png'), activeIcon: require('@/assets/image/main/sidebarIcon/sidebarActive3.png'), label: '菜单3' }, { anchor: 'sidebar4', icon: require('@/assets/image/main/sidebarIcon/sidebar4.png'), activeIcon: require('@/assets/image/main/sidebarIcon/sidebarActive4.png'), label: '菜单4 ' } } }, methods: { scrollToAnchor(anchor) { // 通过方法通知父组件修改 selectedAnchor this.$emit('scroll-to-anchor', anchor); }, isSelected(anchor) { // 检查当前项是否被选中 return this.selectedAnchor === anchor; }, } } </script> <style lang="scss" scoped> //根据自己需要编写样式 .left-sidebar { z-index: 999; position: fixed; left: 0; top: 50%; transform: translateY(-50%); height: 450px; width: 153px; padding: 20px 30px 20px 20px; gap: 10px; border-radius: 0 20px 20px 0; border: 1px solid var(--systNaNpx-text-icon-color-text-light-solid, #FFF); background: linear-gradient(180deg, #f0f2f6d9 0%, #fffeffd9 100%); box-shadow: 0 0 20px 0 #0000001a; display: flex; flex-direction: column; align-items: center; justify-content: center; a { width: 102px; display: flex; justify-content: flex-start; align-items: center; flex: 1; text-align: left; white-space: nowrap; // 防止文字换行 .line { width: 1px; height: 60px; background: linear-gradient(180deg, #d9d9d900 0%, #D9D9D9 55.21%, #d9d9d900 100%); } .activeLine { width: 1px; height: 60px; background: linear-gradient(180deg, #1a76ff00 0%, #0D6EFF 55.21%, #2c80ff00 100%); } span { color: #131f31; font-family: "PingFang SC"; font-size: 14px; font-style: normal; font-weight: 600; line-height: 24px; margin-left: 4px; } } } img { width: 26px; height: 26px; margin-left: 12px; } </style>
父组件:
<!-- index.vue --> <template> <div class="sidebar" ref="sidebar1"></div> <div class="sidebar" ref="sidebar2"></div> <div class="sidebar" ref="sidebar3"></div> <div class="sidebar" ref="sidebar4"></div> <LeftSidebar :selectedAnchor="selectedAnchor" @scroll-to-anchor="scrollToAnchor" /> </template> <script> import LeftSidebar from '@/components/homeCops/sidebar/LeftSidebar .vue' export default { components: { LeftSidebar }, data () { return { selectedAnchor:'sidebar1'//默认高亮显示第一个 } }, mounted() { //经测试不同电脑监听使用的可能不成功,这里可以自行选择一个监听 //监听当滚动条发生变化时调用handleScroll设置selectedAnchor的值并传给子组件 window.addEventListener('scroll', this.handleScroll, true) window.addEventListener('onscroll', this.handleScroll, true) window.addEventListener('scroll', this.handleScroll.bind(this), true) this.$el.addEventListener('scroll', this.handleScroll.bind(this)) }, methods: { scrollToAnchor(anchor) { // 获取对应锚点的DOM元素 const targetElement = this.$refs[`${anchor}`].$el // 如果找到目标元素,则执行滚动 if (targetElement) { // smooth不生效 targetElement.scrollIntoView({ behavior: 'auto' }) } }, handleScroll() { // 获取所有需要需要锚点定位的DOM元素 const navContents = document.querySelectorAll('.sidebar') const offsetTopArr = [] navContents.forEach(item => { // 获取上面DOM元素距离顶部的距离 offsetTopArr.push(item.offsetTop) }) // 获取页面滚动了距离 const scrollTop = document.getElementById('app').scrollTop let navIndex = 0//需要高亮显示的元素 for (let n = 0; n < offsetTopArr.length; n++) { if (scrollTop >= offsetTopArr[n]) { navIndex = n } } // 设置高亮显示 this.selectedAnchor = `sidebar${navIndex + 1}`; } } } </script>
解析:
①首先让元素默认选中第一个,在父组件中设置一个字段表示选中第几个
data () {
return {
selectedAnchor:'sidebar1'
}
},
②将该值传递给子组件
:selectedAnchor="selectedAnchor"
③在子组件中接收并使用
<div :class="isSelected(item.anchor) ? 'activeLine' : 'line'" />
props: ['selectedAnchor'],
isSelected(anchor) {
// 检查当前项是否被选中
return this.selectedAnchor === anchor;
},
④在父组件编写功能代码
mounted() { //经测试不同电脑监听使用的可能不成功,这里可以自行选择一个监听 window.addEventListener('scroll', this.handleScroll, true) window.addEventListener('onscroll', this.handleScroll, true) window.addEventListener('scroll', this.handleScroll.bind(this), true) this.$el.addEventListener('scroll', this.handleScroll.bind(this)) }, methods: { handleScroll() { // 获取所有需要需要锚点定位的DOM元素 const navContents = document.querySelectorAll('.sidebar') const offsetTopArr = [] navContents.forEach(item => { // 获取上面DOM元素距离顶部的距离 offsetTopArr.push(item.offsetTop) }) // 获取页面滚动了距离 const scrollTop = document.getElementById('app').scrollTop let navIndex = 0//需要高亮显示的元素 for (let n = 0; n < offsetTopArr.length; n++) { if (scrollTop >= offsetTopArr[n]) { navIndex = n } } // 设置高亮显示 this.selectedAnchor = `sidebar${navIndex + 1}`; } }
到此为止以上代码实现了滚动自动选择菜单的功能
①在子组件中添加点击事件,通过$emit将参数传给父组件
@click="scrollToAnchor(item.anchor)"
scrollToAnchor(anchor) {
// 通过方法通知父组件
this.$emit('scroll-to-anchor', anchor);
},
②在父组件中接收子组件传递的参数,并使用scrollIntoView实现锚点功能
@scroll-to-anchor="scrollToAnchor"
scrollToAnchor(anchor) {
// 获取对应锚点的DOM元素
const targetElement = this.$refs[`${anchor}`].$el
// 如果找到目标元素,则执行滚动
if (targetElement) {
// smooth不生效
targetElement.scrollIntoView({ behavior: 'auto' })
}
},
以上两个功能代码要结合使用,如果只使用点击功能则需要在父组件中修改selectedAnchor 的值。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。