webcomponent in template and alpine.js



我想定义一个自定义元素并将其附加在阴影dom中。此元素使用alpine和bootstrap4,并且必须在图形上与dom的其余部分隔离。Alpine必须包含在webcomponent中并直接使用(而不是在light dom中)。

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous" />
<script defer src="//unpkg.com/alpinejs@3.9.3/dist/cdn.min.js"></script>
<div class="container" x-data="my_component">
<div class="row">
<div class="col-lg-2 col-md-4">
<div class="form-group">
<label for="sel1">Sel 1</label>
<select id="sel1" class="form-control" x-model="sel1">
<option value="" disabled>Sel 1</option>
<template x-for="{label, id} in optsSel1" :key="id">
<option
x-text="label"
x-bind:value="id"
x-bind:selected="id === sel1"
></option>
</template>
</select>
</div>
</div>
</div>
<div class="row mt-xs-3 mt-sm-3">
<div class="col-lg-12 text-center">
<button class="btn btn-warning btn-lg btn-block" @click="notify">
Submit
</button>
</div>
</div>
</div>
<script>
const optsSel1 = [{
id: "AF",
label: "Afghanistan"
},
{
id: "AL",
label: "Albania"
},
{
id: "DZ",
label: "Algeria"
}
];
document.addEventListener("alpine:init", () => {
Alpine.data("my_component", () => ({
optsSel1,
sel1: "AF",
notify() {
const data = new URLSearchParams({
sel1: this.sel1
});
alert(data);
}
}));
});
</script>

我尝试将上面的代码包装在一个模板标签中,并定义一个自定义元素。

图形上是ok的,bootstrap似乎工作。

JS在alpine上也工作得很好:init会显示一个警告。

但是在alpine中定义的所有与dom交互的逻辑似乎都不起作用:

  1. select的选项为空;
  2. 点击提交按钮没有效果。

<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div>
<button class="btn btn-warning btn-lg btn-block">button outside</button>
<my-component />
</div>
<template id="my-component_tpl">
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
crossorigin="anonymous"
/>
<script defer src="//unpkg.com/alpinejs@3.9.3/dist/cdn.min.js"></script>
<div class="container" x-data="my_component">
<div class="row">
<div class="col-lg-2 col-md-4">
<div class="form-group">
<label for="sel1">Sel 1</label>
<select id="sel1" class="form-control" x-model="sel1">
<option value="" disabled>Sel 1</option>
<template x-for="{label, id} in optsSel1" :key="id">
<option
x-text="label"
x-bind:value="id"
x-bind:selected="id === sel1"
></option>
</template>
</select>
</div>
</div>
</div>
<div class="row mt-xs-3 mt-sm-3">
<div class="col-lg-12 text-center">
<button class="btn btn-warning btn-lg btn-block" @click="notify">
Submit
</button>
</div>
</div>
</div>
<script>
const optsSel1 = [{
id: "AF",
label: "Afghanistan"
},
{
id: "AL",
label: "Albania"
},
{
id: "DZ",
label: "Algeria"
}
];
document.addEventListener("alpine:init", () => {
alert("alpine:init " + JSON.stringify(optsSel1, null, 2));
Alpine.data("my_component", () => ({
optsSel1,
sel1: "AF",
notify() {
const data = new URLSearchParams({
sel1: this.sel1
});
alert(data);
}
}));
});
</script>
</template>
<script>
customElements.define(
"my-component",
class extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({
mode: "open"
});
const tpl = document.getElementById("my-component_tpl");
shadow.appendChild(tpl.content);
}
}
);
</script>
</body>
</html>

就错了什么?提前感谢!

你应该加上

document.addEventListener("alpine:initialized",()=>{
Alpine.initTree(this.shadowRoot)
})

到connectedCallback函数

Alpine的变异观察者看不到影子dom里面有什么,所以你必须手动初始化它。

查看你的代码片段

最新更新