当前位置:首页 > VUE

前端vue实现左右联动

2026-01-20 04:02:38VUE

实现左右联动的基本思路

左右联动通常指两个独立滚动的区域(如左侧菜单和右侧内容),当滚动一侧时另一侧同步滚动。Vue中可通过监听滚动事件、计算元素位置和动态调整滚动位置实现。

监听滚动事件

为左右两侧容器添加@scroll事件监听,使用v-on@语法绑定处理函数。避免高频触发可使用防抖(debounce)优化:

<template>
  <div class="container">
    <div class="left" @scroll="handleLeftScroll">
      <!-- 左侧内容 -->
    </div>
    <div class="right" @scroll="handleRightScroll">
      <!-- 右侧内容 -->
    </div>
  </div>
</template>

<script>
export default {
  methods: {
    handleLeftScroll(event) {
      if (this.scrolling) return;
      this.scrolling = 'right';
      const percent = event.target.scrollTop / (event.target.scrollHeight - event.target.clientHeight);
      this.$refs.right.scrollTop = percent * (this.$refs.right.scrollHeight - this.$refs.right.clientHeight);
      setTimeout(() => this.scrolling = false, 100);
    },
    handleRightScroll(event) {
      if (this.scrolling) return;
      this.scrolling = 'left';
      const percent = event.target.scrollTop / (event.target.scrollHeight - event.target.clientHeight);
      this.$refs.left.scrollTop = percent * (this.$refs.left.scrollHeight - this.$refs.left.clientHeight);
      setTimeout(() => this.scrolling = false, 100);
    }
  },
  data() {
    return {
      scrolling: false
    };
  }
};
</script>

动态计算滚动位置

通过比例同步两侧滚动位置更精准。计算当前滚动位置占总可滚动高度的比例,将该比例应用到另一侧容器:

// 在handleScroll方法中:
const percent = event.target.scrollTop / (event.target.scrollHeight - event.target.clientHeight);
this.$refs.otherSide.scrollTop = percent * (this.$refs.otherSide.scrollHeight - this.$refs.otherSide.clientHeight);

防止循环触发

设置标志位避免滚动事件互相触发导致无限循环:

data() {
  return {
    isSyncing: false
  };
},
methods: {
  handleScroll(event, targetRef) {
    if (this.isSyncing) return;
    this.isSyncing = true;
    // 计算并设置目标滚动位置
    requestAnimationFrame(() => {
      this.isSyncing = false;
    });
  }
}

使用IntersectionObserver实现精准联动(适用于内容区块对应)

当左右两侧为严格对应的区块时,可使用交叉观察器实现更精准的联动:

mounted() {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting && !this.scrolling) {
        const index = this.leftItems.findIndex(item => item.id === entry.target.dataset.id);
        this.scrolling = true;
        this.$refs.left.scrollTop = index * 50; // 假设每个项高度50px
        setTimeout(() => this.scrolling = false, 100);
      }
    });
  }, { threshold: 0.5 });

  this.rightItems.forEach(item => {
    observer.observe(this.$refs[`right-${item.id}`]);
  });
}

样式与布局建议

确保容器具有固定高度和overflow-y: scroll样式:

.container {
  display: flex;
  height: 100vh;
}
.left, .right {
  flex: 1;
  overflow-y: scroll;
  height: 100%;
}

性能优化方案

对于大数据量场景,可采用虚拟滚动技术(如vue-virtual-scroller)减少DOM节点:

前端vue实现左右联动

<template>
  <RecycleScroller
    class="left"
    :items="leftItems"
    :item-size="50"
    @scroll="handleLeftScroll"
  >
    <!-- 模板内容 -->
  </RecycleScroller>
</template>

完整示例组件

<template>
  <div class="linkage-container">
    <div 
      ref="left"
      class="left-list"
      @scroll="handleLeftScroll"
    >
      <div 
        v-for="item in leftItems" 
        :key="item.id"
        :class="{ active: activeId === item.id }"
      >
        {{ item.title }}
      </div>
    </div>
    <div 
      ref="right"
      class="right-content"
      @scroll="handleRightScroll"
    >
      <section 
        v-for="item in rightItems" 
        :key="item.id"
        :ref="`right-${item.id}`"
      >
        <h2>{{ item.title }}</h2>
        <p>{{ item.content }}</p>
      </section>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      leftItems: [...],
      rightItems: [...],
      activeId: null,
      scrolling: false
    };
  },
  mounted() {
    this.setupIntersectionObserver();
  },
  methods: {
    handleLeftScroll(event) {
      if (this.scrolling === 'right') return;
      this.scrolling = 'left';
      const percent = event.target.scrollTop / (event.target.scrollHeight - event.target.clientHeight);
      this.$refs.right.scrollTop = percent * (this.$refs.right.scrollHeight - this.$refs.right.clientHeight);
      setTimeout(() => this.scrolling = false, 100);
    },
    setupIntersectionObserver() {
      const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
          if (entry.isIntersecting && !this.scrolling) {
            this.activeId = entry.target.dataset.id;
          }
        });
      }, { threshold: 0.5 });
      this.rightItems.forEach(item => {
        observer.observe(this.$refs[`right-${item.id}`][0]);
      });
    }
  }
};
</script>

标签: vue
分享给朋友:

相关文章

vue实现好友列表

vue实现好友列表

实现好友列表的Vue组件 数据准备 在Vue组件的data中定义好友列表数据,通常是一个数组对象,每个对象包含好友的基本信息如ID、头像、昵称等。 data() { return { f…

简单实现vue

简单实现vue

Vue 的基本实现 创建一个简单的 Vue 应用需要引入 Vue 库,并编写基本的模板和数据绑定逻辑。 <!DOCTYPE html> <html lang="en"> &l…

vue实现开关

vue实现开关

Vue 实现开关组件的方法 使用原生HTML和Vue数据绑定 通过v-model绑定复选框的checked状态,结合CSS样式实现开关效果: <template> <label…

vue 实现遮罩

vue 实现遮罩

Vue 实现遮罩层的方法 使用固定定位和透明背景 在Vue中实现遮罩层可以通过CSS固定定位结合透明背景色完成。创建一个全屏遮罩组件,利用position: fixed覆盖整个视窗。 <tem…

vue实现pc

vue实现pc

Vue 实现 PC 端应用开发 Vue.js 是一个流行的前端框架,适用于构建 PC 端 Web 应用。以下是关键步骤和最佳实践: 项目初始化 使用 Vue CLI 或 Vite 创建项目:…

vue实现横滚

vue实现横滚

Vue 实现横滚效果 横滚效果通常指水平滚动内容,常见于轮播图、横向导航栏等场景。以下是几种实现方式: 使用 CSS 和 Vue 结合 通过 CSS 的 overflow-x 和 white-spa…