赞
踩
网上最全的让人看了头疼的这个,可以参考:
效果展示:
重点代码:
确定滚动的位置:
// 上下左右键,影响滚动到特定位置 scrollTo() { let { current_index } = this.n; // 滚动的节点 let cnode = this.$el.querySelector('.penguins'); let child = cnode.children[0]; // 进度条向上/下滚动间距:一个桌面的块高+20px上间距 let childMargin = ~~getComputedStyle(child).marginTop.replace('px', ''); let spaceHeight = child.offsetHeight + childMargin; let current = cnode.scrollTop; let endHeight = cnode.scrollHeight - cnode.offsetHeight; let target; /** * current_index:目标位置的索引 * 因为最后两行在可视区域内,此时进度条需滚至最末,不会再滚动 * 倒数第三行-->倒数第二行,进度条滚至最末, * 倒数第二行-->倒数第一行,进度条仍在最末 */ let isPenultimateLine = Math.floor((this.n.dataList.length - 1) / 3) - Math.floor(current_index / 3); console.log('isPenultimateLine:' + isPenultimateLine); if (isPenultimateLine <= 1) { target = endHeight; } else { target = Math.floor(current_index / 3) * spaceHeight; } // 若还未滚至末尾,则从滚动条当前位置current滚动到target目标位置,动画滚动 this.animateTo(cnode, current, target); },
滚动动画:
animateTo(node, current, target) { console.log(current + '------' + target); /** * 当前位置等于目标位置则不滚动, * 比如当前在最后一行,按↑ 上键至倒数第二行,应不滚动 * 或当前在倒数第二行,按↓ 下键至最后一行,应不滚动 */ if (current === target) return; clearInterval(node.timer); let step = (target - current) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); node.timer = setInterval(() => { node.scrollTop = node.scrollTop + step; if (Math.abs(target - node.scrollTop) < Math.abs(step)) { node.scrollTop = target; clearInterval(node.timer); } }, 15); }
详细代码,复制即可运行
企鹅图片,自行下载:
// App.vue <template> <div class="app"> <PenguinList /> </div> </template> <script> // 在Vue的组件入口中,引入写的组件,具体位置具体引入 import PenguinList from '@/components/PenguinList'; export default { name: 'app', components: { PenguinList } }; </script> <style lang="less"> html, body { margin: 0; padding: 0; height: 100%; width: 100%; } .app { width: 100%; height: 100%; background-image: radial-gradient(#233c90, #121d38) !important; color: #fff !important; } </style>
PenguinList企鹅列表组件:
// PenguinList.vue <template> <div class="penguin-list"> <div class="penguins transparent-right-scroll"> <div v-for="(item, index) in n.dataList" :key="'penguin' + index" :class="[n.current_index === index ? 'penguin-focus' : '', (index + 1) % 3 !== 0 ? 'block-mr' : '']" :penguin-id="index + 1" > <div class="left-img"> <img src="@/assets/imgs/penguin.jpg" alt="" /> <span>小芒果</span> </div> <div class="right-desc"> <span class="title">{{ item.name }}</span> <div class="desc">{{ item.desc }}</div> </div> </div> </div> </div> </template> <script> export default { name: 'PenguinList', data() { return { n: { current_index: 0, dataList: [] } }; }, mounted() { this.onLoad(); this.listenHotKeys(); }, methods: { onLoad() { let data = []; for (let i = 0; i < 10; i++) { data.push({ id: 1, name: '企鹅' + i, desc: '真可爱' }); } this.n.dataList = data; }, listenHotKeys() { // 监听快捷键 window.onkeyup = (e) => { let { current_index } = this.n; // ← 左 if (e.keyCode === 37) { if (current_index > 0) { this.$set(this.n, 'current_index', current_index - 1); this.scrollTo(); console.log('← 左'); } } // ↑ 上 if (e.keyCode === 38) { if (current_index >= 3) { this.$set(this.n, 'current_index', current_index - 3); this.scrollTo(); console.log('↑ 上'); } } // → 右 if (e.keyCode === 39) { if (current_index < this.n.dataList.length - 1) { this.$set(this.n, 'current_index', current_index + 1); this.scrollTo(); console.log('→ 右'); } } // ↓ 下 if (e.keyCode === 40) { if (this.n.dataList.length - current_index > 3) { this.$set(this.n, 'current_index', current_index + 3); console.log(this.n.current_index); this.scrollTo(); console.log('↓ 下'); } } }; }, // 上下左右键,影响滚动到特定位置 scrollTo() { let { current_index } = this.n; // 滚动的节点 let cnode = this.$el.querySelector('.penguins'); let child = cnode.children[0]; // 进度条向上/下滚动间距:一个桌面的块高+20px上间距 let childMargin = ~~getComputedStyle(child).marginTop.replace('px', ''); let spaceHeight = child.offsetHeight + childMargin; let current = cnode.scrollTop; let endHeight = cnode.scrollHeight - cnode.offsetHeight; let target; /** * current_index:目标位置的索引 * 因为最后两行在可视区域内,此时进度条需滚至最末,不会再滚动 * 倒数第三行-->倒数第二行,进度条滚至最末, * 倒数第二行-->倒数第一行,进度条仍在最末 */ let isPenultimateLine = Math.floor((this.n.dataList.length - 1) / 3) - Math.floor(current_index / 3); console.log('isPenultimateLine:' + isPenultimateLine); if (isPenultimateLine <= 1) { target = endHeight; } else { target = Math.floor(current_index / 3) * spaceHeight; } // 若还未滚至末尾,则从滚动条当前位置current滚动到target目标位置,动画滚动 this.animateTo(cnode, current, target); }, animateTo(node, current, target) { console.log(current + '------' + target); /** * 当前位置等于目标位置则不滚动, * 比如当前在最后一行,按↑ 上键至倒数第二行,应不滚动 * 或当前在倒数第二行,按↓ 下键至最后一行,应不滚动 */ if (current === target) return; clearInterval(node.timer); let step = (target - current) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); node.timer = setInterval(() => { node.scrollTop = node.scrollTop + step; if (Math.abs(target - node.scrollTop) < Math.abs(step)) { node.scrollTop = target; clearInterval(node.timer); } }, 15); } }, beforeDestroy() { // 取消监听该页面特定的键盘事件 window.onkeyup = () => {}; } }; </script> <style lang="less" scoped> .penguin-list { width: 80%; margin: 0 auto; height: 350px; padding-top: 50px; .penguins { height: 300px; width: 100%; overflow-y: scroll; display: flex; align-content: flex-start; flex-wrap: wrap; background-color: rgb(183, 246, 207); & > div { width: 32%; margin-top: 20px; padding: 38px 20px 20px 34px; cursor: pointer; background-color: rgb(238, 210, 184); color: #000; border-radius: 3px; .left-img { width: 60px; float: left; position: relative; & > span { position: absolute; top: -18px; left: -14px; margin-left: 3px; padding: 0 4px; border-radius: 3px; font-size: 12px; border: 1px solid #17be69; color: #17be69; background-color: #aafdd2; } img { width: 100%; } } .right-desc { float: right; width: calc(100% - 60px); padding: 5px 0 0 10px; .title { width: 100%; font-weight: bold; font-size: 20px; } .desc { color: #666; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } } } .penguin-focus { box-shadow: 0 5px 10px 5px rgba(110, 110, 110, 0.4); background-color: #949da7; } .block-mr { margin-right: 2% !important; } } } /** * 透明滚动条 */ .transparent-right-scroll { /* 滚动条整体样式 */ &::-webkit-scrollbar { width: 0; } } </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。