JavaScript|青训营笔记
这是我参与「第四届青训营 」笔记创作活动的的第3天
写好JavaScript的原则
- 让HTML,CSS,JavaScript的职能分离
- 组件封装,好的UI组件具有正确性,拓展性,复用性
- 应用函数式编程思想(数据抽象,过程抽象)
各司其职
深夜食堂案例。要有一个好的编程思想,JavaScript里面的内容部分不要出现CSS该有的内容,让他们各用各的内容,JavaScript也可以化繁为简,让其他程序员都可以看懂要表达的意思。淫荡避免不必要的由JavaScript直接的操作样式,纯展示类交互可以寻求零js方案,可以减少JavaScript的操作方案。
组件封装
电商轮播图案例。
HTML控制结构,利用无序列表:
<div id="my-slider" class="slider-list">
<ul>
<li class="slider-list__item--selected">
<img src="https://p5.ssl.qhimg.com/t0119c74624763dd070.png">
</li>
<li class="slider-list__item">
<img src="https://p4.ssl.qhimg.com/t01adbe3351db853eb3.jpg">
</li>
<li class="slider-list__item">
<img src="https://p2.ssl.qhimg.com/t01645cd5ba0c3b60cb.jpg">
</li>
<li class="slider-list__item">
<img src="https://p4.ssl.qhimg.com/t01331ac159b58f5478.jpg">
</li>
</ul>
</div>
CSS样式改变图片位置使之重叠,制作切换动画,切换状态使用的修饰符:
#my-slider{
position: relative;
width: 790px;
}
.slider-list ul{
list-style-type:none;
position: relative;
padding: 0;
margin: 0;
}
.slider-list__item,
.slider-list__item--selected{
position: absolute;
transition: opacity 1s;
opacity: 0;
text-align: center;
}
.slider-list__item--selected{
transition: opacity 1s;
opacity: 1;
}
JavaScript行为API:
getSelectedItem()当前选中的元素getSelectesItemlndex()当前选中的元素在列表中的下标slideTo()去到一张图片slideNext()轮播下一张图片slidePrevious()轮播上一张图片 js代码控制流,使用自定义事件来解耦
<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)
组件封装基本方法:
-
结构设计
-
展示效果
-
行为设计
- API功能
- event控制流 改进组件封装的方法:
-
重构:插件化 解耦,将控制元素抽取成插件,插件与组件通过依赖注入方式建立联系
-
重构:模板化 将HTML模板化,更易于扩展
class Slider{
constructor(id, opts = {images:[], cycle: 3000}){
this.container = document.getElementById(id);
this.options = opts;
this.container.innerHTML = this.render();
this.items = this.container.querySelectorAll('.slider-list__item, .slider-list__item--selected');
this.cycle = opts.cycle || 3000;
this.slideTo(0);
}
render(){
const images = this.options.images;
const content = images.map(image => `
<li class="slider-list__item">
<img src="${image}">
</li>
`.trim());
return `<ul>${content.join('')}</ul>`;
}
...
}
- 抽象
将组件通过模型抽象出来
class Component{
constructor(id, opts = {name, data:[]}){
this.container = document.getElementById(id);
this.options = opts;
this.container.innerHTML = this.render(opts.data);
}
registerPlugins(...plugins){
plugins.forEach(plugin => {
const pluginContainer = document.createElement('div');
pluginContainer.className = `.${name}__plugin`;
pluginContainer.innerHTML = plugin.render(this.options.data);
this.container.appendChild(pluginContainer);
plugin.action(this);
});
}
render(data) {
/* abstract */
return ''
}
}
组件封装的原则有封装性,扩展性,正确性,复用性,实现代码要依据HTML的结构,CSS的暂时效果,JavaScript的行为控制,组件封装是有着改进的空间,可以三次重构,插件化,模板化,抽象化都可以实现组件封装的更好效果。
高阶函数
once为了能够让“只执行一次”的需求覆盖不同的时间处理,我们可以讲这个需求剥离出来,这个过程我们称之为过程抽象
function once(fn) {
return function(...args) {
if(fn) {
const ret = fn.apply(this, args);
fn = null;
return ret;
}
}
}
高阶函数(HOF)
以函数作为参数 以函数作为返回值 常用于作为函数修饰器
function HOF0(fn) {
return function(...args) {
return fn.apply(this, args);
}
}
常用的高阶函数
- once
- throttle(节流函数)
- debounce(防抖函数)
- consumer/2(延时调用)
- iterative
编程范式
命令式与声明式:JavaScript同时拥有命令式和声明式代码
总结
写一个好的代码首先应该知道每一个对应的功能作用,让他们各司其职,这样结构不容易乱,方便检查优化代码,是自己或者其他人都可以与更好的解读性,在组价封装的时候也可以用重构,警醒代码改进优化,其中有插件化,模板化,抽象化。JavaScript也有一个有点就是同时拥有命令式和声明式代码。
这是我的总结,若有不到位的地方可以随时提出进行修改。