You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
web components 是谷歌推出的一套用于编写可重用定制元素的一项技术,截止现在,Firefox(版本63)、Chrome和Opera都已默认支持,IE则需要一些polyfill才能使用(具体在下文详细说明)在我看来,组件的一个重要意义在于可复用性,我们在一个react项目里面写的一套组件,搬到一个vue项目中,是无法使用的,需要按照vue的规则重写一个,而且以后如果随着技术的发展,又出了个新的框架,又需要重新再写一遍,这无疑增大了我们的工作量,这时候如果使用web components,可以实现一次编写,处处运行,这多舒服呀~
// 条件渲染html`${this.myBool?html`<p>Render some HTML if myBool is true</p>`:html`<p>Render some other HTML if myBool is false</p>`}`;// 列表渲染html`<ul>${this.myArray.map(i=>html`<li>${i}</li>`)}</ul>`;
简介
web components
是谷歌推出的一套用于编写可重用定制元素的一项技术,截止现在,Firefox(版本63)、Chrome和Opera都已默认支持,IE则需要一些polyfill
才能使用(具体在下文详细说明)在我看来,组件的一个重要意义在于可复用性,我们在一个react项目里面写的一套组件,搬到一个vue项目中,是无法使用的,需要按照vue的规则重写一个,而且以后如果随着技术的发展,又出了个新的框架,又需要重新再写一遍,这无疑增大了我们的工作量,这时候如果使用web components
,可以实现一次编写,处处运行,这多舒服呀~前置知识
一、自定义元素(custom-element)
自定义元素是怎么创建的呢?我们需要使用 JavaScript 定义一个类,然后使用浏览器提供的
customElements.define
方法,将我们的BaseButton
类与<base-button>
元素相关联;浏览器提供的
customElements.define
方法还有第三个参数,但是一般不会用到,如果想了解的同学可以戳一下mdn查看;为了与原生的html元素区别,我们编写的自定义组件必须使用连接符,例如
<base-button>
不能写做<basebutton>
,web components
的使用方式跟普通的html元素一样,只要引入组件后,在页面插入下面代码,就会显示base-button
二、Shadow Dom
相信大家对这个词已经不陌生了,mdn上的这张图已经很形象的解释了shadow dom的隔离性,它可以将我们编写的组件的内部结构隐藏起来,保证内部代码和外部代码不会互相影响
三、HTML模版(template)
使用过vue的同学应该对于
<template>
标签是很熟悉的,Web Components API
提供的<template>
标签,跟vue里面的用法和作用是一样的,我们可以使用它在HTML里面定义DOM:接下来就让我们通过实现下面这个最常见的
button
组件,来熟悉一下怎么一步步实现一个web component
吧。base-button(原生版本)
上面这段代码是通过原生的形式编写,其中,
attributeChangedCallback
是原生提供生命周期回调函数,有兴趣可以参考mdn文档。上面那段代码直接对dom进行了操作,有种回到了写
jq
的感觉,当然我们可以使用<template>
标签来构建html结构,但是对于一些复杂的页面构建,例如条件渲染和列表渲染,写起来还是力不从心的,那么,接下来我们就使用LitElement
来实现这一个组件吧。LitElement简单介绍
LitElement 是随着google的
polymer
框架的3.0版本一起推出的,它可用于创建快速、轻量级的 Web 组件,可在任何具有任何框架的网页中运行。LitElement 使用 lit-html 渲染成 shadow DOM,并添加 API 来管理属性和属性。默认情况下会监听属性,并且元素会在其属性更改时异步更新。虽然官网是英文版的,但是因为例子比较多,读起来也不算很费劲,下面简单讲一下主要的使用方法。起步
安装lit-element
如果需要兼容
Edge
和一些不支持web components的浏览器,可以安装一下WebComponents polyfills
:定义和渲染一个template
通过定义一个类继承自
LitElement
,用html
标签函数包裹html
字符串的形式编写模版,通过get properties
定义属性类型,然后遵从web component
的语法导出一个类,这就是最基本的LitElement
组件了。当然也可以很简单地实现条件渲染和列表渲染,其他更多的使用方法可以查看官网。properties和attributes
定义
property
是DOM中的属性,是JavaScript里的对象,attribute
就是dom
节点自带的属性,例如html
中常用的id、class、title、align
等,它的值只能够是字符串;property
能够从attribute
中得到同步;attribute
不会同步property
上的值;attribute
和property
之间的数据绑定是单向的,attribute
->property
;property
和attribute
上的任意值,都会将更新反映到HTML页面中;声明properties
property options属性
reflect:默认值为false,由定义2、3、4可以知道,property和attribute之间数据绑定是单向的,通过reflect我们可以设置property的值变化后是否同步到attribute,实现数据的双向绑定。
attribute: 默认值为true,用于设置当前property是否独立于attribute,即是否新增一个与property同样名字的attribute ,如果为false,converter,reflect,type都会被忽略。
type:reflect为true时,根据定义1,因为property是js对象类型,而attribute只会是字符串类型,lit-element 会根据默认的转换规则将property转换为attribute,具体的转换规则如下:
attribute to property:
String
类型时:当attribute被定义了,设置property为该值,不用转换;Number
类型时:当attribute被定义了,将property设置为Number(attributeValue);Boolean
类型时:当attribute 非空,设置property为true,如果为null或者undefined,设置property为false ;Object
或者Array
类型时:设置property为JSON.parse(attribueValue)property to attribute:
String
类型时:当property为null,移除该attribute,当property为undefined,不修改attribute值,非null或者undefined,则设置该attribute为property的值;Number
类型时:当property为null,移除该attribute,当property为undefined,不修改attribute值,非null或者undefined,则设置该attribute为property的值;Boolean
类型时:当property为true,创建对应的attribute,为false,移除该attribute;Object
或者Array
类型时:当property为null或者undefined时,移除对应的attribute,不为null或者undefined时,设置attribute的值为JSON.stringify(propertyValue)
。总结一下:了解了上面的
property
和attribute
的定义和转换关系对于我们编写lit-element
有什么用呢?主要的作用是为了做变化监听:1、当通过
this.setAttribut('myprop', 'hello world')
改变attribute的值时,我们可以通过attributeChangedCallback 获得变化的属性名,变化前的值和变化后的值,方便我们对视图进行更新,但是如果设置myProp: {attribute: false} ,attributeChangedCallback则不会监听到该属性的变化,需要注意的是,这里变化的属性名默认为小写格式,即myProp对应为myprop
,当然也可以通过myProp: {attribute: 'my-prop'}进行自定义。2、我们一般比较常见的改变属性值的方式是通过this.xxx 进行修改,也就是修改property的值,这时如果我们也想监测变化的话,可以通过设置myProp: {reflect: true},将property的值同步到
attribute
,这样我们就可以通过attributeChangedCallback来获取变化,从而更新视图了。事件
在react中,数据是单向流动的,数据只会由父级传给子级,如果子级触发了某个事件,想要通知上级,一般是通过父级传递一个方法进入子级,子级调用这个方法,从而达到数据的同步。
在lit-element中,我们可以转换下思维,在我们需要通知上层组件做一些更新操作时,我们可以dispatch一个事件,事件中可以携带信息,然后在父级监听对应的事件,从而达到数据的更新。
CustomEvent和Event
顾名思义,
customEvent
是指自定义事件,而Event
则表示标准事件,如click
、touchStart
、keydown
等。bubbles和composed
shadow Dom
里面触发的一个冒泡事件,在到达shadow Dom
边界就会停止冒泡,同时设置composed
和bubbles
为true
可以使得事件可以穿过shadow Dom
边界。生命周期
这里简单列举下常用的几个生命周期:
connectedCallback
:组件被加载到dom
时触发disconnectedCallback
:组件从dom
中被移除时触发attributeChangedCallback
:组件的attribute
发生变化时触发firstUpdated
: 组件被第一次更新时触发,在组件被创建后只会触发一次updated
: 组件视图更新或重新渲染时触发那么,接下来就使用lit-element来编写一下我们的base-button组件吧~
base-button组件(LitElement版本)
总结:web component 是个人觉得目前可以用于编写组件的一个较好的方案,不会受到项目所选的框架限制,但因为原生语法编写模版在一些复杂场景上(例如条件渲染和列表渲染)的力不从心,我们引入了lit-element,并对lit-element语法进行了简单的介绍,也实现了对应版本的base-button组件,我也改造了一个时间范围选择器组件,将vue版本转换为了lit-element版本,之后也会整理一下并上传到github。
The text was updated successfully, but these errors were encountered: