前端星计划之高复用的组件的设计

前言

感觉这次去北京参加的前端星计划,收获非常的大,特别是月影大大讲的js课程,让我感觉再次之前根本就没有学到js的精髓,一直都是在为了完成某个页面而去写这个页面,根本没有去考虑这个页面接下来的维护,所有的变量全部都耦合在一起,为了改一个点,你需要该无数地方的代码。然后在更多的时候都是在写重复的代码,根本没有考虑到组件的复用的问题。然后对es6很多新的方法都没有接触过。总而言之,就是自己太菜了,还要加把劲的学习。

轮播图组件实现大概思想

轮播组件之结构设计

在编写一个组件的时候你先需要把组件的样式给写出来,比如说,我们要做一个轮播的组件,然后就是几张图片叠加在一起,需要哪张图片就显示哪张图片,这个是基础的样式。

  1. 图片结构是一个列表型结构,所以主体用
  2. 使用 css 绝对定位将图片重叠在同一个位置
  3. 轮播图切换的状态使用修饰符(modifier)
  4. 轮播图的切换动画使用 css transition

轮播组件之API设计

在你想好要做组件之前,你需要对这个组件进行api的设置。建一个类,然后在类中写各种需要的方法。
image

轮播组件之控制流设计

在类之中的方法之间还是会有一定的耦合,这样的话可以采用自定义事件的方法,只需要绑定事件就可以

控制结构

<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中,只有使用了这个插件才会渲染这段代码。

拖动条组件的设计

样式设计

大概写出来是这个样子,左边是输入框,通过输入框输入可以改变右边的进度,然后右边是可以拖动的拖动条,拖动后可以改变左边的输入框的值。

image

API设计

这个组件大概包括以下的几个接口

image.png

实现思路

由于需要数据双向绑定,这里使用的方法是,在你改变数据的时候不是直接改变数据,而是调用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)
	}
posted @ 2018-05-19 22:25  谢大帅哥  阅读(210)  评论(0编辑  收藏  举报