什么是好JS:
l 代码简洁,可以令其他人更清晰明了的理解相关内容
l 各种功能分离,显示、运算、数据的相关代码分开,HTML/CSS/JS各司其职
l 避免不必要的由JS直接操作的样式、纯展示类尽量寻求零JS方案
从多种角度思考网页的功能实现
代码耦合度:
--结构(html)、表现(CSS)、行为(JS)是否分开?现有的JS代码是否绕过了CSS代码直接改变了网页的表现?尽量使代码各司其职,让各个部分的代码功能清晰明了。
--如果对行为的检测并非必要,则可以不使用JS。e.g.双状态切换的点击事件可以通过在html中设置checkbox来代替JS中的点击listener
JS基本七种数据类型为:1.String类型,用于表示字符串;2.Number类型,用于表示数字;3.Boolean类型,用于表示真假取值;4.Symbol类型,代表唯一的特征值;5.Undefined类型;6.Null类型;7.Object类型,用于存储数据块。
表达式和语句:表达式指一个为了得到返回值的计算式,而语句是为了完成某种任务而进行的操作。比如 var a = 7 + "2" 是一行赋值语句,其中 7 + "2" 是表达式。
编写过程中遇到的问题
JS放在head中不生效
解决方法:
1. script代码无法执行是因为DOM元素还未生成,当浏览器下载完JS时会发现item为空,而html页面是在执行了<body>之后才会显示。JavaScript本身就是单线程的,在没有使用两个属性(async和defer)的情况下,只要把script代码块放到<body>下就可以正常执行。
2. 在JS中用window.onload=function(){//JS代码},window.onload() 方法用于在网页加载完毕后立刻执行的操作,即当 HTML 文档加载完毕后,立刻执行某个方法。该方法可以避免因为引用过多的<script>标签而令<body>的结构变得复杂化
e.g.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="./style.css"/>
<script src="function.js"></script>
</head>
<body>
<div id="my-slider" class="slider-list">
<ul>
<li class="slider-list__item">
<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--selected">
<img src="https://p4.ssl.qhimg.com/t01331ac159b58f5478.jpg"/>
</li>
</ul>
</div>
</body>
</html>
#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;
}
class Slider{
constructor(id){
this.container = document.getElementById(id);//获取页面元素
this.items = this.container//将页面元素按id转换为items
.querySelectorAll('.slider-list__item, .slider-list__item--selected');
}
getSelectedItem(){
const selected = this.container
.querySelector('.slider-list__item--selected');
return selected
}
getSelectedItemIndex(){
return Array.from(this.items).indexOf(this.getSelectedItem());
}
slideTo(idx){
const selected = this.getSelectedItem();
if(selected){
selected.className = 'slider-list__item';
}
const item = this.items[idx];
if(item){
item.className = 'slider-list__item--selected';
}
}
slideNext(){
const currentIdx = this.getSelectedItemIndex();
const nextIdx = (currentIdx + 1) % this.items.length;
this.slideTo(nextIdx);
}
slidePrevious(){
const currentIdx = this.getSelectedItemIndex();
const previousIdx = (this.items.length + currentIdx - 1)
% this.items.length;
this.slideTo(previousIdx);
}
}
window.onload=function(){
const slider = new Slider('my-slider');
slider.slideTo(0);
setInterval(()=>{
slider.slideNext();
}, 1000);//每隔一秒执行一次
}
以上代码实现了幻灯片的功能,即每秒切换一次图片,可以看到JS代码中用了window.onload()的方法,在等待html文档执行完毕后再运行,而html中只负责引入外部文件,以降低JS及html的耦合性
监听事件(addEventListener): 对控件的事件进行监听,e.g.定义一个controller控件,当鼠标触碰到控件时会触发JS中的controller.addEventListener('mouseover', evt=>{})功能
插件化:功能解耦
l 将控制元素抽取成插件
l 插件和组件之间通过依赖注入的方式建立联系
当使用JS构建复杂的UI时,可能会令构造函数变得十分复杂,这时可以用注入依赖的方法以降低复杂度
比如上述图片中的轮播图效果,可以用插件化的方式将导航栏小圆点、前后按钮的功能通过依赖来注入轮播图中,以降低控件和组件的耦合度,让附加的控件脱离class主体而成为独立的功能
function pluginNext(slider){
const next = slider.container.querySelector('.slide-list__next');
if(next){
next.addEventListener('click', evt => {
slider.stop();
slider.slideNext();
slider.start();
evt.preventDefault();
});
}
}
class Slider{
registerPlugins(...plugins){
plugins.forEach(plugin => plugin(this));
}
start(){}
stop(){}
.
.
.
}
const slider = new Slider('my-slider');
slider.registerPlugins(pluginNext);
如果想让该插件功能失效的话在registerPlugins中删除掉pluginNext即可
模板化:改进插件/组件解耦
如果仅仅是插件化,插件及组件的模板仍然需要从html中创建。这样会导致即使删除掉JS中的插件,html中渲染的插件组件仍然存在,模板化的目标为让插件及主体的创建彻底脱离html,让JS负责所有组件的创建,这样子在删除JS中的插件时,不仅能令插件的功能失效,同时可以从页面中删除插件的组件
class Slider{
constructor(id, opts = {images:[], cycle: 3000}){
.
.
.
}}
const slider = new Slider('my-slider', {images: ['https://p5.ssl.qhimg.com/t0119c74624763dd070.png',
'https://p4.ssl.qhimg.com/t01adbe3351db853eb3.jpg',
'https://p2.ssl.qhimg.com/t01645cd5ba0c3b60cb.jpg',
'https://p4.ssl.qhimg.com/t01331ac159b58f5478.jpg'], cycle:3000});
抽象化:写一个抽象类作为组件的基类,初始化组件。它有注入插件的方法及抽象的render方法