我正在尝试获取一个可水平滚动的 DOM 元素并设置它的滚动位置。然而,即使我在分配后立即在
console.log()
中输出它的值,该属性似乎也没有更新它的值。
<script setup>
import {ref, watch} from 'vue';
const container = ref();
watch(container, () => {
console.log(container.value.scrollWidth); // Output: 1500
console.log(container.value.scrollLeft); // Output: 0
container.value.scrollLeft = 33;
console.log(container.value.scrollLeft); // ❌ Output: 0, Expected: 33
})
</script>
<template>
<div ref="container"></div>
</template>
仅供参考,我使用
watch()
而不是 onMounted()
因为我不知道滚动位置应该是什么,直到我在父组件中进行 fetch()
调用。下面给出了 <script>
部分的完整版本,但是可以将上面的版本扔到 vue playground 中并运行以显示问题。
我已经用谷歌搜索了这九种方法到星期天。我可以找到有关 Vue 2、Vue 3 Options API 或 Vue 3 Composition 的文章。我是 Vue 的新手,只使用过 Vue 3 Composition API。无论哪种方式,所有文章或堆栈溢出问题似乎都是关于使用模板引用访问(读取)DOM 元素,但它们没有显示如何为 DOM 元素属性赋值。就读取属性而言,上面的代码让我了解,但是当我尝试为属性分配一个新值时,该属性没有得到更新。
<script setup lang="ts">
import { ref, watch } from "vue";
import type { ProbeRequest } from "@/types/classes/ProbeRequest";
import type { ProbeRequestStatus } from "@/types/classes/ProbeRequestStatus";
import { buildTracker, getScrollPosition } from "./utils";
interface Props {
probeRequest: null | ProbeRequest;
}
const props = withDefaults(defineProps<Props>(), { probeRequest: null });
const tracker = ref<(ProbeRequestStatus | string)[]>([]);
const trackerContainer = ref();
watch(
() => props.probeRequest,
(probeRequest) => {
tracker.value = probeRequest ? buildTracker(probeRequest) : [];
if (tracker.value.length > 0) {
console.log(trackerContainer.value.scrollWidth);
console.log(trackerContainer.value.scrollLeft);
const scrollLeft = getScrollPosition(
tracker.value,
trackerContainer.value.scrollWidth
);
trackerContainer.value.scrollLeft = scrollLeft;
console.log(trackerContainer.value.scrollLeft);
}
}
);
</script>
这不是 dom 问题,我打赌你的
ref='container'
不可滚动:
更多:https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
所以问题是在第一次渲染时,容器没有溢出,因为没有内容(我在等待
tracker.value
成为一个包含多个元素的数组;那是在等待 props.probeRequest
有一个价值)。这意味着scrollLeft
必须是0
。 (值得注意的是,这也是为什么我的人为示例不起作用,因为它永远无法滚动)
一旦容器有了内容,我就需要等待它被渲染,然后才能为
scrollLeft
赋值。所以我不得不添加一个await nextTick()
(不知道那是一件事)。
代码现在看起来像这样:
<script setup lang="ts">
import { ref, watch, nextTick } from "vue";
import type { ProbeRequest } from "@/types/classes/ProbeRequest";
import type { ProbeRequestStatus } from "@/types/classes/ProbeRequestStatus";
import { buildTracker, getScrollPosition } from "./utils";
interface Props {
probeRequest: null | ProbeRequest;
}
const props = withDefaults(defineProps<Props>(), { probeRequest: null });
const tracker = ref<(ProbeRequestStatus | string)[]>([]);
const trackerContainer = ref<HTMLInputElement | null>(null);
watch(
() => props.probeRequest,
async (probeRequest) => {
tracker.value = probeRequest ? buildTracker(probeRequest) : [];
await nextTick() // ✅ Here is the magic sauce
if (trackerContainer.value && tracker.value.length > 0) {
console.log(trackerContainer.value.scrollWidth);
console.log(trackerContainer.value.scrollLeft);
const scrollLeft = getScrollPosition(
tracker.value,
trackerContainer.value.scrollWidth
);
trackerContainer.value.scrollLeft = scrollLeft;
console.log(trackerContainer.value.scrollLeft);
}
}
);
</script>
感谢@tachibana-shin 的灵感!