web components示例分析

2 篇文章 0 订阅

总结一下web components的使用:
在线示例

引入

单独文件引入(这样可以复用):

<link rel="import" href="./components/userCard.html">

直接写入同一个html文件内:

<template id="userCardTemplate">
    <style>
        ...
    </style>

    <div>
      ...
    </div>
</template>

生命周期

生命周期方法的执行顺序是:

定义在自定义元素的类定义中的特殊回调函数,影响其行为:

  1. connectedCallback: 当自定义元素第一次被连接到文档DOM时被调用。
  2. disconnectedCallback: 当自定义元素与文档DOM断开连接时被调用。
  3. adoptedCallback: 当自定义元素被移动到新文档时被调用。
  4. attributeChangedCallback: 当自定义元素的一个属性被增加、移除或更改时被调用。

属性/方法

1. 自定义属性
<user-card
    image="https://semantic-ui.com/images/avatar2/large/kristy.png"
    name="--"
    email="chengzan0371@163.com"
>
</user-card>
2. slot
<user-card
    image="https://semantic-ui.com/images/avatar2/large/kristy.png"
    name="--"
    email="chengzan0371@163.com"
>
    <div slot="button" onclick="changeName();">改变name</div>
</user-card>

...

<template id="userCardTemplate">
    ...
      <button class="button">
      	<slot name="button"></slot>
      </button>
    ...
</template>

user-card 的属性 slot=“button” 对应 template

3. Shadow DOM
class UserCard extends HTMLElement {
    constructor() {
        super();
        // shadow DOM 影子DOM
        this.$shadow = this.attachShadow( { mode: 'open' } );
        ...
    }
}

window.customElements.define('user-card', UserCard);

this.$shadow = this.attachShadow( { mode: ‘open’ } );
自定义元素的this.attachShadow()方法开启 Shadow DOM
this.attachShadow()方法的参数 { mode: ‘closed’ } ,表示 Shadow DOM 是封闭的,不允许外部访问。

4.样式

组件的样式应该与代码封装在一起,只对自定义元素生效,不影响外部的全局样式。所以写在里:

<template id="userCardTemplate">
    <style>
        :host {
            display: flex;
            align-items: center;
            width: 450px;
            height: 180px;
            background-color: #d4d4d4;
            border: 1px solid #d5d5d5;
            box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
            border-radius: 3px;
            overflow: hidden;
            padding: 10px;
            box-sizing: border-box;
            font-family: 'Poppins', sans-serif;
        }
        .image {
            flex: 0 0 auto;
            width: 160px;
            height: 160px;
            vertical-align: middle;
            border-radius: 5px;
        }
        ...
    </style>
	...
</template>

示例分析

1. html
<user-card
    image="https://semantic-ui.com/images/avatar2/large/kristy.png"
    name="--"
    email="chengzan0371@163.com"
>
    <div slot="button" onclick="changeName();">改变name</div>
</user-card>
...
<template id="userCardTemplate">
    <style>
        :host {
            display: flex;
            align-items: center;
            width: 450px;
            height: 180px;
            background-color: #d4d4d4;
            border: 1px solid #d5d5d5;
            box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
            border-radius: 3px;
            overflow: hidden;
            padding: 10px;
            box-sizing: border-box;
            font-family: 'Poppins', sans-serif;
        }
        .image {
            flex: 0 0 auto;
            width: 160px;
            height: 160px;
            vertical-align: middle;
            border-radius: 5px;
        }
        ...
    </style>

    <img class="image" />
    <div class="container">
      <p class="name"></p>
      <p class="email"></p>
      <button class="button"><slot name="button"></slot></button>
    </div>
</template>
2. js
class UserCard extends HTMLElement {
	// 观察属性
    static get observedAttributes() {
        return ['name', 'email'];
    }

    constructor() {
        super();

        // shadow DOM 影子DOM
        this.$shadow = this.attachShadow( { mode: 'open' } );

		// 获取到对应的tempalte元素
        this.$templateElem = document.currentScript.ownerDocument.getElementById('userCardTemplate');
        // 克隆tempalte元素内容
        this.$content = this.$templateElem.content.cloneNode(true);
		
		// 从该自定义元素获取属性
        this.$content.querySelector('img').setAttribute('src', this.getAttribute('image'));
        this.$content.querySelector('.container>.name').innerText = this.getAttribute('name');
        this.$content.querySelector('.container>.email').innerText = this.getAttribute('email');
        
        // 绑定按钮事件
        // this.$button = shadow.querySelector('button');
        // this.$button.addEventListener('click', () => {
        // // do something
        // });

		// 该自定义元素加入内容
        this.$shadow.appendChild(this.$content);
    }

	// 生命周期回调:当自定义元素第一次被连接到文档DOM时被调用
    connectedCallback() {
        // console.log('connectedCallback');
    }

	// 自定义元素属性改变的回调
    attributeChangedCallback(attr, oldVal, newVal) {
        switch(attr) {
            case 'name':
            // do something with 'foo' attribute
                // 触发重新渲染
                this.render(attr, newVal);
                break;

            case 'email':
            // do something with 'bar' attribute
                // 触发重新渲染
                this.render(attr, newVal);
                break;

        }
    }

    render(attr, newVal) {
        console.log('render...');
        this.$shadow.querySelector(`.${attr}`).innerText = newVal;
    }
}

// 定义该自定义元素
window.customElements.define('user-card', UserCard);
  
// 改变名字方法,在
function changeName() {
    document.querySelector('user-card').setAttribute('name', '程赞');
}

参考资料

MDN:https://developer.mozilla.org/zh-CN/docs/Web/Web_Components
阮一峰:Web Components 入门实例教程

目前我在练习中使用的就是这些,如果有错误的地方还望指正。
还有一个疑问就是:如何在 < user-card > 中传入自定义事件,比如 onChangeName=“changeName”
已解决:使用eval() 使用setTimeout

<user-card
    image="https://semantic-ui.com/images/avatar2/large/kristy.png"
    name="--"
    email="chengzan0371@163.com"
    onchangeNameCallback="changeCallback"
>
    <div slot="button" onclick="changeName();">hello</div>
</user-card>
class UserCard extends HTMLElement {
	...
	
	constructor() {
		...
		
		const changeNameCallback = this.getAttribute('onchangeNameCallback');
        if (changeNameCallback) {
            this.addEventListener('changeNameCallback', () => setTimeout(changeNameCallback + '()',0));
        }
		
		...
	}
	
	...
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值