【问题标题】:Horizontal Scroll Using Buttons in VueJS在 VueJS 中使用按钮进行水平滚动
【发布时间】:2018-12-15 17:59:46
【问题描述】:

我希望使用 VueJS 中的按钮实现水平滚动。我有一个容器,其中有几个水平堆叠的 div,我想使用按钮滚动它们。

Here 是 JQuery 的 SO 上的相同线程。 This demo 是 JQuery 中的解决方案。它应该能说明我所追求的效果。

如何使用 VueJS 实现这种效果?

我已经看过的一些库包括 vue-scroll-tojump

  • Vue-scroll-to 要求用户指定要滚动到的元素,而我想在特定元素内水平滚动一定数量的像素。

  • Jump 允许滚动定义数量的像素,但只能在垂直方向工作,并且似乎只能在窗口上滚动。

编辑:我在 VanillaJS 中找到了一个小库:https://github.com/tarun-dugar/easy-scroll

【问题讨论】:

  • 我知道你想要 2 个按钮。向左滚动和向右滚动?
  • @roliroli 是的,没错。理想情况下,单击右侧按钮并将该元素向右滚动一定数量的像素,当单击左侧按钮时,该元素将向左滚动。
  • 好的,我要创建一个沙盒示例,等等

标签: javascript html css vue.js scroll


【解决方案1】:

您只能使用 JavaScript,使用您提供的示例,我仅将其转换为 JavaScript,这是它的 Codepen。

https://codepen.io/immad-hamid/pen/yEmayr

这是可以替换您发送的示例的 JavaScript。

const rightBtn = document.querySelector('#right-button');
const leftBtn = document.querySelector('#left-button');
const content = document.querySelector('#content');

rightBtn.addEventListener("click", function(event) {
  content.scrollLeft += 300;
  event.preventDefault();
});

leftBtn.addEventListener("click", function(event) {
  content.scrollLeft -= 300;
  event.preventDefault();
});

对于动画,你必须使用一些东西......你能做到吗?

【讨论】:

  • 感谢您的支持 - 效果很好。您能解释一下我将如何实现我在帖子中链接到的演示中显示的动画滚动效果吗?
  • 不客气。我只是有点忙,一些重要的工作来了。您可以搜索 JavaScript 动画并为动画创建通用方法,并使用 addEventListener 将值发送到该方法以进行动画处理。如果你能做到,请告诉我,如果没有,我明天会展示给你。
  • 抱歉回复晚了,我居然忘了我必须回复你。那你能做到吗?
  • 不用担心,我实际上在 Vanilla JS 中找到了一个可爱的轻量级库,它可以完成我需要的一切(带有动画)! github.com/tarun-dugar/easy-scroll
【解决方案2】:

codepen 也有这个例子

$ Here's the link https://codepen.io/wa23/pen/pObyrq

这里有重要的事情: HTML(哈巴狗)

link(href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400" rel="stylesheet")


h1 Vue Carousel
script#v-carousel(type="x/template")
  .card-carousel-wrapper
    .card-carousel--nav__left(
      @click="moveCarousel(-1)"
      :disabled="atHeadOfList"
    )
    .card-carousel
      .card-carousel--overflow-container
        .card-carousel-cards(:style="{ transform: 'translateX' + '(' + currentOffset + 'px' + ')'}")
          .card-carousel--card(v-for="item in items")
            img(src="https://placehold.it/200x200")
            .card-carousel--card--footer
              p {{ item.name }}
              p.tag(v-for="(tag,index) in item.tag" :class="index > 0 ? 'secondary' : ''") {{ tag }}
    .card-carousel--nav__right(
      @click="moveCarousel(1)"
      :disabled="atEndOfList"
    )
#app 
  carousel

CSS(CSS)

$vue-navy: #2c3e50;
$vue-navy-light: #3a5169;
$vue-teal: #42b883;
$vue-teal-light: #42b983;
$gray: #666a73;
$light-gray: #f8f8f8;


body {
  background: $light-gray;
  color: $vue-navy;
  font-family: 'Source Sans Pro', sans-serif; 
}

.card-carousel-wrapper {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 20px 0 40px;
  color: $gray;
}

.card-carousel {
  display: flex;
  justify-content: center;
  width: 640px;
  
  &--overflow-container {
    overflow: hidden;
  }
  
  &--nav__left,
  &--nav__right {
    display: inline-block;
    width: 15px;
    height: 15px;
    padding: 10px;
    box-sizing: border-box;
    border-top: 2px solid $vue-teal;
    border-right: 2px solid $vue-teal;
    cursor: pointer;
    margin: 0 20px;
    transition: transform 150ms linear;
    &[disabled] {
      opacity: 0.2;
      border-color: black;
    }
  }
  
  &--nav__left {
    transform: rotate(-135deg);
    &:active {
      transform: rotate(-135deg) scale(0.9);
    }
  }
  
  &--nav__right {
    transform: rotate(45deg);
    &:active {
      transform: rotate(45deg) scale(0.9);
    }
  }
}

.card-carousel-cards {
  display: flex;
  transition: transform 150ms ease-out;
  transform: translatex(0px);
 
  .card-carousel--card {
    margin: 0 10px;
    cursor: pointer;
    box-shadow: 0 4px 15px 0 rgba(40,44,53,.06), 0 2px 2px 0 rgba(40,44,53,.08);
    background-color: #fff;
    border-radius: 4px;
    z-index: 3;
    margin-bottom: 2px;
    
    &:first-child {
      margin-left: 0;
    }
    
    &:last-child {
      margin-right: 0;
    }
    
    img {
      vertical-align: bottom;
      border-top-left-radius: 4px;
      border-top-right-radius: 4px;
      transition: opacity 150ms linear;
      user-select: none;
      
      &:hover {
        opacity: 0.5;
      }
    }
    
    &--footer {
      border-top: 0;
      padding: 7px 15px;
      
      p {
        padding: 3px 0;
        margin: 0;
        margin-bottom: 2px;
        font-size: 19px;
        font-weight: 500;
        color: $vue-navy;
        user-select: none;
        
        &.tag {
          font-size: 11px;
          font-weight: 300;
          padding: 4px;
          background: rgba(40,44,53,.06);
          display: inline-block;
          position: relative;
          margin-left: 4px;
          color: $gray;
          
          &:before {
            content:"";
            float:left;
            position:absolute;
            top:0;
            left: -12px;
            width:0;
            height:0;
            border-color:transparent rgba(40,44,53,.06) transparent transparent;
            border-style:solid;
            border-width:8px 12px 12px 0;
        }
          &.secondary {
            margin-left: 0;
            border-left: 1.45px dashed white;
            &:before {
              display: none !important;
            }
          }
        
          &:after {
            content:"";
            position:absolute;
            top:8px;
            left:-3px;
            float:left;
            width:4px;
            height:4px;
            border-radius: 2px;
            background: white;
            box-shadow:-0px -0px 0px #004977;
          }
        }
      }
    }
  }
}

h1 {
  font-size: 3.6em;
  font-weight: 100;
  text-align: center;
  margin-bottom: 0;
  color: $vue-teal;
}

JS

Vue.component("carousel", {
  template: "#v-carousel",
  data() {
    return {
      currentOffset: 0,
      windowSize: 3,
      paginationFactor: 220,
      items: [
        {name: 'Kin Khao', tag: ["Thai"]},
        {name: 'Jū-Ni', tag: ["Sushi", "Japanese", "$$$$"]},
        {name: 'Delfina', tag: ["Pizza", "Casual"]},
        {name: 'San Tung', tag: ["Chinese", "$$"]},
        {name: 'Anchor Oyster Bar', tag: ["Seafood", "Cioppino"]},
        {name: 'Locanda', tag: ["Italian"]},
        {name: 'Garden Creamery', tag: ["Ice cream"]},
      ]
    }
  },
  computed: {
    atEndOfList() {
      return this.currentOffset <= (this.paginationFactor * -1) * (this.items.length - this.windowSize);
    },
    atHeadOfList() {
      return this.currentOffset === 0;
    },
  },
  methods: {
    moveCarousel(direction) {
      // Find a more elegant way to express the :style. consider using props to make it truly generic
      if (direction === 1 && !this.atEndOfList) {
        this.currentOffset -= this.paginationFactor;
      } else if (direction === -1 && !this.atHeadOfList) {
        this.currentOffset += this.paginationFactor;
      }
    },
  }
});

new Vue({
  el:"#app"
});

编辑:很抱歉没有尽快回复,因为我这几天很忙

【讨论】:

    【解决方案3】:

    我为此做了一个沙盒:see it here

    逻辑是这样的:

    scroll_left() {
      let content = document.querySelector(".wrapper-box");
      content.scrollLeft -= 50;
    },
    scroll_right() {
      let content = document.querySelector(".wrapper-box");
      content.scrollLeft += 40;
    }
    

    你有一个包装器并且你增加/减少scrollLeft 属性

    完整代码可见here

    【讨论】:

    • 这很棒;但是,您知道一种优雅的滚动动画方式吗?
    • 我会接受你的回答;但是,在我这样做之前,最好明确一点,该解决方案不会以与我链接到的演示相同的方式进行动画处理。我还建议您编辑答案以使用refs 而不是“document.querySelector”来选择元素,因为根据我的问题,它是一种更“Vue 方式”的做事方式。这也是我打算在我的代码中使用的方法:)
    猜你喜欢
    • 2019-03-15
    • 2018-08-03
    • 1970-01-01
    • 2014-04-27
    • 2019-02-02
    • 1970-01-01
    • 1970-01-01
    • 2013-07-29
    • 1970-01-01
    相关资源
    最近更新 更多