可重用 Alpine.js 组件?
Reusable Alpine.js components?
如何使用 Alpine.js 创建可重用组件并显示它?例如,也许我想定义一个通用的 Alpine.js 按钮组件,它根据参数更改文本和颜色,然后让我的 Alpine.js 导航栏组件使用按钮组件显示登录按钮。
我可以在纯客户端代码中执行此操作,而不依赖服务器模板化所有按钮 HTML 在所有使用按钮组件的地方吗?
Alpine.js 贡献者@ryangjchandler 评论说可重用模板超出了 Alpine.js:
的范围
The proposed [Alpine.js version 3] x-component directive will NOT have anything to do with templating or the markup for your component. Instead it will provide a way of writing more immediately reusable data sets & functions, whilst reducing the amount of directives you need to define in your markup.
If you need re-usable templates, I would consider using a server-side template engine or a more monolithic front end framework such as Vue or React. (link)
和
The functionality you are looking for is far out of the scope of Alpine. It's designed to work alongside your existing markup from the server or static files, not replace / component-ise your markup. (link)
Can I do this in pure client-side code, without relying on a server templating?
是的,你可以。
Alpine.js 总是会尝试 persuade 您使用服务器端模板引擎。
但就像你一样,我不让自己被说服:
<template x-component="dropdown">
<div x-data="{ ...dropdown(), ...$el.parentElement.data() }">
<button x-on:click="open">Open</button>
<div x-show="isOpen()" x-on:click.away="close" x-text="content"></div>
</div>
</template>
<x-dropdown content="Content for my first dropdown"></x-dropdown>
<div> Random stuff... </div>
<x-dropdown content="Content for my second dropdown"></x-dropdown>
<x-dropdown></x-dropdown>
<script>
function dropdown() {
return {
show: false,
open() { this.show = true },
close() { this.show = false },
isOpen() { return this.show === true },
content: 'Default content'
}
}
// The pure client-side code
document.querySelectorAll('[x-component]').forEach(component => {
const componentName = `x-${component.getAttribute('x-component')}`
class Component extends HTMLElement {
connectedCallback() {
this.append(component.content.cloneNode(true))
}
data() {
const attributes = this.getAttributeNames()
const data = {}
attributes.forEach(attribute => {
data[attribute] = this.getAttribute(attribute)
})
return data
}
}
customElements.define(componentName, Component)
})
</script>
使用 Alpine.js v3 和全局 Alpine 组件,您可以使用 Alpine.component() 来封装此功能。
<div x-data="dropdown">
...
</div>
<script>
Alpine.component('dropdown', () => ({
open: false,
toggle() { this.open = !this.open }
}))
</script>
使用alpinejs-component
cdn 同一页面:
<div
x-data="{
people: [
{ name: 'John', age: '25', skills: ['JavaScript', 'CSS'] },
{ name: 'Jane', age: '30', skills: ['Laravel', 'MySQL', 'jQuery'] }
]
}"
>
<ul>
<template x-for="person in people">
<!-- use the person template to find the <template id="person"> element. -->
<x-component-wrapper x-component template="person" x-data="{ item: person }"></x-component-wrapper>
</template>
</ul>
</div>
<template id="person">
<li class="user-card">
<h2 x-text="item.name"></h2>
<p x-text="item.age"></p>
<ul>
<template x-for="skill in item.skills">
<li x-text="skill"></li>
</template>
</ul>
</li>
</template>
<script src="https://unpkg.com/alpinejs-component@1.x.x/dist/component.min.js"></script>
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
使用url导入html模板:
<div
x-data="{
people: [
{ name: 'John', age: '25', skills: ['JavaScript', 'CSS'] },
{ name: 'Jane', age: '30', skills: ['Laravel', 'MySQL', 'jQuery'] }
]
}"
>
<ul>
<template x-for="person in people">
<x-component-wrapper x-component url="/public/person.html" x-data="{ item: person }"></x-component-wrapper>
</template>
</ul>
</div>
<script src="https://unpkg.com/alpinejs-component@1.x.x/dist/component.min.js"></script>
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
person.html
:
<li class="user-card">
<h2 x-text="item.name"></h2>
<p x-text="item.age"></p>
<ul>
<template x-for="skill in item.skills">
<li x-text="skill"></li>
</template>
</ul>
</li>
通过 npm 安装:
npm i -D alpinejs-component
yarn add -D alpinejs-component
注册插件:
import Alpine from "alpinejs";
import component from "alpinejs-component";
Alpine.plugin(component);
window.Alpine = Alpine;
Alpine.start();
或在浏览器中使用模块:
<x-component-wrapper x-component template="dropdown" x-data="dropdown"></x-component-wrapper>
<x-component-wrapper x-component template="dropdown" x-data="dropdown"></x-component-wrapper>
<template id="dropdown">
<div @click="close" class="dropdown-toggle">
<button x-on:click="open">Open</button>
<div x-show="show" x-text="content"></div>
</div>
</template>
<script type="module">
import { default as Alpine } from 'https://cdn.skypack.dev/alpinejs'
import alpinejsComponent from 'https://cdn.skypack.dev/alpinejs-component'
function dropdown() {
return {
show: false,
open() {
console.log('open')
this.show = true
console.log(this.show)
},
close(event) {
const button = this.$el.querySelector('button')
const target = event.target
if (this.$el.contains(target) && !button.contains(target)) {
this.show = false
}
},
get isOpen() {
return this.show === true
},
content: 'Default content',
init() {
console.log(this.$el.parentElement)
console.log('dropdown --- init')
},
}
}
Alpine.data('dropdown', dropdown)
Alpine.plugin(alpinejsComponent)
Alpine.start()
</script>
工作顺利。
如何使用 Alpine.js 创建可重用组件并显示它?例如,也许我想定义一个通用的 Alpine.js 按钮组件,它根据参数更改文本和颜色,然后让我的 Alpine.js 导航栏组件使用按钮组件显示登录按钮。
我可以在纯客户端代码中执行此操作,而不依赖服务器模板化所有按钮 HTML 在所有使用按钮组件的地方吗?
Alpine.js 贡献者@ryangjchandler 评论说可重用模板超出了 Alpine.js:
的范围The proposed [Alpine.js version 3] x-component directive will NOT have anything to do with templating or the markup for your component. Instead it will provide a way of writing more immediately reusable data sets & functions, whilst reducing the amount of directives you need to define in your markup.
If you need re-usable templates, I would consider using a server-side template engine or a more monolithic front end framework such as Vue or React. (link)
和
The functionality you are looking for is far out of the scope of Alpine. It's designed to work alongside your existing markup from the server or static files, not replace / component-ise your markup. (link)
Can I do this in pure client-side code, without relying on a server templating?
是的,你可以。
Alpine.js 总是会尝试 persuade 您使用服务器端模板引擎。
但就像你一样,我不让自己被说服:
<template x-component="dropdown">
<div x-data="{ ...dropdown(), ...$el.parentElement.data() }">
<button x-on:click="open">Open</button>
<div x-show="isOpen()" x-on:click.away="close" x-text="content"></div>
</div>
</template>
<x-dropdown content="Content for my first dropdown"></x-dropdown>
<div> Random stuff... </div>
<x-dropdown content="Content for my second dropdown"></x-dropdown>
<x-dropdown></x-dropdown>
<script>
function dropdown() {
return {
show: false,
open() { this.show = true },
close() { this.show = false },
isOpen() { return this.show === true },
content: 'Default content'
}
}
// The pure client-side code
document.querySelectorAll('[x-component]').forEach(component => {
const componentName = `x-${component.getAttribute('x-component')}`
class Component extends HTMLElement {
connectedCallback() {
this.append(component.content.cloneNode(true))
}
data() {
const attributes = this.getAttributeNames()
const data = {}
attributes.forEach(attribute => {
data[attribute] = this.getAttribute(attribute)
})
return data
}
}
customElements.define(componentName, Component)
})
</script>
使用 Alpine.js v3 和全局 Alpine 组件,您可以使用 Alpine.component() 来封装此功能。
<div x-data="dropdown">
...
</div>
<script>
Alpine.component('dropdown', () => ({
open: false,
toggle() { this.open = !this.open }
}))
</script>
使用alpinejs-component
cdn 同一页面:
<div
x-data="{
people: [
{ name: 'John', age: '25', skills: ['JavaScript', 'CSS'] },
{ name: 'Jane', age: '30', skills: ['Laravel', 'MySQL', 'jQuery'] }
]
}"
>
<ul>
<template x-for="person in people">
<!-- use the person template to find the <template id="person"> element. -->
<x-component-wrapper x-component template="person" x-data="{ item: person }"></x-component-wrapper>
</template>
</ul>
</div>
<template id="person">
<li class="user-card">
<h2 x-text="item.name"></h2>
<p x-text="item.age"></p>
<ul>
<template x-for="skill in item.skills">
<li x-text="skill"></li>
</template>
</ul>
</li>
</template>
<script src="https://unpkg.com/alpinejs-component@1.x.x/dist/component.min.js"></script>
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
使用url导入html模板:
<div
x-data="{
people: [
{ name: 'John', age: '25', skills: ['JavaScript', 'CSS'] },
{ name: 'Jane', age: '30', skills: ['Laravel', 'MySQL', 'jQuery'] }
]
}"
>
<ul>
<template x-for="person in people">
<x-component-wrapper x-component url="/public/person.html" x-data="{ item: person }"></x-component-wrapper>
</template>
</ul>
</div>
<script src="https://unpkg.com/alpinejs-component@1.x.x/dist/component.min.js"></script>
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
person.html
:
<li class="user-card">
<h2 x-text="item.name"></h2>
<p x-text="item.age"></p>
<ul>
<template x-for="skill in item.skills">
<li x-text="skill"></li>
</template>
</ul>
</li>
通过 npm 安装:
npm i -D alpinejs-component
yarn add -D alpinejs-component
注册插件:
import Alpine from "alpinejs";
import component from "alpinejs-component";
Alpine.plugin(component);
window.Alpine = Alpine;
Alpine.start();
或在浏览器中使用模块:
<x-component-wrapper x-component template="dropdown" x-data="dropdown"></x-component-wrapper>
<x-component-wrapper x-component template="dropdown" x-data="dropdown"></x-component-wrapper>
<template id="dropdown">
<div @click="close" class="dropdown-toggle">
<button x-on:click="open">Open</button>
<div x-show="show" x-text="content"></div>
</div>
</template>
<script type="module">
import { default as Alpine } from 'https://cdn.skypack.dev/alpinejs'
import alpinejsComponent from 'https://cdn.skypack.dev/alpinejs-component'
function dropdown() {
return {
show: false,
open() {
console.log('open')
this.show = true
console.log(this.show)
},
close(event) {
const button = this.$el.querySelector('button')
const target = event.target
if (this.$el.contains(target) && !button.contains(target)) {
this.show = false
}
},
get isOpen() {
return this.show === true
},
content: 'Default content',
init() {
console.log(this.$el.parentElement)
console.log('dropdown --- init')
},
}
}
Alpine.data('dropdown', dropdown)
Alpine.plugin(alpinejsComponent)
Alpine.start()
</script>
工作顺利。