英文:
Why Alpine.js magic inside x-data isn't reactive?
问题
我在Alpine.js中编写了我的第一个魔术功能。它返回页面滚动比例,一个介于0-1之间的数字,最终带有一个scale
(例如100以获取百分比)和一个round
:
/**
* @param {import("alpinejs").Alpine} Alpine
*/
export default (Alpine) => {
const data = Alpine.reactive({ ratio: 0 });
const calculate = () =>
(document.documentElement.scrollTop || document.body.scrollTop) /
((document.documentElement.scrollHeight || document.body.scrollHeight) -
document.documentElement.clientHeight) || 0;
const update = () => (data.ratio = calculate());
window.addEventListener('load', update);
window.addEventListener('scroll', update, { passive: true });
Alpine.magic('pageScroll', () => (scale, round) => {
let value = data.ratio;
if (!isNaN(scale)) {
value *= scale;
}
if (!isNaN(round)) {
value = value.toFixed(round);
}
return value;
});
};
使用x-bind
(请参见此示例并滚动页面)运行得很好:
<div class="fixed top-0 left-0 w-4 bg-red-500 duration-100"
x-data x-bind:style="{ height: $pageScroll(100) + '%' }">
</div>
问题出现在我尝试将$pageScroll(100)
分配给组件的ratio
属性时(以便重用它),魔术不再具有反应性:
<div class="fixed top-0 right-0 w-4 bg-green-500 duration-100"
x-data="{ scroll: $pageScroll(100) }"
x-bind:style="{ height: scroll + '%' }"
x-text="scroll">
</div>
有人知道这是否是正常行为以及如何解决这个问题吗?
由于魔术注册了一个事件监听器,附加到x-bind
和x-text
都会创建更多监听器,从而降低性能。
英文:
I wrote my first magic in Alpine.js. It returns the page scroll ratio, a number between 0-1, eventually with a scale
(i.e. 100 to get the percenteage) and a round
:
/**
* @param {import("alpinejs").Alpine} Alpine
*/
export default (Alpine) => {
const data = Alpine.reactive({ ratio: 0 });
const calculate = () =>
(document.documentElement.scrollTop || document.body.scrollTop) /
((document.documentElement.scrollHeight || document.body.scrollHeight) -
document.documentElement.clientHeight) || 0;
const update = () => (data.ratio = calculate());
window.addEventListener('load', update);
window.addEventListener('scroll', update, { passive: true });
Alpine.magic('pageScroll', () => (scale, round) => {
let value = data.ratio;
if (!isNaN(scale)) {
value *= scale;
}
if (!isNaN(round)) {
value = value.toFixed(round);
}
return value;
});
};
Works just fine using x-bind
(see this pen and scroll the page):
<div class="fixed top-0 left-0 w-4 bg-red-500 duration-100"
x-data x-bind:style="{ height: $pageScroll(100) + '%' }">
</div>
The problem is when I try to assign the $pageScroll(100)
to a ratio
property of the component (in order to reuse it), the magic isn't reactive anymore:
<div class="fixed top-0 right-0 w-4 bg-green-500 duration-100"
x-data="{ scroll: $pageScroll(100) }"
x-bind:style="{ height: scroll + '%' }"
x-text="scroll">
</div>
Does anyone know if this is the normal behaviour and how can I solve the problem?
Since the magic register an event listener, attaching to both x-bind
and x-text
would create more listeners, degrading performances.
答案1
得分: 1
魔法属性在定义 x-data 时不可用,因为 x-data 在组件上下文 (this) 存在之前运行。
这里 有一篇关于这个主题的好文章,我从中摘取了引用的短语。
您可以尝试使用 init() 函数来解决这个问题,我认为这样的解决方案可能有效(我现在无法测试):
<div class="fixed top-0 right-0 w-4 bg-green-500 duration-100"
x-data="{ scroll: 0, scale: 100 }"
x-init="scroll = $pageScroll(scale)"
x-bind:style="{ height: scroll + ''%' }"
x-text="scroll"
>
</div>
英文:
The magic properties are not available when defining x-data "since x-data is run before the component context (this) exists"
Here a good article on the subject from which I extracted the quoted phrase
You can try to work around the problem using the init() function, I think that a solution like this can work (I can't test it now):
<div class="fixed top-0 right-0 w-4 bg-green-500 duration-100"
x-data="{ scroll: 0, scale: 100 }"
x-init="scroll = $pageScroll(scale)"
x-bind:style="{ height: scroll + '%' }"
x-text="scroll"
>
</div>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论