原生js实现组件
原生 JavaScript 实现组件
使用构造函数模式
定义一个构造函数,通过 new 关键字创建组件实例。适用于需要封装数据和方法的场景。
function Component(options) {
this.data = options.data;
this.render = function() {
document.getElementById('app').innerHTML = this.data.content;
};
}
const myComponent = new Component({
data: { content: 'Hello, World!' }
});
myComponent.render();
使用类(ES6)
通过 class 语法实现更现代的组件结构,支持继承和封装。
class Component {
constructor(options) {
this.state = options.state;
}
setState(newState) {
this.state = { ...this.state, ...newState };
this.render();
}
render() {
document.getElementById('app').innerHTML = this.state.content;
}
}
const myComponent = new Component({
state: { content: 'Initial Content' }
});
myComponent.setState({ content: 'Updated Content' });
使用闭包封装私有变量
通过闭包实现私有变量,避免外部直接修改内部状态。
function createComponent(config) {
let state = config.initialState;
function update(newState) {
state = { ...state, ...newState };
render();
}
function render() {
document.getElementById('app').innerHTML = state.text;
}
return { update, render };
}
const component = createComponent({
initialState: { text: 'Private State' }
});
component.update({ text: 'New Private State' });
基于 DOM 的自定义元素
使用 CustomElementRegistry 定义自定义 HTML 元素,支持生命周期钩子。
class MyElement extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `<p>Custom Element</p>`;
}
connectedCallback() {
console.log('Element added to DOM');
}
}
customElements.define('my-element', MyElement);
事件驱动组件
通过事件监听实现交互逻辑,适合动态 UI 更新。

function EventDrivenComponent() {
const button = document.createElement('button');
button.textContent = 'Click Me';
button.addEventListener('click', () => {
document.body.append('Button clicked! ');
});
document.body.append(button);
}
EventDrivenComponent();
关键注意事项
- 性能优化:避免频繁 DOM 操作,可使用文档片段(
DocumentFragment)批量更新。 - 解耦设计:将渲染逻辑与业务逻辑分离,例如使用观察者模式管理状态变化。
- 浏览器兼容性:自定义元素需注意 Polyfill 支持(如
@webcomponents/webcomponentsjs)。
扩展实现示例(带模板)
class TemplateComponent {
constructor(templateId, targetId) {
this.template = document.getElementById(templateId).content;
this.target = document.getElementById(targetId);
}
render(data) {
const instance = document.importNode(this.template, true);
Object.entries(data).forEach(([key, value]) => {
instance.querySelectorAll(`[data-bind="${key}"]`).forEach(el => {
el.textContent = value;
});
});
this.target.appendChild(instance);
}
}
// HTML: <template id="tpl"><div data-bind="title"></div></template>
const tc = new TemplateComponent('tpl', 'output');
tc.render({ title: 'Bound Data' });






