【问题标题】:AlpineJS x-data overwrittenAlpineJS x 数据被覆盖
【发布时间】:2021-07-27 16:34:03
【问题描述】:
我有以下 HTML 结构:
<div x-data="{selected: 0}">
<div x-data="{ open: false }"
@click="open = !open; selected !== 1 ? selected = 1 : selected = 0;"
>
test
</div>
<div x-data="{ open: false }"
@click="open = !open; selected !== 2 ? selected = 2 : selected = 0;"
>
test
</div>
</div>
问题是我在 div 子 x-data 中写入后,第一个带有所选 x-data 的 x-data 不再存在。我认为说我覆盖它是正确的。所以问题是,我怎样才能防止这种情况发生?我希望能够保持打开状态并更新所选内容。谢谢
【问题讨论】:
标签:
javascript
laravel
tailwind-css
alpine.js
【解决方案1】:
在 Alpine.js 中,您的数据被封装在组件内(这意味着没有父组件会看到它),嵌套组件也不会看到父组件数据。
目前,此功能不在路线图上。请参阅此 Github 讨论 here。
事件总线方法
一种方法是利用 Alpine.js $dispatch 魔术属性并在其他地方使用带有 x-on: 或 @ 别名的事件侦听器。
<!-- Parent component -->
<div id="papa" x-data="{isTired: false}" x-on:cry.window="isTired = true">
<span x-text="'Papa is tired: ' + isTired"></span>
<!-- New child component scope -->
<div id="baby" x-data="">
<button @click="$dispatch('cry')">Make Baby Cry</button>
</div>
</div>
CodePen Demo
这利用了本机浏览器事件bubbling and capturing。
状态管理存储方法
如果您熟悉 React 或 Vue.js 等框架,那么您可能熟悉 Redux 或 Vuex 等状态管理库。
Spruce 是类似 Alpine.js 的精简版本,它的好处是允许您轻松地在组件之间共享数据。
您可以在其getting started guide 中看到组件之间的通信示例。
【解决方案2】:
我昨天做了很多研究,是的,AlpineJS 不像 React/Vue/Angular 但我有一个可行的解决方案,这是这样的:
<div
x-data="{ count : 0 }"
x-init="$watch('count', val => $dispatch('new-count', val))"
x-on:increment="count++"
x-on:decrement="count--"
>
<div>In root component: <span x-text="count"></span></div>
<div
x-data="{ count: 0 }"
x-on:new-count.window="count = $event.detail"
>
<div>In nested component <span x-text="count"></span></div>
<button x-on:click="$dispatch('increment')">Increment</button>
<button x-on:click="$dispatch('decrement')">Decrement</button>
</div>
</div>
使用$dispatch 并在父级中使用$watch 并在其中使用另一个事件名称创建另一个$dispatch。难题的一部分是在window 级别上收听事件。不理想,但工作。我希望它对其他人也有帮助。
【解决方案3】:
Alpine.js 与 React 或 Vue 不同,不提供任何父子节点
通信模式或原语。 “高山组件”不
从父组件接收任何上下文,每个组件都有自己的
单独和独立的范围,这意味着嵌套不起作用
你会期望来自 Vue/React 甚至 JavaScript (JavaScript
有词法作用域,Alpine 没有)。
这意味着在 Alpine.js 中没有父子组件
通信仅“兄弟”组件通信。对于兄弟姐妹
通信,这种模式经常在 Caleb 的问题中提出(the
Alpine.js 的创建者)和其他贡献者是使用窗口或
文档作为事件总线。
来源:https://codewithhugo.com/alpinejs-component-communication-event-bus/
这是他们命名的代码示例:
<div x-data="{ isOpen: false }">
<!-- this component can be shown/hidden using a `toggle` event -->
<div
x-show="isOpen"
x-on:toggle.window="isOpen = !isOpen"
role="alert"
>
<p>This alert is toggled when `toggle` events are dispatched.</p>
<button @click="isOpen = false">close alert</button>
</div>
</div>
<div x-data="{}">
<p>The button in this component can toggle the "alert".</p>
<button @click="$dispatch('toggle')">Toggle alert</button>
</div>
<div x-data="{}">
<p>The button in this component can <strong>also</strong> toggle the "alert".</p>
<button @click="$dispatch('toggle')">Toggle alert 2</button>
</div>