vue3+Ts 在 script setup 模式下监听页面滚动,并调用子组件的方法设置样式

本文介绍了如何在Vue.js中,通过监听滚动事件动态改变顶部公共组件header.vue的背景色。父组件home.vue使用ref获取Q-Header实例,并在滚动时计算滚动位置,根据位置调整背景色透明度。子组件header.vue提供了setBgColor方法来设置背景色,允许外部调用。滚动过程中使用延时器确保滚动结束时才执行背景色更新。

需求:制作网站时,顶部 header.vue(公共组件)需要随着网页内容垂直方向滚动时的位置变化,动态改变其背景色。

父组件 home.vue 代码:

<template>
    <Q-Header ref="myHeader"></Q-Header>
    <div ref="myDiv">
		父组件代码...
	</div>
</template>

<script setup lang="ts">
import { ref, watch, onMounted, onBeforeUnmount } from 'vue'
import QHeader from '@/components/header.vue'

const myHeader = ref<any>(null)
const myDiv = ref<any>(null)
const myDivH = ref<number>(0)
const oldScrollTop = ref<number>(0); // 记录上一次滚动结束后的滚动距离
const scrollTop = ref<number>(0); // 记录当前的滚动距离
const scrollHandle = () => {
    scrollTop.value = window.scrollY;	//滚动条距离浏览器顶部高度
    if (!myDivH.value) {
        myDivH.value = myDiv.value.offsetHeight;
    }
}
onMounted (() => {
    myHeader.value.setBgColor(0);   //将 header.vue组件的背景设置为透明
    window.addEventListener('scroll', scrollHandle);
})
onBeforeUnmount(() => {
    window.removeEventListener('scroll', scrollHandle)
})

watch(
    () => scrollTop.value,
    (newValue, oldValue) => {
         setTimeout(() => {
            if (newValue === window.scrollY) {
                // 延时执行后当newValue等于window.scrollY,代表滚动结束
                // console.log('滚动结束');
                oldScrollTop.value = newValue; // 每次滚动结束
                if (myDivH) {
                    let i = scrollTop.value / myDivH.value;
                    //调用子组件 header.vue 中的方法setBgColor,设置背景色
                    if (i > 1) {
                        myHeader.value.setBgColor(1)
                    } else {
                        myHeader.value.setBgColor(i.toFixed(2))
                    }
                }
            }
         }, 20); // 需要使用延时器,否则每次newValue和window.scrollY都相等,无法判断,20ms刚好大于watch的侦听周期,故延时20ms
        if (oldScrollTop.value === oldValue) {
            // 每次滚动开始时oldScrollTop与oldValue相等
            console.log('滚动开始');
        }
    }
)
</script>

子组件 header.vue 代码

<script setup lang="ts">
import { ref, defineExpose } from 'vue'

let bgColor = ref<string>(`rgb(37,41,46)`)

// 动态设置背景色透明度
const setBgColor = (v:number) => {
    bgColor.value = `rgba(37,41,46,${ v })`
}
defineExpose({ setBgColor })	//内部方法,供外部调用
</script>
<template>
    <div :style="{'background': bgColor}">
        <div>
            子组件代码...
        </div>
    </div>
</template>
### 在 Vue 3TypeScript 中从 TS 文件调用 Vue 组件方法Vue 3TypeScript 环境中,从一个单独的 TypeScript 文件调用 Vue 组件的方法可以通过多种方式实现。以下是两种常见的方式:使用模板引用(`ref`)和通过事件总线(Event Bus)。 #### 方法 1:通过模板引用(`ref`) 如果需要从外部 TypeScript 文件调用 Vue 组件的方法,可以先在 Vue 组件中暴露该方法通过 `ref` 获取组件实例。以下是一个完整的实现示例: **子组件 (`ChildComponent.vue`)**: ```vue <template> <div> <p>{{ message }}</p> </div> </template> <script lang="ts" setup> import { defineExpose } from &#39;vue&#39;; let message = &#39;Hello from Child Component&#39;; const updateMessage = (newMessage: string) => { message = newMessage; }; defineExpose({ updateMessage, }); </script> ``` **父组件或外部 TypeScript 文件 (`caller.ts`)**: ```typescript import { ref, nextTick } from &#39;vue&#39;; import ChildComponent from &#39;./ChildComponent.vue&#39;; const childRef = ref<InstanceType<typeof ChildComponent> | null>(null); // 假设这是在一个 Vue 组件的 setup 函数中 nextTick(() => { if (childRef.value) { childRef.value.updateMessage(&#39;Message updated from external file!&#39;); } }); ``` 注意:`childRef` 必须绑定到实际的组件实例上才能正常工作[^1]。 --- #### 方法 2:通过事件总线(Event Bus) 另一种方式是使用事件总线来触发 Vue 组件中的方法。这种方法适用于跨组件通信,尤其是当组件之间没有直接的父子关系时。 **创建事件总线 (`eventBus.ts`)**: ```typescript import mitt from &#39;mitt&#39;; const eventBus = mitt(); export default eventBus; ``` **子组件 (`ChildComponent.vue`)**: ```vue <template> <div> <p>{{ message }}</p> </div> </template> <script lang="ts" setup> import { onMounted, onUnmounted } from &#39;vue&#39;; import eventBus from &#39;./eventBus&#39;; let message = &#39;Hello from Child Component&#39;; const updateMessage = (newMessage: string) => { message = newMessage; }; onMounted(() => { eventBus.on(&#39;updateMessage&#39;, updateMessage); }); onUnmounted(() => { eventBus.off(&#39;updateMessage&#39;, updateMessage); }); </script> ``` **外部 TypeScript 文件 (`caller.ts`)**: ```typescript import eventBus from &#39;./eventBus&#39;; eventBus.emit(&#39;updateMessage&#39;, &#39;Message updated via Event Bus!&#39;); ``` 这种方法不依赖于组件的层级结构,因此更加灵活[^2]。 --- ### 注意事项 - 使用 `ref` 的方式需要确保组件已经挂载完成,否则可能会导致 `childRef.value` 为 `undefined`。 - 使用事件总线时需要注意清理事件监听器,以避免内存泄漏问题。 - 如果项目中使用了 Vuex 或 Pinia,也可以通过状态管理工具来实现类似的功能[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值