尝试调整组件的大小 onUpdate
Trying to resize a component onUpdate
我编写了一个组件,如果 div 中有 space 足够的宽度可用,它会将数组中的字符串呈现为 div 中的跨度。
调用 renderDinos() 方法 onMount() 按预期工作。从那里我想更新组件以在 div 的宽度发生变化时动态地重新呈现 div 中的字符串(从数组中添加或减去字符串)。
为了实现这一点,如果组件的宽度发生变化,我将在 afterUpdate() 中再次调用 renderDinos() 。当onMount()运行时scrollWidth是恐龙的宽度[i]所以scrollWidthSum计算准确。
当 afterUpdate() 调用相同的方法时,scrollWidth 的初始值为 0,而不是恐龙 [i] 的宽度。这会打乱 scrollWidthSum 的计算。我还想从 if 块中的 currentWidth 中减去 scrollWidth,以便更好地对齐子项,但是,再次;当我从 onUpdate 调用方法时,该值最初为 0。
有办法解决吗? div 调整大小时,是否有更简单的方法重新呈现其内容?
<script>
import { onMount, tick, afterUpdate } from 'svelte'
let dinosaurs = [
'dinosaur1',
'dinosaur2',
'dinosaur3',
'dinosaur4',
'dinosaur5',
]
let currentWidth = 0,
previousWidth = 0,
scrollWidth,
scrollWidthSum
$: dinosToShow = []
onMount(async () => {
previousWidth = currentWidth
renderDinos()
})
afterUpdate(() => {
if (previousWidth != currentWidth) {
renderDinos()
previousWidth = currentWidth
}
})
async function renderDinos() {
dinosToShow = []
scrollWidthSum = 0
scrollWidth = 0
for (let i = 0; i < dinosaurs.length; i++) {
dinosToShow = [...dinosToShow, `${dinosaurs[i]},\xa0`]
await tick()
console.log(scrollWidth)
scrollWidthSum += scrollWidth
if (scrollWidthSum > currentWidth - 60) {
dinosToShow.pop()
await tick()
break
}
}
}
</script>
<style>
.display {
overflow: hidden;
}
.dinosaur {
display: inline-block;
}
</style>
<div class="display" bind:clientWidth={currentWidth}>
{#each dinosToShow as r}
<span bind:clientWidth={scrollWidth} class="dinosaur">{r}</span>
{/each}
</div>
您将每个跨度的 clientWidth 绑定到同一个变量,随着每个循环的进行而更改它,这被认为是一种不好的做法。
我认为做这样的事情会更好(添加评论以获得一些解释):
<script>
let dinosaurs = [
'dinosaur1',
'dinosaur2',
'dinosaur3',
'dinosaur4',
'dinosaur5',
]
let currentWidth = 0;
// have the array updated when currentWidth updates
$: dinosToShow = render(currentWidth);
function render(currentWidth) {
// Early return
if (currentWidth == 0) return [];
let i = 0;
let sumWidth = 0;
// While instead of for, removes the need for breaks
while(i < dinosaurs.length && sumWidth < currentWidth) {
// Create a dummy span and add it somewhere far off screen
let span = document.createElement('span')
span.classList.add('dinosaur')
span.textContent = `${dinosaurs[i]},\xa0`
span.style = "visibility: hidden; position: fixed; top: -1000;";
document.body.appendChild(span);
// Sum the width of the dummy elements
sumWidth += span.getBoundingClientRect().width
// Remove the dummy again
document.body.removeChild(span)
// if the sum with the dummy is less than the current width do i + 1
// this will effectively include this dino in the list
if (sumWidth < currentWidth) {
i++
}
}
// return the subarray that fits.
// note that if sumWidth > currentWidth this will NOT include the dino that was too big
return dinosaurs.slice(0, i)
}
</script>
<div class="display" bind:clientWidth={currentWidth}>
{#each dinosToShow as r}
<!-- No binding of stuff here -->
<span class="dinosaur">{r}</span>
{/each}
</div>
<style>
.display {
overflow: hidden;
}
.dinosaur {
display: inline-block;
}
</style>
我编写了一个组件,如果 div 中有 space 足够的宽度可用,它会将数组中的字符串呈现为 div 中的跨度。
调用 renderDinos() 方法 onMount() 按预期工作。从那里我想更新组件以在 div 的宽度发生变化时动态地重新呈现 div 中的字符串(从数组中添加或减去字符串)。
为了实现这一点,如果组件的宽度发生变化,我将在 afterUpdate() 中再次调用 renderDinos() 。当onMount()运行时scrollWidth是恐龙的宽度[i]所以scrollWidthSum计算准确。
当 afterUpdate() 调用相同的方法时,scrollWidth 的初始值为 0,而不是恐龙 [i] 的宽度。这会打乱 scrollWidthSum 的计算。我还想从 if 块中的 currentWidth 中减去 scrollWidth,以便更好地对齐子项,但是,再次;当我从 onUpdate 调用方法时,该值最初为 0。
有办法解决吗? div 调整大小时,是否有更简单的方法重新呈现其内容?
<script>
import { onMount, tick, afterUpdate } from 'svelte'
let dinosaurs = [
'dinosaur1',
'dinosaur2',
'dinosaur3',
'dinosaur4',
'dinosaur5',
]
let currentWidth = 0,
previousWidth = 0,
scrollWidth,
scrollWidthSum
$: dinosToShow = []
onMount(async () => {
previousWidth = currentWidth
renderDinos()
})
afterUpdate(() => {
if (previousWidth != currentWidth) {
renderDinos()
previousWidth = currentWidth
}
})
async function renderDinos() {
dinosToShow = []
scrollWidthSum = 0
scrollWidth = 0
for (let i = 0; i < dinosaurs.length; i++) {
dinosToShow = [...dinosToShow, `${dinosaurs[i]},\xa0`]
await tick()
console.log(scrollWidth)
scrollWidthSum += scrollWidth
if (scrollWidthSum > currentWidth - 60) {
dinosToShow.pop()
await tick()
break
}
}
}
</script>
<style>
.display {
overflow: hidden;
}
.dinosaur {
display: inline-block;
}
</style>
<div class="display" bind:clientWidth={currentWidth}>
{#each dinosToShow as r}
<span bind:clientWidth={scrollWidth} class="dinosaur">{r}</span>
{/each}
</div>
您将每个跨度的 clientWidth 绑定到同一个变量,随着每个循环的进行而更改它,这被认为是一种不好的做法。
我认为做这样的事情会更好(添加评论以获得一些解释):
<script>
let dinosaurs = [
'dinosaur1',
'dinosaur2',
'dinosaur3',
'dinosaur4',
'dinosaur5',
]
let currentWidth = 0;
// have the array updated when currentWidth updates
$: dinosToShow = render(currentWidth);
function render(currentWidth) {
// Early return
if (currentWidth == 0) return [];
let i = 0;
let sumWidth = 0;
// While instead of for, removes the need for breaks
while(i < dinosaurs.length && sumWidth < currentWidth) {
// Create a dummy span and add it somewhere far off screen
let span = document.createElement('span')
span.classList.add('dinosaur')
span.textContent = `${dinosaurs[i]},\xa0`
span.style = "visibility: hidden; position: fixed; top: -1000;";
document.body.appendChild(span);
// Sum the width of the dummy elements
sumWidth += span.getBoundingClientRect().width
// Remove the dummy again
document.body.removeChild(span)
// if the sum with the dummy is less than the current width do i + 1
// this will effectively include this dino in the list
if (sumWidth < currentWidth) {
i++
}
}
// return the subarray that fits.
// note that if sumWidth > currentWidth this will NOT include the dino that was too big
return dinosaurs.slice(0, i)
}
</script>
<div class="display" bind:clientWidth={currentWidth}>
{#each dinosToShow as r}
<!-- No binding of stuff here -->
<span class="dinosaur">{r}</span>
{/each}
</div>
<style>
.display {
overflow: hidden;
}
.dinosaur {
display: inline-block;
}
</style>