vue 组件状态冲突

在写vue组件Carousel 时,出现在同一个页面中多次使用同一个组件时的状态冲突,原因是过多的使用了JavaScript原生的DOM操作方式,修改使用vue中ref 操作DOM元素后,则此冲突消失;

vue中对于ref的解释为:ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例.

<template>
    <div class="yu-carousel" ref="carousel"
         :class="[type]"
         :style="{width:width,height:height}">
      <ul class="yu-img-warp" ref="warp">
        <slot/>
        <yu-carousel-item :src="lastSrc" v-if="!type"/>
      </ul>
      <ol v-if="!type" ref="lines">  //***添加 ref 用于操作DOM元素***
        <li v-for="(value,index) in items"></li>
      </ol>
      <div class="carousel-arrow">
        <a  ref="left" href="javascript:;" class="left_arrow"><i class="iconfont icon-angle-left"></i></a>
        <a  ref="right"  href="javascript:;" class="right_arrow"><i class="iconfont icon-angle-right"></i></a>
      </div>
    </div>
</template>
<script>
import YuCarouselItem from './carousel-item';

export default {
  name: 'YuCarousel',
  components: {
    YuCarouselItem,
  },
  props: {
    width: String,
    height: String,
    autoplay: false,
    interval: Number,
    type: String,
    position: null,
  },
  data() {
    return {
      items: 0,
      lastSrc: String,
    }
  },
  methods: {
  },
  mounted() {
    //  动画函数
    function animate(element, target, num) {
      num = num || 10;
      clearInterval(element.timer);
      element.timer = setInterval( () => {
        let leader = element.offsetLeft;
        let step = target > leader ? num : -num;
        if (Math.abs(target - leader) >= Math.abs(step)) {
          leader += step;
          element.style.left = leader + "px";
        } else {
          clearInterval(element.timer);
          element.style.left = target + "px";
        }
      }, 15);
    }
    function animate1(element, obj, fn){
      clearInterval(element.timer);
      element.timer = setInterval(() => {
        let flag = true;
        for(let k in obj) {
          let style = k;
          let target = obj[k];
          if (k === 'opacity') {
            let leader = getStyle(element, style);
            leader = parseFloat(leader) || 0;
            leader *= 1000;
            target *= 1000;
            let step = (target - leader)/10;
            step = step>0?Math.ceil(step):Math.floor(step);
            leader += step;
            element.style[style] = leader / 1000;
            if (leader !== target) {
              flag = false;
            }
          } else if (k === 'zIndex') {
            element.style.zIndex = target;
          } else {
            let leader = getStyle(element, style);
            leader = parseInt(leader) || 0;
            let step = (target - leader) / 10;
            step = step > 0 ? Math.ceil(step) : Math.floor(step);
            leader += step;
            element.style[style] = `${leader}px`;
            if (leader !== target) {
              flag = false;
            }
          }
        }
        if (flag) {
          clearInterval(element.timer);
          fn && fn();
        }
      }, 15);
    }
    function getStyle(element, style) {
      if ('getComputedStyle' in window) {
        return window.getComputedStyle(element, null)[style];
      } else {
        return element.currentStyle[style];
      }
    }
    let lines = null;
    const carousel = this.$refs.carousel;
    const ul = carousel.children[0];
    const leftArrow = this.$refs.left;
    const rightArrow = this.$refs.right;
    const imgs = ul.children;
    const imgWidth = carousel.offsetWidth;
    let lock = true;
    const arr = this.position;
    let count = 0;
    let timer = null;
    if (!this.type) {
      this.$nextTick(() => {
        lines = this.$refs.lines.children;
        lines[0].className = 'now';
        console.log(lines);
        // 小圆点
        for (let i = 0; i < lines.length; i++) {
          lines[i].index = i;
          lines[i].addEventListener('click', () => {
            for (let j = 0; j < lines.length; j++) {
              lines[j].className = '';
            }
            lines[this.index].className = 'now';
            animate(ul, -this.index * imgWidth, 50);
          })
        }
      });
    }
    this.lastSrc = this.$children[0].src;
    this.items = this.$children.length - 1;
    this.$refs.warp.style.width = `${this.$children.length}00%`;
    // const list = document.querySelectorAll('.yu-img-warp li');  **有冲突时的代码**
    const list = this.$refs.warp.children;   // **修改之后 无冲突,使用啦 ref操作DOM元素**
    for (let i = 0; i < list.length; i++) {
      list[i].style.width = `${(1 / this.$children.length) * 100}%`;
    }
    //  轮播图
    if (this.type) {
      for (let i = 0; i < imgs.length; i++) {
        animate1(imgs[i], arr[i]);
      }
    }
    rightArrow.addEventListener('click', () => {
      //  普通轮播图
      if (this.type) {
        if (lock) {
          lock = false;
          arr.unshift(arr.pop());
          for (let i = 0; i < imgs.length; i ++) {
            animate1(imgs[i], arr[i], () => {
              lock = true;
            })
          }
        }
      } else {
        if (count >= imgs.length - 1) {
          ul.style.left = 0;
          count = 0
        }
        count += 1;
        animate(ul, -count * imgWidth, 50);
        for (let i = 0; i < lines.length; i++) {
          lines[i].className = '';
        }
        if (count >= imgs.length - 1) {
          lines[0].className = 'now';
        } else {
          lines[count].className = 'now';
        }
      }
    });
    //  左箭头
    leftArrow.addEventListener('click', () => {
      if (this.type) {
        if (lock) {
          lock = false;
          arr.push(arr.shift());
          for (let i = 0; i < imgs.length; i++) {
            animate1(imgs[i], arr[i], () => {
              lock = true;
            })
          }
        }
      } else {
        //  普通轮播图
        if (count <= 0) {
          count = imgs.length - 1;
          ul.style.left = `${-count * imgWidth}px`;
        }
        count -= 1;
        animate(ul, -count * imgWidth, 50);

        for (let i = 0; i < lines.length; i++) {
          lines[i].className = '';
        }
        lines[count].className = 'now';
      }
    });
    //  line

    //  自动播放
    let that = this;
    function auto() {
      timer = setInterval(() => {
        rightArrow.click();
      }, that.interval);
    }
    if (this.autoplay) {
      auto();
      carousel.onmouseover = () => {
        clearInterval(timer);
      };
      carousel.onmouseout = () => {
        clearInterval(timer);
        auto();
      }
    }
  },
}
</script>
Logo

前往低代码交流专区

更多推荐