前端星计划之高复用的组件的设计
前言
感觉这次去北京参加的前端星计划,收获非常的大,特别是月影大大讲的js课程,让我感觉再次之前根本就没有学到js的精髓,一直都是在为了完成某个页面而去写这个页面,根本没有去考虑这个页面接下来的维护,所有的变量全部都耦合在一起,为了改一个点,你需要该无数地方的代码。然后在更多的时候都是在写重复的代码,根本没有考虑到组件的复用的问题。然后对es6很多新的方法都没有接触过。总而言之,就是自己太菜了,还要加把劲的学习。
轮播图组件实现大概思想
轮播组件之结构设计
在编写一个组件的时候你先需要把组件的样式给写出来,比如说,我们要做一个轮播的组件,然后就是几张图片叠加在一起,需要哪张图片就显示哪张图片,这个是基础的样式。
- 图片结构是一个列表型结构,所以主体用
- 使用 css 绝对定位将图片重叠在同一个位置
- 轮播图切换的状态使用修饰符(modifier)
- 轮播图的切换动画使用 css transition
轮播组件之API设计
在你想好要做组件之前,你需要对这个组件进行api的设置。建一个类,然后在类中写各种需要的方法。
轮播组件之控制流设计
在类之中的方法之间还是会有一定的耦合,这样的话可以采用自定义事件的方法,只需要绑定事件就可以
控制结构
<a class="slide-list__next"></a>
<a class="slide-list__previous"></a>
<div class="slide-list__control">
<span class="slide-list__control-buttons--selected"></span>
<span class="slide-list__control-buttons"></span>
<span class="slide-list__control-buttons"></span>
<span class="slide-list__control-buttons"></span>
</div>
自定义事件
const detail = {index: idx}
const event = new CustomEvent('slide', {bubbles:true, detail})
this.container.dispatchEvent(event)
轮播图之各种优化
在完成上面的后你还可以进行各种优化,比如说,依赖注入,把每一个小插件作为一个依赖注入到组件中,需要这个依赖就注入一下就好,不需要就不要管他。代码也不会报错。然后你还可以进行插件化和模版化把每个依赖的小插件的html代码写在js中,只有使用了这个插件才会渲染这段代码。
拖动条组件的设计
样式设计
大概写出来是这个样子,左边是输入框,通过输入框输入可以改变右边的进度,然后右边是可以拖动的拖动条,拖动后可以改变左边的输入框的值。
API设计
这个组件大概包括以下的几个接口
实现思路
由于需要数据双向绑定,这里使用的方法是,在你改变数据的时候不是直接改变数据,而是调用setData方法来改变数据,调用setData方法里面会调用数据的渲染方法,就和小程序一样,这样改变数据才会激活视图的更新。
然后clickDot是实现点击小圆点来拖动的效果。对小圆点设置一个mousedown事件,发生按下去的事件后对窗口设置一个mousemove事件随时改变小圆点的位置,当松开的时候就清楚mousemove事件。
同时在小圆点动的时候激活一个自定义的移动事件,为了响应的更改input中的数据。
改变进度和小圆点的位置的时候,全部依赖的是定义的数据,所以渲染界面只需要setData一下就可以了。
然后对于输入框,如果界面改变了,就会激活自定义事件,监听一下,然后通过getPercentage来获得当前的数据。如果输入框里面的值变了,然后调用setData方法就好了。
总结反思
这是第一次使用类的方式来写组件,基本实现了数据的双向绑定,然后在new的时候你可以配置一些基本的参数,然后还学会了自定义事件,在此之前是通过回调函数来实现的。但是还是有许多需要改进的地方,组件还可以细分成几个小的插件,在新建的时候就可以通过依赖注入的方式来注入想要的插件
代码
html
<div id="control">
<div class="sensitivity" id="sensitivity">
<div class="line" id="line">
<div class="progress" id="progress"></div>
</div>
<div class="dot"></div>
</div>
</div>
css
*{
margin: 0;
padding: 0;
}
.sensitivity {
width: 100px;
position: relative;
}
.line {
width: 100%;
height: 2px;
background-color: #cccccc;
border-radius: 1px;
overflow: hidden;
}
.progress {
height: 2px;
width: 0;
background-color: #57A3F3;
-webkit-transition: all .2s;
-moz-transition: all .2s;
-ms-transition: all .2s;
-o-transition: all .2s;
transition: all .2s;
}
.dot {
cursor: pointer;
height: 6px;
width: 6px;
border: 2px solid #57A3F3;
box-sizing: border-box;
background-color: #ffffff;
border-radius: 50%;
position: absolute;
top: -2px;
left: -3px;
-webkit-transition: all .2s;
-moz-transition: all .2s;
-ms-transition: all .2s;
-o-transition: all .2s;
transition: all .2s;
}
.dot:hover {
cursor: pointer;
border: 1px solid #57A3F3;
}
js-滑动类
class Slide {
constructor(dot, progress, father) {
this.data = 0;
//判断是否存在
this.dot = dot;
this.progress = progress;
//父组件
this.father = father;
}
//设置数据
setData(data) {
this.data = data;
this.setPercentage()
}
//渲染方法
render() {
this.clickDot();
}
//所有监听事件来控制拖动条
clickDot() {
let sensitivity = this.father.querySelector(".sensitivity");
let dot = this.father.querySelector(".sensitivity .dot");
//自定义事件,通过监听事件来重新渲染dom
const slideEvent = new CustomEvent("slide");
dot.addEventListener("mousedown", (e) => {
document.onmousemove = (e) => {
//设置data
this.setData((e.clientX - sensitivity.offsetLeft) / sensitivity.offsetWidth * 100);
document.dispatchEvent(slideEvent);
};
document.onmouseup = () => {
document.onmousemove = null;
}
});
}
//设置百分数来改变进度
setPercentage() {
if (this.data < 0) {
this.data = 0;
}
if (this.data > 100) {
this.data = 100;
}
let sensitivityWidth = this.father.querySelector(".sensitivity").offsetWidth;
if (this.dot) {
this.setDot(this.data * sensitivityWidth * 0.01 - 3 + 'px');
}
if (this.progress) {
this.setProgress(this.data * sensitivityWidth * 0.01 + "px");
}
}
//得到当前的百分数
getPercentage() {
return this.data;
}
//设置点的位置
setDot(position) {
let dot = this.father.querySelector(".sensitivity .dot");
if (dot) {
dot.style.left = position;
}
}
//设置进度的位置
setProgress(position) {
let progress = this.father.querySelector(".sensitivity .progress");
if (progress) {
progress.style.width = position;
}
}
}
js-new
let father = document.querySelector("#control");
let a = new Slide(true, true, father);
a.render();
document.addEventListener("slide", (e) => {
document.querySelector("#input").value = parseInt(a.getPercentage());
});
//监听输入框改变
document.querySelector("#input").onkeyup = () => {
a.setData(document.querySelector("#input").value)
}