将 Alpine .js与'static'服务器端标记混合,同时获得绑定等的好处



我是Alpine的新手,正在努力思考如何使这样的场景发挥作用:

假设我有一个服务器端构建的页面,它包含一些按钮,代表新闻通讯,用户可以注册。用户可能已经注册了一些,我们也需要通过添加一个css类来指出这一点。eis-signed-up.

初始服务器端标记可以像这样:

<button id='newsletter-1' class='newsletter-signup'>Newsletter 1</button>
<div>some content here...</div>
<button id='newsletter-2' class='newsletter-signup'>Newsletter 2</button>
<div>more content here...</div>
<button id='newsletter-3' class='newsletter-signup'>Newsletter 3</button>
<div>and here...</div>
<button id='newsletter-4' class='newsletter-signup'>Newsletter 4</button>

(当所有加载完成后,<button>应该允许用户直接订阅或取消订阅时事通讯,通过点击其中一个按钮,这应该相应地切换is-signed-up的css-class。)

然后,我从端点获取json,可以是这样的

{"newsletters":[    
{"newsletter":"newsletter-1"},  
{"newsletter":"newsletter-2"},
{"newsletter":"newsletter-4"} 
]}

我猜它也可以是这样的:

{"newsletters":["newsletter-1", "newsletter-2", "newsletter-4"]}

或其他结构,但情况是,用户已经注册了时事通讯1,2和4,但不是时事通讯3,我们不知道,直到我们从端点获得JSON。

(但也许第一个变化更容易映射到一个模型,我猜…)

无论如何,我想做三件事:

  1. 让Alpine获取具有特定newsletter id的模型和dom元素之间的关系。'newsletter-2') -即使模型中不存在确切的id。
  2. 如果用户已经注册了时事通讯,将is-signed-upcss-class添加到相应的<button>中,向用户显示其状态。
  3. 绑定到每个时事通讯按钮,所以所有的-不仅仅是那些,用户已经注册-听一个"点击",并相应地更新模型。

我有一个想法,我可能需要事先"准备"每个新闻通讯按钮与一些阿尔卑斯属性,如'x-model='newsletter-2',但我仍然不确定如何将它们绑定在一起时,阿尔卑斯有初始化,我有来自端点的数据,

我该如何处理这样的事情?

提前感谢!😊

所以我们这里的基本任务是在单击按钮时向列表添加/删除特定项。这里我定义了两个组件:newsletter组件使用Alpine.data()创建数据(subs数组),提供切换方法(toggle_subscription(which))和检查方法(is_subscribed(which)),我们可以使用它们为按钮设置正确的CSS类。它还处理init()方法中的数据获取,该方法在组件初始化后自动执行。我还创建了一个save方法,我们可以使用它将订阅列表发送回后端。

第二个组件subButtonAlpine.bind()只是为了使HTML代码更紧凑和可读。(我们可以将其中的每个属性直接放到按钮中。)因此,在点击事件时,它调用toggle_subscription,并将当前时事通讯的键作为参数来添加/删除它。此外,如果当前的时事通讯在列表中,它将bg-redCSS类绑定到按钮。为此,我们使用在主组件中定义的is_subscribed方法。

.bg-red {
background-color: Tomato;
}
<script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
<div x-data="newsletter">
<button x-bind="subButton('newsletter-1')">Newsletter 1</button>
<button x-bind="subButton('newsletter-2')">Newsletter 2</button>
<button x-bind="subButton('newsletter-3')">Newsletter 3</button>
<button x-bind="subButton('newsletter-4')">Newsletter 4</button>

<div>
<button @click="save">Save</button>
</div>
</div>

<script>
document.addEventListener('alpine:init', () => {
Alpine.data('newsletter', () => ({
subs: [],
init() {
// Fetch list of subscribed newsletters from backend
this.subs = ['newsletter-1', 'newsletter-2', 'newsletter-4']
},
toggle_subscription(which) {
if (this.subs.includes(which)) {
this.subs = this.subs.filter(item => item !== which)
}
else {
this.subs.push(which)
}
},
is_subscribed(which) {
return this.subs.includes(which)
},

save() {
// Send this.sub to the backend to save active state.
}
}))
Alpine.bind('subButton', (key) => ({
'@click'() {
this.toggle_subscription(key)
},
':class'() {
return this.is_subscribed(key) && 'bg-red'
}
}))
})
</script>

最新更新