<template>
  <div class="container">
    <ul class="menu">
      <li
        v-for="item in list"
        :key="item.key"
        :class="{ active: item.key == current }"
        @click="liClick(item.key)"
      >
        {{ item.name }}
      </li>
    </ul>
    <div class="content">
      <div id="key1">国家1</div>
      <div id="key2">省份2</div>
      <div id="key3">城市3</div>
      <div id="key4">县城4</div>
      <div id="key5">国家5</div>
      <div id="key6">省份6</div>
      <div id="key7">城市7</div>
      <div id="key8">县城8</div>
      <div id="key9">县城9</div>
      <div id="key10">县城10</div>
    </div>
  </div>
</template>
<script setup>
import { reactive, ref, onMounted, watchEffect } from "vue";
const current = ref("key1");
// const flag = ref(false);//----放开是另一种效果
const liClick = (key) => {
  // flag.value = true;//----放开是另一种效果
  current.value = key;

  /* 
  获取到key 然后渠道对应的元素 进行滚动
   */
  let content = document.querySelector(".content");
  let target = document.querySelector(`#${key}`);
  content.scrollTo({
    top: target.offsetTop - 30,
    behavior: "smooth",
  });
};
const list = reactive([
  {
    key: "key1",
    name: "国家1",
  },
  {
    key: "key2",
    name: "省份2",
  },
  {
    key: "key3",
    name: "城市3",
  },
  {
    key: "key4",
    name: "县城4",
  },
  {
    key: "key5",
    name: "国家5",
  },
  {
    key: "key6",
    name: "省份6",
  },
  {
    key: "key7",
    name: "城市7",
  },
  {
    key: "key8",
    name: "县城8",
  },
  {
    key: "key9",
    name: "县城9",
  },
  {
    key: "key10",
    name: "县城10",
  },
]);
const showKeys = reactive([
  // "ke1",
  // "key2",
  // "key3",
  // "key4",
  // "key5",
  // "key6",
  // "key7",
  // "key8",
  // "key9",
  // "key10",
]);
// -----交叉观察器
let io = new IntersectionObserver(
  (entrys) => {
    console.log("进入视口--", entrys[0].target.id);
    let firstInsetId = entrys[0].target.id;
    let isInter = entrys[0].isIntersecting;
    console.log(11111, isInter);

    if (isInter) {
      let isFind = showKeys.findIndex((item) => item == firstInsetId);
      if (isFind == -1) {
        showKeys.push(firstInsetId);
      }
    } else {
      let index = showKeys.findIndex((item) => item == firstInsetId);
      if (index !== -1) {
        showKeys.splice(index, 1);
      }
    }
  },
  { threshold: [0, 0.25, 0.5, 1] }
);
watchEffect(() => {
  // if (flag.value) return;//----放开是另一种效果
  let result = "";
  for (const item of list) {
    if (showKeys.findIndex((key) => key === item.key) !== -1) {
      result = item.key;
      break;
    }
  }
  current.value = result;
});
console.log(watchEffect);
// ----初始话监听
const startObser = () => {
  for (const item of list) {
    let el = document.querySelector(`#${item.key}`);
    showKeys.push(item.key);
    io.observe(el);
  }
};
onMounted(() => {
  // let content = document.querySelector(".content");//----放开是另一种效果
  // content.addEventListener("mouseenter", () => {//----放开是另一种效果
  //   console.log(123);
  //   flag.value = false;
  // });
  startObser();
});
</script>
<style lang="less" scoped>
.container {
  width: 100%;
  height: 100%;
  background-color: #fff;
  display: flex;
  justify-content: flex-start;
  .menu {
    margin-right: 5px;
    width: 120px;
    border: 1px solid pink;
    padding: 0;
    margin-bottom: 0;
    li {
      list-style: none;
      height: 26px;
      line-height: 26px;
      font-size: 16px;
      text-align: center;
      cursor: pointer;
      &:hover {
        background-color: rgb(211, 14, 100);
      }
    }
    li.active {
      background-color: rgb(211, 14, 100);
    }
  }
  .content {
    width: calc(100% - 120px);
    border: 1px solid red;
    overflow-y: auto;
    padding-top: 5px;
    div {
      height: 200px;
      border: 1px solid rgb(0, 255, 21);
      // margin-bottom: 3px;
    }
  }
}
</style>

下面这是稍微修改后的版本----去掉了监听---同时打开节流阀是在 鼠标滚动时 (上个版本是在鼠标移入时) -----对比上面的可


<template>
  <div class="container">
    <ul class="menu">
      <li
        v-for="item in list"
        :key="item.key"
        :class="{ active: item.key == current }"
        @click="liClick(item.key)"
      >
        {{ item.name }}
      </li>
    </ul>
    <div class="content">
      <div id="key1">国家1</div>
      <div id="key2">省份2</div>
      <div id="key3">城市3</div>
      <div id="key4">县城4</div>
      <div id="key5">国家5</div>
      <div id="key6">省份6</div>
      <div id="key7">城市7</div>
      <div id="key8">县城8</div>
      <div id="key9">县城9</div>
      <div id="key10">县城10</div>
    </div>
  </div>
</template>
<script setup>
import { reactive, ref, onMounted, watchEffect } from "vue";
const current = ref("key1");
const flag = ref(false); //----放开是另一种效果
const liClick = (key) => {
  flag.value = true; //----放开是另一种效果
  current.value = key;

  /* 
  获取到key 然后渠道对应的元素 进行滚动
   */
  let content = document.querySelector(".content");
  let target = document.querySelector(`#${key}`);
  content.scrollTo({
    top: target.offsetTop - 30,
    behavior: "smooth",
  });
};
const list = reactive([
  {
    key: "key1",
    name: "国家1",
  },
  {
    key: "key2",
    name: "省份2",
  },
  {
    key: "key3",
    name: "城市3",
  },
  {
    key: "key4",
    name: "县城4",
  },
  {
    key: "key5",
    name: "国家5",
  },
  {
    key: "key6",
    name: "省份6",
  },
  {
    key: "key7",
    name: "城市7",
  },
  {
    key: "key8",
    name: "县城8",
  },
  {
    key: "key9",
    name: "县城9",
  },
  {
    key: "key10",
    name: "县城10",
  },
]);
const showKeys = reactive([
  // "ke1",
  // "key2",
  // "key3",
  // "key4",
  // "key5",
  // "key6",
  // "key7",
  // "key8",
  // "key9",
  // "key10",
]);
// -----交叉观察器
let io = new IntersectionObserver(
  (entrys) => {
    console.log("进入视口--", entrys[0].target.id);
    let firstInsetId = entrys[0].target.id;
    let isInter = entrys[0].isIntersecting;
    console.log(11111, isInter);

    if (isInter) {
      let isFind = showKeys.findIndex((item) => item == firstInsetId);
      if (isFind == -1) {
        showKeys.push(firstInsetId);
      }
    } else {
      let index = showKeys.findIndex((item) => item == firstInsetId);
      if (index !== -1) {
        showKeys.splice(index, 1);
      }
    }

    if (flag.value) return; //----放开是另一种效果
    let result = "";
    for (const item of list) {
      if (showKeys.findIndex((key) => key === item.key) !== -1) {
        result = item.key;
        break;
      }
    }
    current.value = result;
  },
  { threshold: [0, 0.25, 0.5, 1] }
);
// watchEffect(() => {
//   if (flag.value) return; //----放开是另一种效果
//   let result = "";
//   for (const item of list) {
//     if (showKeys.findIndex((key) => key === item.key) !== -1) {
//       result = item.key;
//       break;
//     }
//   }
//   current.value = result;
// });
console.log(watchEffect);
// ----初始话监听
const startObser = () => {
  for (const item of list) {
    let el = document.querySelector(`#${item.key}`);
    showKeys.push(item.key);
    io.observe(el);
  }
};
onMounted(() => {
  let content = document.querySelector(".content"); //----放开是另一种效果
  content.addEventListener("mousewheel", () => {
    //----放开是另一种效果
    console.log(123);
    flag.value = false;
  });
  startObser();
});
</script>
<style lang="less" scoped>
.container {
  width: 100%;
  height: 100%;
  background-color: #fff;
  display: flex;
  justify-content: flex-start;
  .menu {
    margin-right: 5px;
    width: 120px;
    border: 1px solid pink;
    padding: 0;
    margin-bottom: 0;
    li {
      list-style: none;
      height: 26px;
      line-height: 26px;
      font-size: 16px;
      text-align: center;
      cursor: pointer;
      &:hover {
        background-color: rgb(211, 14, 100);
      }
    }
    li.active {
      background-color: rgb(211, 14, 100);
    }
  }
  .content {
    width: calc(100% - 120px);
    border: 1px solid red;
    overflow-y: auto;
    padding-top: 5px;
    div {
      height: 200px;
      border: 1px solid rgb(0, 255, 21);
      // margin-bottom: 3px;
    }
  }
}
</style>

以看一下  

vue2中的写法

<template>
  <div class="main">
    <ul class="nav">
      <li @click="liClick(item.key)" :class="{active:currentKey==item.key}" v-for="item in navList" :key="item.key">{{ item.key }}</li>
    </ul>
    <div class="content">
      <div :id="item.key" v-for="item in navList" :key="item.key">{{ item.name }}</div>
    </div>
  </div>
</template>
<script>
export default {
  name: 'Play',
  data () {
    return {
      flag:false,
      currentKey:"key1",
      navList: [
        {name:"世界1",key:"key1"},
        {name:"世界2",key:"key2"},
        {name:"世界3",key:"key3"},
        {name:"世界4",key:"key4"},
        {name:"世界5",key:"key5"},
        {name:"世界6",key:"key6"},
        {name:"世界7",key:"key7"},
        {name:"世界8",key:"key8"},
        {name:"世界9",key:"key9"},
        {name:"世界10",key:"key10"},
      ]
    }
  },
  methods: {
    liClick (key) {
      this.flag=true
      this.currentKey = key
      // ---获取根元素
      let content = document.querySelector(".content")
      // ----获取目标元素
      let targetEle = document.querySelector(`#${key}`)
      content.scrollTo({
        top: targetEle.offsetTop,
        behavior: "smooth"
      })
    }
  },
  mounted () {
    let ioInKey=[]
    let option = {
      threshold: [0, 0.25, 0.5, 0.75, 1],
    }
    const io = new IntersectionObserver((entrys) => {
      let entrysOfFirst = entrys[0].target.id
      if (entrys[0].isIntersecting) {
        let find = ioInKey.findIndex(item => item == entrysOfFirst)
        if (find == -1) {
          ioInKey.push(entrysOfFirst)
       }
      } else {
        let find = ioInKey.findIndex(item => item == entrysOfFirst)
        if (find != -1) {
          ioInKey.splice(find,1)
        }
      }
      if(this.flag) return false
      for (let item of this.navList){
        const findItem= ioInKey.find(ite => ite == item.key)
        if (findItem) {
          this.currentKey = item.key
         break
        }
      }
    }, option);
    this.navList.forEach(item => {
      io.observe(document.querySelector(`#${item.key}`))
      ioInKey.push(item.key)
    })
    // -----根元素绑定鼠标滚动事件---为了开始节流
    let content = document.querySelector(".content")
    content.addEventListener("mousewheel", () => {
      this.flag=false
    })
  }
}
</script>
<style lang="scss" scoped>
*{
  margin:0;
  padding:0;
}
.main{
  width:100%;
  height:100%;
  display:flex;
  justify-content: flex-start;
  .nav{
    width:120px;
    min-height:300px;
    font-size:16px;
    li{
      height:26px;
      line-height: 26px;
      text-align:center;
      background-color: pink;
      &:hover,&.active{
        background-color: rgb(108, 253, 5);
      }
    }
  }
  .content{
    flex:1;
    margin-left:5px;
    width:calc(100%-120px);
    height:700px;
    overflow-y:auto;
    border:1px solid rgb(0, 255, 8);
    div{
      height:300px;
      border:1px solid blue;
    }
  }
}
</style>

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐