你知道原生HTML组件是什么吗?原生HTML组件的介绍

本篇文章给大家带来的内容是关于你知道原生html组件是什么吗?原生html组件的介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

嘿!看看这几年啊,Web 前端的发展可是真快啊!

想想几年前,HTML 是前端开发者的基本技能,通过各式各样的标签就可以搭建一个可用的网站,基本交互也不是问题。如果再来点 CSS,嗯,金黄酥脆,美味可口。这时候再撒上几把 JavaScript,简直让人欲罢不能。

随着需求的增长,HTML 的结构越来越复杂,大量重复的代码使得页面改动起来异常困难,这也就孵化了一批批模版工具,将公共的部分抽取出来变为公共组件。再后来,随着 JavaScript 的性能提升,JavaScript 的地位越来越高,不再只是配菜了,前端渲染的出现降低了服务端解析模版的压力,服务端只要提供静态文件和 API 接口就行了嘛。再然后,前端渲染工具又被搬回了服务端,后端渲染出现了(黑人问号???)

总之,组件化使得复杂的前端结构变得清晰,各个部分独立起来,高内聚低耦合,使得维护成本大大降低。

那么,你有听说过原生 HTML 组件吗?

立即学习“前端免费学习笔记(深入)”;

1754597496-5bc7f1ee5c154_articlex.jpg

四大 Web 组件标准

在说原生 HTML 组件之前,要先简单介绍一下四大 Web 组件标准,四大 Web 组件标准分别为:HTML Template、Shadow DOM、Custom Elements 和 HTML Imports。实际上其中一个已经被废弃了,所以变成“三大”了。

HTML Template 相信很多人都有所耳闻,简单的讲也就是 HTML5 中的 标签,正常情况下它无色无味,感知不到它的存在,甚至它下面的 img 都不会被下载,script 都不会被执行。 就如它的名字一样,它只是一个模版,只有到你用到它时,它才会变得有意义。

Shadow DOM 则是原生组件封装的基本工具,它可以实现组件与组件之间的独立性。

Custom Elements 是用来包装原生组件的容器,通过它,你就只需要写一个标签,就能得到一个完整的组件。

HTML Imports 则是 HTML 中类似于 ES6 Module 的一个东西,你可以直接 import 另一个 html 文件,然后使用其中的 DOM 节点。但是,由于 HTML Imports 和 ES6 Module 实在是太像了,并且除了 Chrome 以外没有浏览器愿意实现它,所以它已经被废弃并不推荐使用了。未来会使用 ES6 Module 来取代它,但是现在貌似还没有取代的方案,在新版的 Chrome 中这个功能已经被删除了,并且在使用的时候会在 Console 中给出警告。警告中说使用 ES Modules 来取代,但是我测试在 Chrome 71 中 ES Module 会强制检测文件的 MIME 类型必须为 JavaScript 类型,应该是暂时还没有实现支持。

2508713701-5bc7f09060787_articlex.png

Shadow DOM

要说原生 HTML 组件,就要先聊聊 Shadow DOM 到底是个什么东西。

大家对 DOM 都很熟悉了,在 HTML 中作为一个最基础的骨架而存在,它是一个树结构,树上的每一个节点都是 HTML 中的一部分。DOM 作为一棵树,它拥有着上下级的层级关系,我们通常使用“父节点”、“子节点”、“兄弟节点”等来进行描述(当然有人觉得这些称谓强调性别,所以也创造了一些性别无关的称谓)。子节点在一定程度上会继承父节点的一些东西,也会因兄弟节点而产生一定的影响,比较明显的是在应用 CSS Style 的时候,子节点会从父节点那里继承一些样式。

而 Shadow DOM,也是 DOM 的一种,所以它也是一颗树,只不过它是长在 DOM 树上的一棵特殊的紫薯,啊不,子树。

什么?DOM 本身不就是由一棵一棵的子树组成的吗?这个 Shadow DOM 有什么特别的吗?

Shadow DOM 的特别之处就在于它致力于创建一个相对独立的一个空间,虽然也是长在 DOM 树上的,但是它的环境却是与外界隔离的,当然这个隔离是相对的,在这个隔离空间中,你可以选择性地从 DOM 树上的父节点继承一些属性,甚至是继承一棵 DOM 树进来。

利用 Shadow DOM 的隔离性,我们就可以创造原生的 HTML 组件了。

实际上,浏览器已经通过 Shadow DOM 实现了一些组件了,只是我们使用过却没有察觉而已,这也是 Shadow DOM 封装的组件的魅力所在:你只管写一个 HTML 标签,其他的交给我。(是不是有点像 React 的 JSX 啊?)

我们来看一看浏览器利用 Shadow DOM 实现的一个示例吧,那就是 video 标签:

我们来看一下浏览器渲染的结果:

3986383008-5bc7f0af9a354_articlex.png

等一下!不是说 Shadow DOM 吗?这和普通 DOM 有啥区别???

在 Chrome 中,Elements 默认是不显示内部实现的 Shadow DOM 节点的,需要在设置中启用:

4254440722-5bc7f0c9331b5_articlex.png

3551890025-5bc7f0d516ea6_articlex.png

注:浏览器默认隐藏自身的 Shadow DOM 实现,但如果是用户通过脚本创造的 Shadow DOM,是不会被隐藏的。

然后,我们就可以看到 video 标签的真面目了:

925947494-5bc7f0fadca05_articlex.png

在这里,你可完全像调试普通 DOM 一样随意调整 Shadow DOM 中的内容(反正和普通 DOM 一样,刷新一下就恢复了)。

我们可以看到上面这些 shadow DOM 中的节点大多都有 pseudo 属性,根据这个属性,你就可以在外面编写 CSS 样式来控制对应的节点样式了。比如,将上面这个 pseudo=”-webkit-media-controls-overlay-play-button” 的 input 按钮的背景色改为橙色:

video::-webkit-media-controls-overlay-play-button {  background-color: orange;}

2935846866-5bc7f11a17342_articlex.png

由于 Shadow DOM 实际上也是 DOM 的一种,所以在 Shadow DOM 中还可以继续嵌套 Shadow DOM,就像上面那样。

浏览器中还有很多 Element 都使用了 Shadow DOM 的形式进行封装,比如 、、 等,这里就不一一展示了。

由于 Shadow DOM 的隔离性,所以即便是你在外面写了个样式:div { background-color: red !important; },Shadow DOM 内部的 div 也不会受到任何影响

也就是说,写样式的时候,该用 id 的时候就用 id,该用 class 的时候就用 class,一个按钮的 class 应该写成 .button 就写成 .button。完全不用考虑当前组件中的 id、class 可能会与其他组件冲突,你只要确保一个组件内部不冲突就好——这很容易做到。

这解决了现在绝大多数的组件化框架都面临的问题:Element 的 class(className) 到底怎么写?用前缀命名空间的形式会导致 class 名太长,像这样:.header-nav-list-sublist-button-icon;而使用一些 CSS-in-JS 工具,可以创造一些唯一的 class 名称,像这样:.Nav__welcomeWrapper___lKXTg,这样的名称仍旧有点长,还带了冗余信息。

ShadowRoot

ShadowRoot 是 Shadow DOM 下面的根,你可以把它当做 DOM 中的

一样看待,但是它不是 ,所以你不能使用 上的一些属性,甚至它不是一个节点。

你可以通过 ShadowRoot 下面的 appendChild、querySelectorAll 之类的属性或方法去操作整个 Shadow DOM 树。

对于一个普通的 Element,比如

,你可以通过调用它上面的 attachShadow 方法来创建一个 ShadowRoot(还有一个 createShadowRoot 方法,已经过时不推荐使用),attachShadow 接受一个对象进行初始化:{ mode: ‘open’ },这个对象有一个 mode 属性,它有两个取值:’open’ 和 ‘closed’,这个属性是在创造 ShadowRoot 的时候需要初始化提供的,并在创建 ShadowRoot 之后成为一个只读属性。

mode: ‘open’ 和 mode: ‘closed’ 有什么区别呢?在调用 attachShadow 创建 ShadowRoot 之后,attachShdow 方法会返回 ShadowRoot 对象实例,你可以通过这个返回值去构造整个 Shadow DOM。当 mode 为 ‘open’ 时,在用于创建 ShadowRoot 的外部普通节点(比如

)上,会有一个 shadowRoot 属性,这个属性也就是创造出来的那个 ShadowRoot,也就是说,在创建 ShadowRoot 之后,还是可以在任何地方通过这个属性再得到 ShadowRoot,继续对其进行改造;而当 mode 为 ‘closed’ 时,你将不能再得到这个属性,这个属性会被设置为 null,也就是说,你只能在 attachShadow 之后得到 ShadowRoot 对象,用于构造整个 Shadow DOM,一旦你失去对这个对象的引用,你就无法再对 Shadow DOM 进行改造了。

可以从上面 Shadow DOM 的截图中看到 #shadow-root (user-agent) 的字样,这就是 ShadowRoot 对象了,而括号中的 user-agent 表示这是浏览器内部实现的 Shadow DOM,如果使用通过脚本自己创建的 ShadowRoot,括号中会显示为 open 或 closed 表示 Shadow DOM 的 mode。

3465801305-5bc7f119096b3_articlex.png

浏览器内部实现的 user-agent 的 mode 为 closed,所以你不能通过节点的 ShadowRoot 属性去获得其 ShadowRoot 对象,也就意味着你不能通过脚本对这些浏览器内部实现的 Shadow DOM 进行改造。

HTML Template

有了 ShadowRoot 对象,我们可以通过代码来创建内部结构了,对于简单的结构,也许我们可以直接通过 document.createElement 来创建,但是稍微复杂一些的结构,如果全部都这样来创建不仅麻烦,而且代码可读性也很差。当然也可以通过 ES6 提供的反引号字符串(const template = `……`;)配合 innerHTML 来构造结构,利用反引号字符串中可以任意换行,并且 HTML 对缩进并不敏感的特性来实现模版,但是这样也是不够优雅,毕竟代码里大段大段的 HTML 字符串并不美观,即便是单独抽出一个常量文件也是一样。

这个时候就可以请 HTML Template 出场了。我们可以在 html 文档中编写 DOM 结构,然后在 ShadowRoot 中加载过来即可。

HTML Template 实际上就是在 html 中的一个 标签,正常情况下,这个标签下的内容是不会被渲染的,包括标签下的 img、style、script 等都是不会被加载或执行的。你可以在脚本中使用 getElementById 之类的方法得到 标签对应的节点,但是却无法直接访问到其内部的节点,因为默认他们只是模版,在浏览器中表现为 #document-fragment,字面意思就是“文档片段”,可以通过节点对象的 content 属性来访问到这个 document-fragment 对象。

2033065598-5bc7f18543064_articlex.png

通过 document-fragment 对象,就可以访问到 template 内部的节点了,通过 document.importNode 方法,可以将 document-fragment 对象创建一份副本,然后可以使用一切 DOM 属性方法替换副本中的模版内容,最终将其插入到 DOM 或是 Shadow DOM 中。

const template = document.getElementById('temp');const copy = document.importNode(template.content, true);copy.getElementById('title').innerHTML = 'Hello World!';const div = document.getElementById('div');const shadowRoot = div.attachShadow({ mode: 'closed' });shadowRoot.appendChild(copy);

HTML Imports

有了 HTML Template,我们已经可以方便地创造封闭的 Web 组件了,但是目前还有一些不完美的地方:我们必须要在 html 中定义一大批的 ,每个组件都要定义一个 。

此时,我们就可以用到已经被废弃的 HTML Imports 了。虽然它已经被废弃了,但是未来会通过 ES6 Modules 的形式再进行支持,所以理论上也只是换个加载形式而已。

通过 HTML Imports,我们可以将 定义在其他的 html 文档中,然后再在需要的 html 文档中进行导入(当然也可以通过脚本按需导入),导入后,我们就可以直接使用其中定义的模版节点了。

已经废弃的 HTML Imports 通过 标签实现,只要指定 rel=”import” 就可以了,就像这样:,它可以接受 onload 和 onerror 事件以指示它已经加载完成。当然也可以通过脚本来创建 link 节点,然后指定 rel 和 href 来按需加载。Import 成功后,在 link 节点上有一个 import 属性,这个属性中存储的就是 import 进来的 DOM 树啦,可以 querySelector 之类的,并通过 cloneNode 或 document.importNode 方法创建副本后使用。

未来新的 HTML Imports 将会以 ES6 Module 的形式提供,可以在 JavaScript 中直接 import * as template from ‘./template.html’;,也可以按需 import,像这样:const template = await import(‘./template.html’);。不过目前虽然浏览器都已经支持 ES6 Modules,但是在 import 其他模块时会检查服务端返回文件的 MIME 类型必须为 JavaScript 的 MIME 类型,否则不允许加载。

Custom Elements

有了上面的三个组件标准,我们实际上只是对 HTML 进行拆分而已,将一个大的 DOM 树拆成一个个相互隔离的小 DOM 树,这还不是真正的组件。

要实现一个真正的组件,我们就需要用到 Custom Elements 了,就如它的名字一样,它是用来定义原生组件的。

Custom Elements 的核心,实际上就是利用 JavaScript 中的对象继承,去继承 HTML 原生的 HTMLElement 类(或是具体的某个原生 Element 类,比如 HTMLButtonElement),然后自己编写相关的生命周期函数,处理成员属性以及用户交互的事件。

看起来这和现在的 React 很像,在 React 中,你可以这样创造一个组件:class MyElement extends React.Component { … },而使用原生 Custom Elements,你需要这样写:class MyElement extends HTMLElement { … }。

Custom Elements 的生命周期函数并不多,但是足够使用。这里我将 Custom Elements 的生命周期函数与 React 进行一个简单的对比:

constructor(): 构造函数,用于初始化 state、创建 Shadow DOM、监听事件之类。

对应 React 中 Mounting 阶段的大半部分,包括:constructor(props)、static getDerivedStateFromProps(props, state) 和 render()。

在 Custom Elements 中,constructor() 构造函数就是其原本的含义:初始化,和 React 的初始化类似,但它没有像 React 中那样将其拆分为多个部分。在这个阶段,组件仅仅是被创建出来(比如通过 document.createElement()),但是还没有插入到 DOM 树中。

connectedCallback(): 组件实例已被插入到 DOM 树中,用于进行一些展示相关的初始化操作。

对应 React 中 Mounting 阶段的最后一个生命周期:componentDidMount()。

在这个阶段,组件已经被插入到 DOM 树中了,或是其本身就在 html 文件中写好在 DOM 树上了,这个阶段一般是进行一些展示相关的初始化,比如加载数据、图片、音频或视频之类并进行展示。

attributeChangedCallback(attrName, oldVal, newVal): 组件属性发生变化,用于更新组件的状态。

对应 React 中的 Updating 阶段:static getDerivedStateFromProps(props, state)、shouldComponentUpdate(nextProps, nextState)、render()、getSnapshotBeforeUpdate(prevProps, prevState) 和 componentDidUpdate(prevProps, prevState, snapshot)。

当组件的属性(React 中的 props)发生变化时触发这个生命周期,但是并不是所有属性变化都会触发,比如组件的 class、style 之类的属性发生变化一般是不会产生特殊交互的,如果所有属性发生变化都触发这个生命周期的话,会使得性能造成较大的影响。所以 Custom Elements 要求开发者提供一个属性列表,只有当属性列表中的属性发生变化时才会触发这个生命周期函数。

这个属性列表通过组件类上的一个静态只读属性来声明,在 ES6 Class 中使用一个 getter 函数来实现,只实现 getter 而不实现 setter,getter 返回一个常量,这样就是只读的了。像这样:

class AwesomeElement extends HTMLElement {  static get observedAttributes() {    return ['awesome'];  }}

disconnectedCallback(): 组件被从 DOM 树中移除,用于进行一些清理操作。

对应 React 中的 Unmounting 阶段:componentWillUnmount()。

adoptedCallback(): 组件实例从一个文档被移动到另一个文档。

这个生命周期是原生组件独有的,React 中没有类似的生命周期。这个生命周期函数也并不常用到,一般在操作多个 document 的时候会遇到,调用 document.adoptNode() 函数转移节点所属 document 时会触发这个生命周期。

在定义了自定义组件后,我们需要将它注册到 HTML 标签列表中,通过 window.customElements.define() 函数即可实现,这个函数接受两个必须参数和一个可选参数。第一个参数是注册的标签名,为了避免和 HTML 自身的标签冲突,Custom Elements 要求用户自定义的组件名必须至少包含一个短杠 -,并且不能以短杠开头,比如 my-element、awesome-button 之类都是可以的。第二个参数是注册的组件的 class,直接将继承的子类类名传入即可,当然也可以直接写一个匿名类:

window.customElements.define('my-element', class extends HTMLElement {  ...});

注册之后,我们就可以使用了,可以直接在 html 文档中写对应的标签,比如:,也可以通过 document.createElement(‘my-element’) 来创建,用法与普通标签几乎完全一样。但要注意的是,虽然 html 标准中说部分标签可以不关闭或是自关闭(
或是
),但是只有规定的少数几个标签允许自关闭,所以,在 html 中写 Custom Elements 的节点时必须带上关闭标签。

由于 Custom Elements 是通过 JavaScript 来定义的,而一般 js 文件都是通过 标签外联的,所以 html 文档中的 Custom Elements 在 JavaScript 未执行时是处于一个默认的状态,浏览器默认会将其内容直接显示出来。为了避免这样的情况发生,Custom Elements 在被注册后都会有一个 :defined CSS 伪类而在注册前没有,所以我们可以通过 CSS 选择器在 Custom Elements 注册前将其隐藏起来,比如:

my-element:not(:defined) {  display: none;}

或者 Custom Elements 也提供了一个函数来检测指定的组件是否已经被注册:customElements.whenDefined(),这个函数接受一个组件名参数,并返回一个 Promise,当 Promise 被 resolve 时,就表示组件被注册了。

这样,我们就可以放心的在加载 Custom Elements 的 JavaScript 的 标签上使用 async 属性来延迟加载了(当然,如果是使用 ES6 Modules 形式的话默认的加载行为就会和 defer 类似)。

1241246191307-5bc7f1ac6b9fe_articlex.png

Custom Elements + Shadow DOM

使用 Custom Elements 来创建组件时,通常会与 Shadow DOM 进行结合,利用 Shadow DOM 的隔离性,就可以创造独立的组件。

通常在 Custom Elements 的 constructor() 构造函数中去创建 Shadow DOM,并对 Shadow DOM 中的节点添加事件监听、对特定事件触发原生 Events 对象。

正常编写 html 文档时,我们可能会给 Custom Elements 添加一些子节点,像这样:

Title

Content

,而我们创建的 Shadow DOM 又拥有其自己的结构,怎样将这些子节点放置到 Shadow DOM 中正确的位置上呢?

在 React 中,这些子节点被放置在 props 的 children 中,我们可以在 render() 时选择将它放在哪里。而在 Shadow DOM 中有一个特殊的标签:,这个标签的用处就如同其字面意思,在 Shadow DOM 上放置一个“插槽”,然后 Custom Elements 的子节点就会自动放置到这个“插槽”中了。

有时我们需要更加精确地控制子节点在 Shadow DOM 中的位置,而默认情况下,所有子节点都会被放置在同一个 标签下,即便是你写了多个 。那怎样更精确地对子节点进行控制呢?

默认情况下,Fallback 这样的是默认的 ,只有第一个默认的 会有效,将所有子节点全部放进去,如果没有可用的子节点,将会显示默认的 Fallback 内容(Fallback 可以是一棵子 DOM 树)。

标签有一个 name 属性,当你提供 name 后,它将变为一个“有名字的 ”,这样的 可以存在多个,只要名字各不相同。此时他们会自动匹配 Custom Elements 下带 slot 属性并且 slot 属性与自身 name 相同的子节点,像这样

  

Others

Animals

Fruits

Cat
Apple
Banana
flower
pencil
Dog
peach
red
class MyList extends HTMLElement {  constructor() {    super();    const root = this.attachShadow({ mode: 'open' });    const template = document.getElementById('list');    root.appendChild(document.importNode(template.content, true));  }}customElements.define('my-list', MyList);

这样就可以得到如图所示的结构,#shadow-root (open) 表示这是一个开放的 Shadow DOM,下面的节点是直接从 template 中 clone 过来的,浏览器自动在三个 标签下放置了几个灰色的

节点,实际上这些灰色的

节点表示的是到其真实节点的“引用”,鼠标移动到他们上会显示一个 reveal 链接,点击这个链接即可跳转至其真实节点。

1523399701-5bc7f1ce6b75a_articlex.png

这里我们可以看到,虽然 下的子节点是乱序放置的,但是只要是给定了 slot 属性,就会被放置到正确的 标签下。注意观察其中有一个

flower

,这个节点由于指定了 slot=”other”,但是却找不到匹配的 标签,所以它不会被显示在结果中。

在为 Custom Elements 下的 Shadow DOM 设置样式的时候,我们可以直接在 Shadow DOM 下放置 标签,也可以放置 ,Shadow DOM 下的样式都是局部的,所以不用担心会影响到 Shadow DOM 的外部。并且由于这些样式仅影响局部,所以对性能也有很大的提升。

在 Shadow DOM 内部的样式中,也有一些特定的选择器,比如 :host 选择器,代表着 ShadowRoot,这类似于普通 DOM 中的 :root,并且它可以与其他伪类组合使用,比如当鼠标在组件上时::host(:hover),当组件拥有某个 class 时::host(.awesome),当组件拥有 disabled 属性时::host([disabled])……但是 :host 是拥有继承属性的,所以如果在 Custom Elements 外部定义了某些样式,将会覆盖 :host 中的样式,这样就可以轻松地实现各式各样的“主题风格”了。

为了实现自定义主题,我们还可以使用 Shadow DOM 提供的 :host-context() 选择器,这个选择器允许检查 Shadow DOM 的任何祖先节点是否包含指定选择器。比如如果在最外层 DOM 的 或

上有一个 class:.night,则 Shadow DOM 内就可以使用 :host-context(.night) 来指定一个夜晚的主题。这样可以实现主题样式的继承。

还有一种样式的定义方式是利用 CSS 变量。我们在 Shadow DOM 中使用变量来指定样式,比如:background-color: var(–bg-colour, #0F0);,这样就可以在 Shadow DOM 外面指定 –bg-colour 变量来设置样式了,如果没有指定变量,将使用默认的样式颜色 #0F0。

有时我们需要在 Shadow DOM 内部使用完全自定义的样式,比如字体样式、字体大小,如果任由其继承可能导致布局错乱,而每次在组件外面指定样式又略显麻烦,并且也破坏了组件的封装性。所以,Shadow DOM 提供了一个 all 属性,只要指定 :host{ all: initial; } 就可以重置所有继承的属性。

Demo

Web Components 的 Demo 在网上已经有很多了,这是我 2 年前初次接触 ES6 与 Web Components 的时候写的一个 Demo:https://github.com/jinliming2/Calendar-js,一个日历,当时还是 v0 的规范,并且在 Firefox 下还存在会导致 Firefox 崩溃的 Bug(感觉是 Firefox 在实现 Shadow DOM 时的 Bug)。目前这个 Demo 已经不能在 Firefox 下运行了,因为 Firefox 已经删除了 v0 规范,开始实行 v1 标准了,所以近期我可能会重构一下这个 Demo。

以上就是你知道原生HTML组件是什么吗?原生HTML组件的介绍的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1547235.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月21日 19:00:21
图文详解如何用html5 canvas画一条直线
下一篇 2025年12月21日 19:00:42

相关推荐

  • 修复Django电商项目中AJAX过滤产品列表图片不显示问题

    在Django电商项目中,当使用AJAX动态加载过滤后的产品列表时,常遇到图片无法正常显示的问题。这通常是由于前端模板中图片加载方式(如data-setbg属性结合JavaScript库)与AJAX动态内容更新机制不兼容所致。解决方案是直接在AJAX返回的HTML中使用标准的标签来渲染图片,确保浏览…

    2026年5月10日
    000
  • 修复点击时按钮抖动:CSS垂直对齐实践

    本文探讨了在Web开发中,交互式按钮(如播放/暂停按钮)在点击时发生意外垂直位移的问题。通过分析CSS样式变化对元素布局的影响,我们发现这是由于按钮不同状态下的边框样式和内边距改变,以及默认的垂直对齐行为共同作用所致。核心解决方案是利用CSS的vertical-align属性,将其设置为middle…

    2026年5月10日
    000
  • 如何在HTML中插入表单元素_HTML表单控件与输入类型使用指南

    HTML表单通过标签构建,包含action和method属性定义数据提交目标与方式,常用input类型如text、password、email等适配不同输入需求,配合label、required、placeholder提升可用性,结合textarea、select、button等控件实现完整交互,是…

    2026年5月10日
    000
  • 前端缓存策略与JavaScript存储管理

    根据数据特性选择合适的存储方式并制定清晰的读写与清理逻辑,能显著提升前端性能;合理运用Cookie、localStorage、sessionStorage、IndexedDB及Cache API,结合缓存策略与定期清理机制,可在保证用户体验的同时避免安全与性能隐患。 前端缓存和JavaScript存…

    2026年5月10日
    100
  • HTML5网页如何实现手势操作 HTML5网页移动端交互的处理技巧

    首先利用原生touch事件实现滑动判断,再通过preventDefault解决滚动冲突,接着引入Hammer.js处理复杂手势,最后通过优化点击区域、避免事件冲突和增加视觉反馈提升体验。 在移动端浏览器中,HTML5网页可以通过触摸事件实现手势操作,提升用户体验。虽然原生JavaScript提供了基…

    2026年5月10日
    000
  • JavaScript 闭包:理解闭包原理与内存泄漏问题

    闭包是函数访问其外部作用域变量的能力,即使外部函数已执行完毕。如 inner 函数引用 outer 中的 count,形成闭包,使变量持久存在。闭包本身无害,但可能因延长变量生命周期导致内存泄漏,例如事件监听器引用大对象时。若未及时清理 DOM 事件或定时器,闭包会阻止垃圾回收,造成内存占用过高。解…

    2026年5月10日
    000
  • JavaScript 动态菜单点击高亮效果实现教程

    本教程详细介绍了如何使用 JavaScript 实现动态菜单的点击高亮功能。通过事件委托和状态管理,当用户点击菜单项时,被点击项会高亮显示(绿色),同时其他菜单项恢复默认样式(白色)。这种方法避免了不必要的DOM操作,提高了性能和代码可维护性,确保了无论点击方向如何,功能都能稳定运行。 动态菜单高亮…

    2026年5月10日
    200
  • html5怎么画实线_HTML5用CSS border-style:solid画元素实线边框【绘制】

    可通过CSS的border-style属性设为solid添加实线边框:一、内联样式用border:2px solid #000;二、内部样式表统一设置如div{border:1px solid #333};三、外部CSS文件定义.my-box{border:3px solid red}并引入;四、单…

    2026年5月10日
    100
  • JavaScript函数中插入加载动画(Spinner)的正确方法

    本文旨在解决在JavaScript函数中插入加载动画(Spinner)时遇到的异步问题。通过引入async/await和Promise.all,确保在数据处理完成前后正确显示和隐藏加载动画,提升用户体验。我们将提供两种实现方案,并详细解释其原理和优势。 在Web开发中,当执行耗时操作时,显示加载动画…

    2026年5月10日
    000
  • 动态更新圆形进度条:JavaScript成绩计算器集成指南

    本文档旨在指导开发者如何将JavaScript成绩计算系统与动态圆形进度条集成,实现可视化展示平均成绩。我们将详细讲解如何修改现有的JavaScript代码,使其在计算出平均分后,能够动态更新圆形进度条的进度,从而提供更直观的用户体验。本文档包含详细的代码示例和注意事项,帮助开发者轻松实现这一功能。…

    2026年5月10日
    000
  • JavaScript计算器开发:解决数值显示与初始化问题

    本教程深入探讨了使用JavaScript构建计算器时常见的数值显示异常问题,特别是由于类属性未初始化导致的`Cannot read properties of undefined`错误。我们将详细分析问题根源,并通过在构造函数中调用初始化方法来解决该问题,同时优化显示逻辑,确保计算器功能稳定且界面显…

    2026年5月10日
    000
  • 使用 Ajax 和 FormData 实现文件上传及文本数据提交的完整教程

    本文旨在解决在使用 Ajax 和 FormData 进行文件上传时,遇到的 $_POST 和 $_FILES 为空的问题。通过详细的代码示例和解释,我们将展示如何正确地构建 FormData 对象,并通过 Ajax 将文件和文本数据发送到服务器端,同时避免常见的错误配置,确保数据能够成功地被 PHP…

    2026年5月10日
    000
  • JavaScript 高效判断页面所有复选框状态的技巧与实践

    本文旨在提供一套高效且专业的javascript方法,用于判断网页中所有复选框的选中状态。我们将探讨如何利用`array.some()`快速确定是否有未选中的复选框(进而判断是否全部选中),以及如何使用`array.filter()`统计选中和未选中的复选框数量。通过优化dom元素选择和数组操作,提…

    2026年5月10日
    000
  • 解决Persistent UTM代码导致链接意外添加问号的问题

    本文旨在解决在使用JavaScript持久化UTM参数时,链接在没有UTM参数的情况下被意外添加问号的问题。通过分析问题代码,找出错误原因,并提供修正后的代码示例,确保只有当存在UTM参数时,链接才会被添加相应的参数。同时,强调了代码的健壮性和可维护性,避免不必要的修改和潜在的错误。 在使用Java…

    2026年5月10日
    200
  • html标签如何读_HTML标签(语义化/结构)阅读与理解方法

    答案是掌握HTML标签的语义化含义与结构作用。理解HTML需从语义化入手,使用如article、nav、header等标签准确表达内容意义,提升可访问性、SEO和代码可维护性;阅读时应从外到内分析结构,识别页面骨架,区分语义标签与非语义标签(如div、span)的合理使用场景,避免仅凭外观选择标签,…

    2026年5月10日
    000
  • 从 JavaScript 获取 URL 并在 PHP DataGrid 中使用

    本文档旨在指导开发者如何从 JavaScript 函数中获取 URL,并将其动态应用于 PHP DataGrid。通过前端 JavaScript 动态生成 API 地址,并将其传递给后端的 PHP DataGrid,实现数据根据用户会话动态加载。 动态配置 DataGrid 的 URL 在构建动态 …

    2026年5月10日
    000
  • JavaScript 中使用多个 querySelector 更新页面元素

    本文旨在讲解如何在 JavaScript 的 if 语句中使用多个 querySelector 来更新不同的页面元素,并提供示例代码和注意事项,帮助开发者理解并应用此技术。通过该方法,可以根据特定条件动态修改页面内容,提升用户体验。 使用 querySelector 在 if 语句中更新多个元素 在…

    2026年5月10日
    100
  • HTML5代码如何制作3D效果 HTML5代码中WebGL的入门实例

    最核心的技术是WebGL,通过HTML5的canvas结合JavaScript使用WebGL API渲染3D图形。首先创建包含canvas的HTML页面,获取WebGL上下文,编写GLSL着色器定义顶点位置与颜色,编译着色器并链接成程序,接着设置顶点缓冲区传入三角形坐标和颜色数据,引入gl-matr…

    2026年5月10日
    000
  • 基于两数组数据计算结果排序的 React 教程

    本教程针对 React 应用中需要根据两个独立数组的数据计算结果进行排序的场景,提供了一种高效的解决方案。通过使用 JavaScript 的 `reduce` 和 `map` 方法,将两个数组根据唯一标识符进行合并,从而简化排序逻辑,提高代码的可读性和可维护性。避免了复杂的嵌套循环或同步迭代,提供了…

    2026年5月10日
    000
  • 控制HTML Canvas颜色空间输出24位深度TIFF图像

    本教程详细介绍了如何在web前端环境中,特别是结合`html2canvas`和`canvas-to-tiff`库时,通过明确设置html canvas的颜色空间为`srgb`,从而确保输出24位深度的tiff图像。文章将提供具体的javascript代码示例,并解释其原理,帮助开发者解决canvas…

    2026年5月10日
    100

发表回复

登录后才能评论
关注微信