vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue动态绑定style失效

Vue实现无限轮播效果时动态绑定style失效的解决方法

作者:尖椒土豆sss

最近在开发中遇到了一个新需求:列表轮播滚动,实现方式也有很多,比如使用第三方插件,但是由于不想依赖第三方插件,想自己实现,于是我开始了尝试,但是在这个过程中遇到了动态绑定style样式不生效,所以本文介绍了Vue实现无限轮播效果时动态绑定style失效的解决方法

前言

最近在开发中遇到了一个新需求:列表轮播滚动;这个需求其实是比较常见的,实现方式也有很多,比如使用第三方插件:vue-seamless-scroll,但是由于不想依赖第三方插件,想自己实现,于是我开始了尝试,但是在这个过程中遇到了动态绑定style样式不生效、绑定值与渲染值不一致等问题。谨以此篇记录自己的学习过程,也希望可以帮助到其他同学。

基础代码如下

创建一个 scroll.vue 组件,内容如下:

<div class="domScroll">
 <div
      :class="['scroll-content', rollClass]">
      <slot></slot>
      <slot></slot>
 </div>
</div>
 export default {
  data() {
    return {
      rollClass: ""
    };
  }
 }
<style lang="less" scoped>
.domScroll {
  overflow: hidden;
}
</style>

实现方式1(不推荐)

tableScroll() {
  this.$nextTick(() => {
    const tabDom = this.$el.querySelector(".scroll-content");
    const rowOffsetHeight = this.$el.querySelector(".row-item")
          .offsetHeight;;
    setInterval(() => {
      const shift = this.data[0];
        setTimeout(() => {
          this.data.push(shift);
          tabDom.style.transition = "all .5s";
          tabDom.style.marginTop = `-${rowOffsetHeight}px`;
        }, 500);
        setTimeout(() => {
          this.data.splice(0, 1);
          tabDom.style.transition = "all 0s ease 0s";
          tabDom.style.marginTop = "0";
        }, 1000);
    }, 1500);
  });
}

代码分析

主要是通过不停的将第一条数据添加到数组末尾、然后删除当前第一条数据,同时添加删除动画样式来实现滚动效果。这种方式添加删除时会出现停顿卡顿的现象。

实现方式2(推荐)

初始化方法

    init() {
      const scrollContent = this.$el.querySelector(".scroll-content");
      if (scrollContent) {
        const offsetHeight = scrollContent.offsetHeight;
        const scrollClass = this.setScrollClass(offsetHeight / 2, this.speed);
        this.rollClass = scrollClass;
      }
    },

首先通过 this.$el.querySelector(".scroll-content"); 获取到目标dom元素,如果该dom存在,获取其 offsetHeight值。

然后调用 setScrollClass方法传参:

最后将返回值设置给全局变量 rollClass

setScrollClass方法

    setScrollClass(offsetHeight, speed) {
      const uid = Math.random().toString(36).substring(2, 5);
      const style = document.createElement("style");
      style.innerHTML = `
        @keyframes listRowup${uid} {
          0% {
            -webkit-transform: translate3d(0, 0, 0);
            transform: translate3d(0, 0, 0);
          }
          100% {
            -webkit-transform: translate3d(0, -50%, 0);
            transform: translate3d(0, -50%, 0);
          }
        }
        .rowup-${uid} {
          -webkit-animation: ${Math.floor(
            (offsetHeight * 1000) / speed
          )}ms listRowup${uid} linear infinite normal;
          animation: ${Math.floor(
            (offsetHeight * 1000) / speed
          )}ms listRowup${uid} linear infinite normal;
        }
      `;
      document.getElementsByTagName("head")[0].appendChild(style);
      return `rowup-${uid}`;
    }

该函数主要职责:

组件使用

在主文件引入 scroll.vue

<Domscroll :height="140">
    <div class="listBox flex">
      <div
        v-for="item in scrollList"
        :key="item"
        class="item"
      >
        {{ item }}
      </div>
    </div>
</Domscroll>
computed: {
scrollList() {
  return [...this.list1,...this.list1]
}, 
data() {
return {
 list1: [
      "机构类",
      "区域类",
      "国家类",
      "证照文书类",
      "业务对象类",
      "人员类",
      "法律法规类型",
      "金融类"
    ]
  }
}
  

需要注意的是这里需要将原数据拷贝成两份数据,我这里使用计算属性+ 扩展运算符实现 scrollList 方法返回双份数据。

开始优化

在上面方式1中的代码已经可以实现dom列表的无限滚动效果;但是可以看出来该代码有优化的空间。

修改基础代码

添加: ref="scrollContent"

<div class="domScroll">
 <div
      ref="scrollContent"
      :class="['scroll-content']"
      :style="scrollSty">
      <slot></slot>
      <slot></slot>
 </div>
</div>

添加:scrollSty变量

 export default {
  data() {
    return {
      scrollSty: {
        animation: ""
      }
    };
  }
 }

将css动画添加到css中

<style lang="less" scoped>
.domScroll {
  overflow: hidden;
  @keyframes rowup {
    0% {
      -webkit-transform: translate(0, 0);
      transform: translate(0, 0);
    }
    100% {
      -webkit-transform: translate(0, -50%);
      transform: translate(0, -50%);
    }
  }
}
</style>

修改methods方法

  dynamicStyle(speed) {
      const scrollContent = this.$refs.scrollContent;
      const offsetHeight = scrollContent.offsetHeight / 2;
      const duration = Math.floor((offsetHeight * 1000) / speed);
      this.scrollSty = {
        animation: `${duration}ms listRowup linear infinite normal`,
        "-webkit-animation": `${duration}ms listRowup linear infinite normal`
      };
    },

代码分析

动画参数

animation设置 CSS 动画的属性:

遇到问题

当在 mounted 中执行 dynamicStyle方法时发现动画没有生效,检查元素后发现确实成功绑定动画了,但是为什么不生效呢?

于是将结果值与dom元素打印出来做对比:

发现动态绑定的style animation的属性结果与预期(函数设置的style)绑定的值竟然不同! 我一脸懵逼,反复查看代码发现没有错误啊!

尝试解决

最终解决

<style lang="less" scoped>
.domScroll {
  overflow: hidden;
}
</style>

<style>
 @keyframes rowup {
    0% {
      -webkit-transform: translate(0, 0);
      transform: translate(0, 0);
    }
    100% {
      -webkit-transform: translate(0, -50%);
      transform: translate(0, -50%);
    }
  }

</style>

经过查资料分析发现原来是因为 style 标签的 scoped 属性导致的动画样式的选择器不匹配

scoped 样式中生成的类名会自动生成唯一标识符,浏览器无法找到这些动画的定义,导致动画效果无法生效!

比较推荐的方法就是将动画样式定义在全局样式文件中,这样可以确保 @keyframes 能够被任何元素正确的引用使用。

以上就是Vue实现无限轮播效果时动态绑定style失效的解决方法的详细内容,更多关于Vue动态绑定style失效的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文