vscode 扩展 本地_如何扩展本地html元素

news/2024/7/10 1:57:27 标签: java, python, html, javascript, vue
htmledit_views">

vscode 扩展 本地

When standard HTML is not enough

如果标准HTML不够用

Ever since the days of XML we have tried to extend HTML with our own tags.

从XML时代开始,我们就尝试使用我们自己的标签扩展HTML。

The standard library of HTML tags is fairly limited and intentionally consists of low-level building blocks, meant to be composed by developers into more high-level functionality.

HTML标签的标准库是相当有限的,有意地由低级构建块组成,意在由开发人员组成更高级的功能。

Now that all modern browsers support Web Components (or more specifically Custom Elements) you can create your very own HTML elements that you can use anywhere by just loading a script and adding the tag to the document.

现在,所有现代浏览器都支持Web组件 (或更具体地讲,是Custom Elements ),您可以创建自己HTML元素,只需加载脚本并将标签添加到文档中,即可在任何地方使用。

It’s really as simple as that.

就这么简单。

If you have created your own image gallery, you can use it by just loading the script and adding <image-gallery></image-gallery> to the document:

如果您创建了自己的图片库,则可以通过加载脚本并将<image-gallery></image-gallery>到文档中来使用它:

class ImageGallery extends HTMLElement {
constructor() {
super();
} ...}customElements.define('image-gallery', ImageGallery);<image-gallery></image-gallery> // presto!

Here the ImageGallery class contains all the functionality for the <image-gallery> HTML element and we register it throughcustomElements.define with the 'image-gallery' tag name.

这里的ImageGallery类包含<image-gallery> HTML元素的所有功能,我们通过customElements.define使用'image-gallery'标签名对其进行注册。

Now frameworks like React, Angular and Vue.js also allow you to create your own HTML tags, but contrary to framework components, Custom Elements are real first-class HTML elements.

现在,像React,Angular和Vue.js这样的框架也允许您创建自己HTML标签,但是与框架组件相反,自定义元素是真正的一流HTML元素。

In this case the ImageGallery class extends HTMLElement, which is the base interface of all HTML elements. This means that it will inherit all the functionality that is common to all HTML elements.

在这种情况下, ImageGallery类扩展了HTMLElementHTMLElement是所有HTML元素的基本接口。 这意味着它将继承所有HTML元素共有的所有功能。

For example, you can attach event listeners to it through addEventListener, use CSS to style it through its style property or interact with it in the browser devtools like any other HTML element.

例如,您可以通过addEventListener将事件侦听器附加到该事件侦听器,使用CSS通过其style属性设置其style或在浏览器devtool中与其他HTML元素进行交互。

And it doesn’t stop there.

而且不止于此。

站在巨人的肩膀上 (Standing On The Shoulders Of Giants)

Instead of extending HTMLElement, Custom Elements can also extend other built-in HTML elements like <button>, <img> and <a> for example.

自定义元素还可以扩展其他内置HTML元素,例如<button><img><a> ,而不是扩展HTMLElement

Let’s say we want to create a lazy loading image that will not load until it’s scrolled into the viewport. We could do this by searching for all images in the page and attach a IntersectionObserver to each image that makes sure the image will only load when it becomes visible.

假设我们要创建一个延迟加载图像,直到将其滚动到视口后才加载。 我们可以通过搜索页面中的所有图像并在每个图像上附加一个IntersectionObserver来确保此图像仅在可见时才加载。

But we could also extend the built-in image element itself and use that enhanced image element instead of the regular <img> HTML element.

但是我们也可以扩展内置图像元素本身,并使用增强的图像元素代替常规的<img> HTML元素。

We can do this by creating a Custom Element that doesn’t extend HTMLElement but instead extends the interface of the <img> element, which is HTMLImageElement:

我们可以通过创建一个自定义元素来做到这一点,该自定义元素不扩展HTMLElement而是扩展<img>元素的接口,即HTMLImageElement

class LazyImg extends HTMLImageElement {
constructor() {
super();
}...}customElements.define('lazy-img', LazyImg, {extends: 'img'});

The Custom Element is registered with the usual call to customElement.define but now it takes a third argument, {extends: 'img'}, that specifies which HTML element will be extended.

自定义元素已通过对customElement.define的常规调用进行注册,但是现在它使用了第三个参数{extends: 'img'} ,该参数指定将扩展哪个HTML元素。

Now instead of using a new HTML tag, we can just use our enhanced image element with the regular <img> tag but we add the new functionality to it through the is attribute:

现在,不用新HTML标签,我们可以将增强的图像元素与常规的<img>标签一起使用,但是可以通过is属性为它添加新功能:

<img is="lazy-img" src="/path/to/image.png">

This image is now an enhanced image that gets all the functionality we defined in the LazyImg class.

现在,此图像是增强的图像,具有我们在LazyImg类中定义的所有功能。

The complete implementation of LazyImg is too large for this article but you can find the source code on my Github.

LazyImg 的完整实现对于 LazyImg 来说太大了,但是您可以在 我的Github 上找到源代码

The beauty of this approach is that any browser that doesn’t support extending built-in HTML elements will simply ignore the is attribute and just render a regular image.

这种方法的优点在于,任何不支持扩展内置HTML元素的浏览器都将仅忽略is属性,而仅呈现常规图像。

Progressive enhancement at its finest.

最好的逐步增强。

示例:客户端路由 (Example: client-side routing)

This way, we can also easily enhance ordinary links to become links that work with a client-side router.

这样,我们还可以轻松地增强普通链接,使其成为可与客户端路由器一起使用的链接。

Normally, we would need to loop through all these links and write some code to prevent that we navigate to another page when the link is clicked, because we want to handle the routing on the client-side.

通常,我们需要遍历所有这些链接并编写一些代码,以防止单击链接时导航到另一个页面,因为我们要在客户端处理路由。

By extending the native <a> tag, we can simply add an is attribute to indicate it is a client-side link, so it won’t make the browser go to the page specified in its href attribute when clicked.

通过扩展本机的<a>标记,我们可以简单地添加一个is属性以指示它是客户端链接,因此单击它不会使浏览器转到其href属性中指定的页面。

We do this by extending the HTMLAnchorElement which is the interface for the <a> tag:

为此,我们扩展了HTMLAnchorElement ,它是<a>标签的接口:

class RouterLink extends HTMLAnchorElement {
constructor() {
super();
}
connectedCallback() {
this.addEventListener('click', e => {
e.preventDefault();
this.dispatchEvent(new CustomEvent('route-change', {
composed: true,
detail: {link: this}
}));
})
}
}

In the connectedCallback we set an event handler to intercept the click event. By calling e.preventDefault, we prevent the browser from following the link so nothing happens when a user clicks the link.

connectedCallback我们设置了一个事件处理程序来拦截click事件。 通过调用e.preventDefault ,我们可以防止浏览器跟踪链接,因此当用户单击链接时什么也不会发生。

Then we throw a new route-change event with the link as the payload in the link property. A parent element can listen for this event and perform the client-side routing, for example a nav tag that has also been extended:

然后,我们在link属性中引发一个新的route-change事件,该链接具有链接作为有效负载。 父元素可以侦听此事件并执行客户端路由,例如也已扩展的nav标签:

<nav is="client-side-router">
<a href="/path/to/page1" is="router-link">Page 1</a>
<a href="/path/to/page2" is="router-link">Page 2</a>
<a href="/path/to/page3" is="router-link">Page 3</a>
</nav>

This way, we can build a navigation component that will work perfectly fine in older, not supporting browsers and that will be enhanced to a client-side router in modern browsers.

这样,我们可以构建一个导航组件,该组件在较旧的浏览器中可以完美运行,不支持浏览器,并且可以在现代浏览器中增强为客户端路由器。

Let’s look at how we could implement the router itself by extending the <nav> tag.

让我们看看如何通过扩展<nav>标签实现路由器本身。

The <nav> tag doesn’t have its own interface so it simply extends HTMLElement. Although it is a built-in element we can still add Shadow DOM to it which will make interacting with the child element, the links, a bit easier and robust:

<nav>标签没有自己的接口,因此仅扩展了HTMLElement 。 尽管它是一个内置元素,我们仍然可以向其添加Shadow DOM,这将使它与子元素,链接进行交互变得更加容易和健壮:

class ClientSideRouter extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<slot name="link"></slot>
`;
}
connectedCallback() {
const slot = this.shadowRoot.querySelector('slot');
const links = slot.assignedNodes();
links.forEach(link => {
link.addEventListener('route-change', e => {
this.handleRouteChange(e.detail.link);
});
});
}
}

The Shadow DOM of the router will only contain a named <slot> element which will serve as the insertion point for the links. We can then get all links through the assignedNodes method of the <slot> and add an event listener to each link, so we can handle the route change when a link is clicked.

路由器的Shadow DOM仅包含一个名为<slot>元素,该元素将用作链接的插入点。 然后,我们可以通过<slot>assignedNodes方法获取所有链接,并向每个链接添加一个事件侦听器,以便单击链接时可以处理路由更改。

The only thing we need to add on the links is a slot attribute to make sure they are inserted in the correct slot:

我们需要在链接上添加的唯一内容是slot属性,以确保将其插入正确的插槽中:

<a href="/path/to/page1" is="router-link" slot="link">Page 1</a>

We could omit the name attribute on the slot and the slot attribute on the link. That would also work but then any newlines inside the nav components would also be returned by assignedNodes() as empty text nodes and we would need to filter them out.

我们可以省略 插槽上 name 属性和 链接上的 slot 属性。 这也将起作用,但是 nav 组件 内的所有换行符 也将由 assignedNodes() 作为空文本节点返回,我们需要将其过滤掉。

This is nice, but the fact that we need to add a separate event handler to each link is a bit unfortunate and inefficient. It would be better if we could just add a single event handler to the router itself.

很好,但是事实是我们需要为每个链接添加一个单独的事件处理程序,这有点不幸且效率低下。 如果我们只向路由器本身添加一个事件处理程序,那就更好了。

We can do this by adding bubbles: true to the config object of the route-change event thrown by RouterLink:

我们可以通过添加bubbles: true来做到这一点bubbles: trueRouterLink引发的route-change事件的config对象:

this.dispatchEvent(new CustomEvent('route-change', {
composed: true,bubbles: true, // <-- add this to make the event bubble up
detail: {url}
}));

The event will now bubble up and we can listen to it on the router itself:

现在该事件将冒泡,我们可以在路由器本身上监听它:

class ClientSideRouter extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<slot name="link"></slot>
`;
}
connectedCallback() {
this.outlet = document.querySelector(this.dataset.outlet);this.addEventListener('route-change', e => {
this.handleRouteChange(e.detail.link)
});

}
handleRouteChange(link) {
// handle route change
}
}
customElements.define('client-side-router', ClientSideRouter, {extends: 'nav'});

We could now also make a simple implementation of the handleRouteChange method. We could add a data- attribute to the router, containing a CSS selector to specify where the templates should be rendered and a data- attribute to each router link to specify which template should be rendered:

现在,我们还可以对handleRouteChange方法进行简单的实现。 我们可以向路由器添加一个data- attribute属性,其中包含一个CSS选择器以指定应在何处呈现模板,而为每个路由器链接提供一个data- attribute以指定应呈现哪个模板:

<nav is="client-side-router" data-outlet="#main">
<a href="/path/to/page1" is="router-link" slot="link"data-template="./page1.html">Page 1</a>
...</nav><!-- templates are rendered here -->
<div id="main"></div>

In the handleRouteChange method we then fetch the template, render it inside the outlet and add and entry to the browser’s history so the url will change to reflect the route change:

然后,在handleRouteChange方法中,获取模板,将其呈现在出口内,并添加和输入浏览器的历史记录,以便更改URL以反映路线更改:

async handleRouteChange(link) {
const template = link.dataset.template;
const url = link.getAttribute('href');
const state = {template, url};
const html = await (await fetch(template)).text();
history.pushState(state, null, url);
this.outlet.innerHTML = html;
}

Now this is obviously a naive and very basic implementation, but I hope you got an idea of what is possible by extending built-in HTML elements.

现在,这显然是一个幼稚且非常基本的实现,但是我希望您对扩展内置HTML元素的可能实现有所了解。

You can find the source code including a demo page on my Github.

您可以在我的Github上找到包括演示页面在内的源代码。

You can follow me on Twitter where I regularly write about the PWAs, Web Components and the capabilities of the modern web.

您可以在Twitter上关注我,在那里我定期撰写有关PWA,Web组件和现代Web功能的文章。

翻译自: https://itnext.io/how-to-extend-a-native-html-element-1d4674e09c22

vscode 扩展 本地


http://www.niftyadmin.cn/n/1469178.html

相关文章

matlab画红玫瑰,网上收到的用matlab画玫瑰花的代码怎么不行啊,报告错误,求大神...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼function plot_rosedraw_main(450,90);function draw_main(x,y)%粉红色玫瑰arcdata{1}[65 -60 150 350 866 -54 300 470 865 -56 30 230 1064 -57 300 490 17];ellipsedata{1}[73 -30 250 450 27 4059 -30 100 290 27 4065 -40 140…

python 静态检查_python中的静态类型检查

python 静态检查Python 3.5 introduced Type Hints, a new feature that allows developers to use static type checking in python.Python 3.5引入了Type Hints &#xff0c;这是一项新功能&#xff0c;允许开发人员在python中使用静态类型检查。 Python中的类型检查 (Type …

python str函数数字转换成字符串,Pandas将数字转换为字符串意外结果

似乎没有办法获得输入表(从html/xls/etc文件)到DataFrame对象&#xff0c;因为它是1对1&#xff0c;没有pandas内部应用的任何字段转换。在假设下面的html表是以.xls文件的扩展名保存的&#xff0c;那么我们如何在Python内存中使用DataFrame对象获得相同的表示形式呢&#xff1…

js 捕获异常获取异常信息_js世界中的异常安全

js 捕获异常获取异常信息As recent versions of JavaScript (formally EMCAScript) provide more programmatic facilities (and syntactic sugar) for us programmers to utilize, code in JavaScript has never been more expressive, though new pitfalls come along. With …

python核心语法练习题,python3核心语法练习题(像背单词一样掌握)

想背单词一样记住python用法1 如何打印im "ok"答案&#xff1a;print(im "ok")2 print(r\ \)和print(\ \)结果是分别什么&#xff1f;语句中的‘r’是什么作用&#xff1f;答&#xff1a;请自行实验3如何不使用 打印多行&#xff1f;答案&#xff1a…

php 二进制 pdf文件怎么打开,如何从javascript中的二进制流打开并读取PDF

我在使用JavaScript读取二进制数据流时遇到了一些困难。如何从javascript中的二进制流打开并读取PDF目前&#xff0c;一个窗口弹出并打开并显示无法加载PDF文档。 我会在下面发布我的回复和代码&#xff0c;任何帮助将不胜感激。这里是我的后端PHP&#xff1a;function getPDF(…

webpack要点

If you write JavaScript, then you must heard of Webpack. Even if you don’t use it personally, you will still see it in your team’s project highly likely. I’m always resistant to learn it, probably because subconsiously I think it’s too complex to learn…

php table 其中一个表格放2条数据_其它放一条数据,jsp页面中,一个table数据有很多列,有上下左右滚动条,怎样可以表格数据横向拖动的时候,表格的前四列固定不动?...

自己百度 谷歌好多案例&#xff0c; 但是都不太符合现在的项目&#xff0c;现在的项目是一个table&#xff0c;百度案例要么是用插件&#xff0c;要么是两个table&#xff0c;但是这样改动会太大&#xff0c;要么是用新的div复制table的前四列&#xff0c;这样表格的点击事件将…