我是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。
(但也许第一个变化更容易映射到一个模型,我猜…)
无论如何,我想做三件事:
- 让Alpine获取具有特定newsletter id的模型和dom元素之间的关系。'newsletter-2') -即使模型中不存在确切的id。
- 如果用户已经注册了时事通讯,将
is-signed-up
css-class添加到相应的<button>
中,向用户显示其状态。 - 绑定到每个时事通讯按钮,所以所有的-不仅仅是那些,用户已经注册-听一个"点击",并相应地更新模型。
我有一个想法,我可能需要事先"准备"每个新闻通讯按钮与一些阿尔卑斯属性,如'x-model='newsletter-2'
,但我仍然不确定如何将它们绑定在一起时,阿尔卑斯有初始化,我有来自端点的数据,
我该如何处理这样的事情?
提前感谢!😊
所以我们这里的基本任务是在单击按钮时向列表添加/删除特定项。这里我定义了两个组件:newsletter
组件使用Alpine.data()
创建数据(subs
数组),提供切换方法(toggle_subscription(which)
)和检查方法(is_subscribed(which)
),我们可以使用它们为按钮设置正确的CSS类。它还处理init()
方法中的数据获取,该方法在组件初始化后自动执行。我还创建了一个save
方法,我们可以使用它将订阅列表发送回后端。
第二个组件subButton
和Alpine.bind()
只是为了使HTML代码更紧凑和可读。(我们可以将其中的每个属性直接放到按钮中。)因此,在点击事件时,它调用toggle_subscription
,并将当前时事通讯的键作为参数来添加/删除它。此外,如果当前的时事通讯在列表中,它将bg-red
CSS类绑定到按钮。为此,我们使用在主组件中定义的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>