在 Svelte 中重新渲染布局后执行功能
Execute function after layout re-render in Svelte
我想在 svelte 中单击 table 行时创建一个弹出菜单。我使用 document.querySelectorAll
方法将 onclick 事件添加到 onMount
内的每个 table 行。在 onMount
函数中,我还重新渲染显示的 table。如何将 onclick 值应用于重新呈现的元素?
onMount(() => {
console.log(document.querySelectorAll(".results .table table tbody tr"));
/* -> returns array with only 1 element -> not correct */
/* ... re-render logic here */
}
但是当我添加超时时:
onMount(() => {
setTimeout(() => {
console.log(document.querySelectorAll(".results .table table tbody tr"));
}, 5000);
/* -> returns array with all elements */
/* ... re-render logic here again */
}
可以找到具有完整源代码的 REPL here
我正在写一些想法,但是评论太长了。
你在 Svelte 可以为你做的 REPL 中做了相当多的额外工作。我同意@voscausa 的观点,您应该将事件委托给 table
。在 Svelte 中,你几乎不必使用 document.querySelector
。您正在遍历所有行两次。您所有的事件侦听器附件都应该是标记中的属性,而不是 JS 中的附件,也不是初始化函数中的附件(因此事件委托给 table)。您一直在监视鼠标位置,但您只在 onclick
中使用它,这是一个 MouseEvent
并且可以访问 X 和 Y 数据。
将点击监听器切换到容器:
<div class="results" on:click={handleClick}> ... </div>
<script>
function handleClick(e) {
const tr = e.target.closest('tr');
const td = e.target.closest('td');
if (td) {
/* code */
} else {
/* code */
}
}
</script>
如果您需要它出现在整个文档中,您可以使用 <svelte:window>
而不是 .results
。
要更新 .option
div 的 css,请执行如下操作:
<div class="options" style=`left:${optionsStyle.left}px;top:${optionsStyle.top}px`> ... </div>
<script>
let optionsStyle = {left: 0, top: 0};
function handleClick(e) {
/* code */
let left = 0, right = 0;
/* calculate left and right here */
optionsStyle = {left: e.clientX, top: e.clientY};
/* code */
}
</script>
要切换 classes,请参阅 class directive。您可以在一个元素上有多个 class 指令。 (显然,我没有在这里完成所有逻辑。)
<div class="options" class:expand={optionsExpand}> ... </div>
<script>
let optionsExpand = false;
function handleClick(e) {
const tr = e.target.closest('tr');
const td = e.target.closest('td');
if (td) {
/* code */
optionsExpand = true;
} else {
/* code */
optionsExpand = false;
}
}
</script>
我个人会将选项弹出窗口变成它自己的组件,并将 optionsExpand
布尔值作为道具传递。
像我在这里描述的那样做会让你以 Svelte 的思维方式思考,它会简化你的代码,你不需要超时,你也不需要 afterUpdates
函数.
我想在 svelte 中单击 table 行时创建一个弹出菜单。我使用 document.querySelectorAll
方法将 onclick 事件添加到 onMount
内的每个 table 行。在 onMount
函数中,我还重新渲染显示的 table。如何将 onclick 值应用于重新呈现的元素?
onMount(() => {
console.log(document.querySelectorAll(".results .table table tbody tr"));
/* -> returns array with only 1 element -> not correct */
/* ... re-render logic here */
}
但是当我添加超时时:
onMount(() => {
setTimeout(() => {
console.log(document.querySelectorAll(".results .table table tbody tr"));
}, 5000);
/* -> returns array with all elements */
/* ... re-render logic here again */
}
可以找到具有完整源代码的 REPL here
我正在写一些想法,但是评论太长了。
你在 Svelte 可以为你做的 REPL 中做了相当多的额外工作。我同意@voscausa 的观点,您应该将事件委托给 table
。在 Svelte 中,你几乎不必使用 document.querySelector
。您正在遍历所有行两次。您所有的事件侦听器附件都应该是标记中的属性,而不是 JS 中的附件,也不是初始化函数中的附件(因此事件委托给 table)。您一直在监视鼠标位置,但您只在 onclick
中使用它,这是一个 MouseEvent
并且可以访问 X 和 Y 数据。
将点击监听器切换到容器:
<div class="results" on:click={handleClick}> ... </div>
<script>
function handleClick(e) {
const tr = e.target.closest('tr');
const td = e.target.closest('td');
if (td) {
/* code */
} else {
/* code */
}
}
</script>
如果您需要它出现在整个文档中,您可以使用 <svelte:window>
而不是 .results
。
要更新 .option
div 的 css,请执行如下操作:
<div class="options" style=`left:${optionsStyle.left}px;top:${optionsStyle.top}px`> ... </div>
<script>
let optionsStyle = {left: 0, top: 0};
function handleClick(e) {
/* code */
let left = 0, right = 0;
/* calculate left and right here */
optionsStyle = {left: e.clientX, top: e.clientY};
/* code */
}
</script>
要切换 classes,请参阅 class directive。您可以在一个元素上有多个 class 指令。 (显然,我没有在这里完成所有逻辑。)
<div class="options" class:expand={optionsExpand}> ... </div>
<script>
let optionsExpand = false;
function handleClick(e) {
const tr = e.target.closest('tr');
const td = e.target.closest('td');
if (td) {
/* code */
optionsExpand = true;
} else {
/* code */
optionsExpand = false;
}
}
</script>
我个人会将选项弹出窗口变成它自己的组件,并将 optionsExpand
布尔值作为道具传递。
像我在这里描述的那样做会让你以 Svelte 的思维方式思考,它会简化你的代码,你不需要超时,你也不需要 afterUpdates
函数.