模块进入视口的动画(vue3动画,看见<=>看不见)

 效果:

这个盒子的视口小于 0.3 时,盒子向两边拉开,逐渐消失 

一开始我是想绑定大盒子里面的两个小盒子的  threshold: [0.3,0.4],

但是视口的大于一定比例,只执行了第一个盒子,而且 视口>0.4,第一个盒子又执行了一次,而第二个盒子没有执行,下面为错误代码

    // if (entry.target === test1Ref.value) {
    //   if (entry.intersectionRatio >= 0.3) {
    //     entry.target.classList.remove("animateTest1Hide");
    //     entry.target.classList.add("animateTest1");
    //   } else if (entry.intersectionRatio < 0.3) {
    //     entry.target.classList.remove("animateTest1");
    //     entry.target.classList.add("animateTest1Hide");
    //   }
    // } else if (entry.target === test2Ref.value) {
    //     if (entry.intersectionRatio >= 0.3) {
    //     entry.target.classList.remove("animateTest2Hide");
    //     entry.target.classList.add("animateTest2");
    //   } else if (entry.intersectionRatio < 0.3) {
    //     entry.target.classList.remove("animateTest2");
    //     entry.target.classList.add("animateTest2Hide");
    //   }
    // }

onMounted(() => {
  observer.value = new IntersectionObserver(onIntersect, {
    threshold: [0.3,0.4],
  });
  observer.value.observe(test1Ref.value);
  observer.value.observe(test2Ref.value);
});

所以改成了只监听外面的大盒子,里面的小盒子可以通过ref拿到,再去做动画就好了

完整代码:

<template>
  <div ref="externalBoxRef" class="externalBoxClass">
    <div ref="box1Ref" class="test1"></div>
    <div ref="box2Ref" class="test2"></div>
  </div>
</template>
<script setup>
// import "intersection-observer";
const externalBoxRef = ref(null);
const box1Ref = ref(null);
const box2Ref = ref(null);
const observer = ref(null);
// 定义可见性变化回调函数
// if (entry.isIntersecting) {}//是否进入视口 // 目标元素进入可视区域时添加动画类
const onIntersect = (entries) => {
//   console.log("执行entries--", entries);
entries.forEach((entry) => {
    console.log("entry-----", entry);
    if(entry.intersectionRatio > 0.3){ //第一个第二个小盒子都在这里设置样式属性
      box1Ref.value.classList.remove("animateTest1Hide");
      box1Ref.value.classList.add("animateTest1");
      box2Ref.value.classList.remove("animateTest2Hide");
      box2Ref.value.classList.add("animateTest2");
    }else{
      box1Ref.value.classList.remove("animateTest1");
      box1Ref.value.classList.add("animateTest1Hide");
      box2Ref.value.classList.remove("animateTest2");
      box2Ref.value.classList.add("animateTest2Hide");
    }
  });
  // 停止观察 只执行一次onIntersect 后面视口变化也不再触发函数了 
  // observer.value.unobserve(entry.target);
};
onMounted(() => {
  observer.value = new IntersectionObserver(onIntersect, {
    threshold: [0.3], //这个是监视盒子出现了百分比(30%)调用函数
  });
  observer.value.observe(externalBoxRef.value);
});
onUnmounted(() => {
  observer.value.disconnect();
});
</script>
<style lang="less" scoped>
.externalBoxClass {
  margin: 0 auto;
  width: 1130px;
  height: 300px;
  background-color: pink;
  display: flex;
  justify-content: space-between;
  .test1 {
    width: 300px;
    height: 100%;
    background-color: #f00;
    // opacity: 0;
    // animation: showDiv1 3s forwards;
  }
  .animateTest1 {
    animation: showDiv1 3s forwards;
  }
  .animateTest1Hide {
    animation: hideDiv1 3s forwards;
  }
  @keyframes showDiv1 {
    from {
      transform: translateX(-100%);
    }
    to {
      transform: translateX(0);
      opacity: 1;
    }
  }
  @keyframes hideDiv1 {
    from {
      transform: translateX(0);
      opacity: 1;
    }
    to {
      transform: translateX(-100%);
      opacity: 0;
    }
  }
  .test2 {
    height: 100%;
    width: 600px;
    background-color: blue;
  }
  .animateTest2 {
    animation: showDiv2 3s forwards;
  }
  .animateTest2Hide {
    animation: hideDiv2 3s forwards;
  }
  @keyframes showDiv2 {
    from {
      transform: translateX(100%);
    }
    to {
      transform: translateX(0);
      opacity: 1;
    }
  }
  @keyframes hideDiv2 {
    from {
      transform: translateX(0);
      opacity: 1;
    }
    to {
      transform: translateX(100%);
      opacity: 0;
    }
  }
}
</style>

注:

1. 可以自己对上面的进行封装(不设置宽高+具名插槽)

子组件内(组件:slideIn.vue)

<div ref="box1Ref" class="test1">
   <slot name="box1"></slot>
</div>
<div ref="box2Ref" class="test2">
   <slot name="box2"></slot>
</div>

父组件:

<slideIn>
  <template v-slot:box1>
    (放到子组件盒子第一个插槽的的内容)
  </template>
  <template v-slot:box2>
    (放到子组件盒第二个插槽的内容)
  </template>
</slideIn>

2. IntersectionObserver是浏览器自带的视口函数,里面的一些参数

调用函数输出:

const onIntersect = (entries) => {
entries.forEach((entry) => {
    console.log("entry-----", entry); //监视的每一个模块
  });
  // 停止观察 只执行一次onIntersect 后面视口变化也不再触发函数了 
  // observer.value.unobserve(entry.target);
};

isIntersecting(true/false):模块进没进入视口

intersectionRatio (0-1):模块进入视口百分比(我用的是这个来做动画)

target :直接拿到这个节点

observer.value = new IntersectionObserver(onIntersect, {threshold: [0.3],});

不想用百分比,单纯的进入视口和离开视口可以直接写:

observer.value = new IntersectionObserver(onIntersect);

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这段代码是一个简单的 HTML 文件,使用了 Vue.js 库来实现数据绑定和渲染。让我一步一步解释这段代码的作用: 1. `<!DOCTYPE html>`:这是 HTML 文档的声明,告诉浏览器使用 HTML 的哪个版本解析页面。 2. `<html lang="en">`:指定文档的语言为英语。 3. `<head>`:HTML 头部元素,用于包含页面的元数据和引入外部资源。 4. `<meta charset="UTF-8">`:指定文档使用 UTF-8 字符编码,以支持更多字符。 5. `<meta http-equiv="X-UA-Compatible" content="IE=edge">`:告诉 IE 浏览器使用最新的渲染引擎。 6. `<meta name="viewport" content="width=device-width, initial-scale=1.0">`:设置口的宽度和缩放比例,用于适配移动设备。 7. `<title>mvvm</title>`:设置页面的标题为 "mvvm"。 8. `<script src="../js/vue.js"></script>`:引入 Vue.js 库文件。 9. `<body>`:HTML 的主体部分,包含了页面的内容。 10. `<div id="root">`:一个 div 元素,用作 Vue 应用程序的挂载点。 11. `{{name}}` 和 `{{rank}}`:Vue 的模板语法,用于在页面中输出数据。这里会显示在 Vue 实例的 data 中定义的 `name` 和 `rank` 的值。 12. `{{$options}}`:Vue 实例的 `$options` 属性,用于在页面中输出 Vue 实例的选项对象。 13. `<script>`:JavaScript 代码块,用于创建和配置 Vue 实例。 14. `Vue.config.productionTip = false`:配置 Vue 的生产环境提示,将其设置为 `false` 可以禁用一些开发时的警告信息。 15. `new Vue({})`:创建一个 Vue 实例,通过传入的参数进行配置。 16. `el:'#root'`:指定 Vue 实例挂载的元素为 id 为 "root" 的 div 元素。 17. `data: {}`:Vue 实例的数据对象,用于存储页面中需要绑定和展示的数据。 18. `name:'uzi'` 和 `rank:'RNG'`:定义了两个数据属性,分别是 `name` 和 `rank`,它们的初始值分别是 'uzi' 和 'RNG'。 整体来说,这段代码通过 Vue.js 将数据绑定到 HTML 页面上,并实现了简单的数据渲染。在页面中可以显示出 `uzi` 和 `RNG` 的值,并输出 Vue 实例的选项对象。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值