如何从子组件访问alpine.js父组件的属性或方法?

时间:2020-06-27 15:54:49

标签: javascript alpine.js

这是问题看起来像的一个示例场景,

<div x-data="{ count : 0 }">
    <div x-data>
        <span x-text="count"></span>
        <button x-on:click="count++">Increment</button>
        <button x-on:click="count--">Decrement</button>         
    </div>
</div>

它将能够增加/减少子组件中的数据count。 我曾想过通过使用$dispatch()调度自定义事件来处理它,但是再次在设计方面,我可能需要在父组件和子组件上编写侦听器,这会使逻辑更加复杂,因为它也应该是响应式的。 / p>

有一个Github issue,并且所有提议的解决方案都没有用。

1 个答案:

答案 0 :(得分:3)

我曾考虑通过使用$ dispatch()调度自定义事件来处理它,但随后在设计方面,我可能需要在父组件和子组件上编写侦听器,这会使逻辑更加复杂,因为它也应该是响应式的

这是问题的症结所在,为了进行父子子母沟通,您需要使用事件。对于子级->父级,您将触发incrementdecrement事件(将使用x-on:incrementx-on:decrement在父级组件中监听事件)。对于父级->子级,每当$watch个更新(我将使用count事件名称)时,您都需要使用new-count来触发更新,这将被侦听在window上使用x-on:new-count.window子组件。

这是完整的工作解决方案(将其视为CodePen):

<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>

在您介绍的情况下,通过使用与Alpine.js集成的全局存储(例如Spruce)可以更好地满足count状态,在这种情况下,我们将阅读并更新父组件和子组件都订阅到的共享全局存储(请参见Spruce文档)。您可以在下面的CodePen中找到工作示例。

<div x-data x-subscribe="count">
  <div>In root component: <span x-text="$store.count"></span></div>
  <div x-data x-subscribe="count">
    <div>In nested component <span x-text="$store.count"></span></div>
    <button x-on:click="$store.count ++">Increment</button>
    <button x-on:click="$store.count--">Decrement</button>
  </div>
</div>
<script>
  Spruce.store('count', 0);
</script>

最后要提到的解决方案是,删除嵌套组件将意味着计数增加和减少将按预期工作。显然,此示例可能已简化并且仅是示例性的,因此该解决方案在许多情况下可能不起作用。注意:唯一的区别是删除了第二个x-data

<div x-data="{ count : 0 }">
    <div>
        <span x-text="count"></span>
        <button x-on:click="count++">Increment</button>
        <button x-on:click="count--">Decrement</button>         
    </div>
</div>