额外内容:使用 Web Components 解决 Vue 中的问题
这是我正在撰写的关于 Web 组件系列文章的番外篇。
第四部分,关于 Polymer 库的内容,正在撰写中。在此期间,不妨看看一位学生向我提出的这个有趣的问题,我们可以用 Web 标准来解决:
他们使用一个库在 Vue 组件中渲染 WebGL 地球仪。他们想要生成一组标记,然后跟踪哪些标记被打开,哪些被关闭。该 WebGL 库提供了一些 API,可以将字符串附加innerHTML到每个标记的弹出窗口中,但没有提供任何用于跟踪打开、关闭或点击事件的 API。
我突然冒出一个有点邪恶的想法😈。如果我们不能给库弹出窗口添加行为,但可以添加HTML,那么如果我们添加的HTML能够封装它自己的行为呢?
🎩 Web Components 来救场啦!!👨💻
定义<popup-tooltip>
我们需要的是一个 HTML 元素,当它包含的弹出窗口打开或关闭时,该元素会触发一个事件。WebGL 库过去常常用于style="visibility: visible"打开和关闭弹出窗口,所以我们将创建一个元素,使其MutationObserver能够监听自身的父元素。
class PopupTooltip extends HTMLElement {
constructor() {
super();
this.observerCallback = this.observerCallback.bind(this);
this.attachShadow({mode: 'open'});
this.shadowRoot.appendChild(document.createElement('slot'));
this.observer = new MutationObserver(this.observerCallback);
}
connectedCallback() {
// HACK: WebGL library toggles style.visibility on it's own
// generated DOM to hide and show tooltips.
const libraryContainer = this.parentElement.parentElement.parentElement;
const config = { attributes: true, subtree: false, children: false };
this.observer.observe(libraryContainer, config);
}
observerCallback([{target}]) {
const visible = target.style.visibility === 'visible';
const type = 'popup-' + visible ? 'opened' : 'closed';
const bubbles = true;
const composed = true;
const detail = this;
this.dispatchEvent(new CustomEvent(type, { bubbles, composed, detail }));
}
}
customElements.define('popup-tooltip', PopupTooltip);
连接到 Vue 包装器
现在我们有了一个元素,当其容器的可见性被 WebGL 库切换时,<popup-tooltip>该元素会触发一个popup-opened事件。我们在包裹它的 Vue 组件的私有 DOM 中设置了监听器:popup-closed
<!-- WebGL lib instanciates on '#earth' -->
<div id="earth" @popup-opened="onPopupOpened" @popup-closed="onPopupClosed"></div>
创建每个弹出窗口
然后,当我们实例化 WebGL 库并传递我们的数据时,我们设置标记以<popup-tooltip>在其工具提示内容中显示元素。
geoMarkers.forEach(marker => {
const location = marker.latLng;
const glMarker = new WebGLLib.popup({/*...*/});
// NB: popupHTML is **just HTML**, there's no framework or library here.
const popupHTML = `<popup-tooltip data-location="${location}">${marker.title}</popup-tooltip>`;
// `bindPopup` is a method on our WebGL library's marker API.
glMarker.bindPopup(popupHTML, config);
})
利润!
最后我们需要做的就是追踪哪些弹出窗口被打开,哪些被关闭。
onPopupOpened({target: {dataset: {location}}}) {
const [lat, lng] = location.split(',');
console.log(`opened: lat: ${lat} lng: ${lng}`);
}
你无需放弃现有框架即可使用 Web 组件。只要能使用 HTML 和 JavaScript,你就可以在任何需要的地方使用它们。这正是 Web 组件的优势所在:我们的 GL 库并不接受 Vue 组件作为输入,而是接受一串 HTML 代码。
几天后我们将继续进行关于 Polymer 库的第四部分,敬请期待。
文章来源:https://dev.to/bennypowers/bonus-solving-problems-in-vue-with-web-components-2582