网站首页 > 基础教程 正文
如果你还在寻找纯前端的,无webpack的,无server的组件封装方式,那是时候玩一玩Web Components了。
“那兼容性呢?”
“你说啥?”
“兼容性呢?”
“你说啥?”
“……”
“你说啥?”
“我知道了,那不是我的目标用户。”
“你说兼容性啊,有个东西叫Polyfill。”
起因
闲着无聊,重写一个简单的管理页面,顺手改造成Web Components,就想着写一篇上手文章,分享一下。
正文
假设我们有个简单的要死的导航,没有图片,没有样式,就是单单的nav套几个a标签,如图:
然后我们就改写成Web Components吧,至于为啥?闲的,不行吗?当然是为了不停的学习了。
原来的结构:
现在的结构:
区别就是外层的pt-nav,自定义的名字;还有那个shadow-root,这个可选,还有就是后面的open,这个可以是closed,不过建议open,原因下面说。
我们要用ES6的class语法,至于ES6的内容:请自行百度学习,如果你还不会的话。
事实上,我们先说一下逻辑,可能帮助你理解。
- 我们要自定义个class,继承自你要继承的目标element,假设我们都继承与HTMLElement;
- 在class里面编写这个自定义组件的内容;
- 告诉引擎,我们定义了一个组件,你可以把他显示出来了。
注意,你定义的这个组件,在功能上完全类比普通组件(标签),所以使用负担几乎为0。
你看到的this,shadow就当成document.querySelector之后的对象就行,顶多多几个实用的api,然后没了,一毛一样。
那么,上代码开始。
额,定义一个Components就这么简单。补充下生命周期:
本例中没有用到生命周期,具体需要接入更复杂业务。
上面我们定义了一个PtNav的组件,class那行就是定义,然后下面的customElements那里就是所说的告诉引擎。这里注意下,如果你不是继承与HTMLElement,比如继承HTMLUListElement,就是ul,则下面需要customElements.define('pt-nav', PtNav, {extends: 'ul'}),多一个参数表示具体的继承对象。
我们定义的地方有个html2template的函数,这个玩意是为了解决封装性和拓展性来的,因为Web Components基础用法是使用createElement创建,然后this.appendChild方式插入自身,或者使用innerHTML方式。但是appendChild废话太多,innerHTML不够灵活(比如外部定义属性时候),所以就有了template#id的方式来优化代码,但是template#id方式又有点画蛇添足感觉,比如你要封装一个组件,然后还得在html文件里面弄个template把模板写进去,那我不是闲的蛋疼吗?所以这里更进一步封装,使用字符串模板方式,进行了拼接处理。
至于什么是字符串模板,可以自行查阅下,挺好用的。
其实到这里为止,都是基于ES6 class的普通dom操作,而事实上也就是这样。
下面说说shadow这个东西。
代码里面有个let shadow = this.attachShadow({ mode: 'open' }),这里牵扯两个内容:
其一:有没有这个的区别。
区别在于,未使用前,函数主体是this,也就是本身这个dom,除了dom名外,其他跟原生的dom几乎没有任何区别;
而使用后(先无视后面的mode),则主体变成了shadow(不含取参数与事件),比如之前是this.appendChild,现在变成了shadow.appendChild。再就是,样式隔离。如文字描述,外部样式对它没用,同样的,他定义的style之类对外部也没有用,这个是封装很重要的一点,避免样式污染。
其二:mode的值,open与closed的区别。
简单来说,就是open时候,外部可以获取内部的dom,而closed就无法获取,反应在代码层面就是let el = document.querySelector('pt-nav')拿到后,能不能通过el.shadowRoot获取到对象。
closed为null,而open如下:
所以一般open就完事了,除非你们的私有要求极高才会用到closed。
关于clone:
这里的cloneNode(true)的作用是为了页面多次使用同一个组件的时候,每个组件互相独立,如果不做这个操作,则会互相污染。简单记就是,反正记着这么写就对了,写false或不写的都是异端。
实际使用:
这有什么好说的?
传参:
比如<pt-nav list='["1", "2", "3"]'></pt-nav>
取参数方式就是简单的this.getAttrbute('list'),注意,拿到的是字符串,如果是json需要转JSON.parse,这里有个坑,不要写成"['1', '2', '3']",就是双引号和单引号的问题,因为单引号在JSON.parse解析会挂掉……
事件:
到这里还需要描述事件吗?
this.addEventListener('click', function doClick() {
console.log('click me!')
})
完事。
补充:
this指的是这个dom,shadow指的是这个dom和内部dom的夹层,切记切记。
总结
当然,奇技淫巧还有一大堆,比如腾讯的Omi,Google的Polymer,有兴趣的都可以了解看看。
总的来说,这是个好东西,跟着标准走,准没错。
猜你喜欢
- 2024-11-17 「uniapp实战笔记」使用uni-nav-bar自定义顶部状态栏和导航栏
- 2024-11-17 VIP感觉!NAS部署OneNav个人导航页,简洁的个人书签管理应用!
- 2024-11-17 使用Chrome扩展程序生成网页骨架屏
- 2024-11-17 一文搞懂爬虫神器selenium常见操作
- 2024-11-17 17、Bootstrap 中的导航都有哪些?(必会)
- 2024-11-17 【魔改版】OneNav Extend网址导航书签系统源码
- 2024-11-17 应用HTML5和CSS3实现举报中心PC端与手机端举报页面的自适应设计
- 2024-11-17 vue.js 脚手架安装和使用(vue脚手架怎么使用)
- 2024-11-17 把喜欢的前端模版加上后台,小白速成课,不懂代码玩建站(下)
- 2024-11-17 HTML5升级的意义是什么?(html5相比原来的版本有哪些更新)
- 最近发表
- 标签列表
-
- jsp (69)
- gitpush (78)
- gitreset (66)
- python字典 (67)
- dockercp (63)
- gitclone命令 (63)
- dockersave (62)
- linux命令大全 (65)
- pythonif (86)
- location.href (69)
- dockerexec (65)
- tail-f (79)
- queryselectorall (63)
- location.search (79)
- bootstrap教程 (74)
- deletesql (62)
- linuxgzip (68)
- 字符串连接 (73)
- html标签 (69)
- c++初始化列表 (64)
- mysqlinnodbmyisam区别 (63)
- arraylistadd (66)
- mysqldatesub函数 (63)
- window10java环境变量设置 (66)
- c++虚函数和纯虚函数的区别 (66)