Ⅰ- 壹 - 放大镜效果:
Ⅱ - 贰 - HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script type="module">
import ZoomMenu from "./js/ZoomMenu.js";
// import CarouselMenu from "./js/CarouselMenu.js";
//小轮播图数组
var list=["a_icon.jpg","b_icon.jpg","c_icon.jpg","d_icon.jpg","e_icon.jpg","f_icon.jpg","g_icon.jpg","h_icon.jpg","i_icon.jpg","j_icon.jpg"]
//实例化ZoomMenu 传入数组
let zoomMenu=new ZoomMenu(list);
//执行zoomMenu方法
zoomMenu.appendTo(document.body);
// let carouselMenu=new CarouselMenu(list);
// carouselMenu.appendTo(document.body);
</script>
</body>
</html>
Ⅲ - 叁 - js
js面向对象开发:有三个模块分别为:
- Zoom .js 是放大镜的封装
- CarouselMenu.js 轮播图的封装
- ZoomMenu.js 为连接1,2的实现
- 用到了Utils.js工具类
一 Zoom .js 是放大镜的封装
import Utils from "./Utils.js";
export default class CarouselMenu {
smallWidth = 450;//small容器的宽度
maskWidth = 303.75;// mask容器宽度
zoomWidth = 540;//zoom容器宽度
constructor() {
//this.elem:储存createElem()返回的div 为创建的所有元素
this.elem = this.createElem();
}
//创建容器 div>(div#small>div#mask)+div#zoom
createElem() {
//判断this.elsm如果有存入的值 直接跳出不执行下面代码 性能优化
if (this.elem) return this.elem;
//创建div容器
let div = Utils.ce("div", {
position: "absolute",
});
//在div容器下面添加以下内容
div.innerHTML =
"<div class='small' id='small'>" +
"<div class='mask' id='mask'></div>" +
"</div>" +
"<div class='zoom' id='zoom'></div>"
;
//添加css样式的函数
this.setStyle();
//这个方法会把所有具备id的元素,放在当前对象中
//列如id是small的div,执行后就能通过this.small直接获取
Utils.getIdElem(div, this);//这里的this是当前这个类
//把这个事件函数储存在mouseHanlder,有利于执行完后关闭事件
this.mouseHanlder=e=>this.smallMouseHandler(e);
//small容器添加事件
this.small.addEventListener("mouseenter", this.mouseHanlder);//鼠标进入事件
//接收 //小轮播图的小图添加鼠标经过事件抛发的事件 CarouselMenu.js 执行函数
document.addEventListener("Change_Menu_Img",e=>this.setImage(e.src));
return div;
}
//div的样式 small:存放的容器 mask:移动的那个小容器 zoom:放大镜效果的容器
setStyle() {
Utils.insertCss(".small", {
width: this.smallWidth + "px",
height: this.smallWidth + "px",
position: "absolute",
border: "1px solid #000000",
});
Utils.insertCss(".mask", {
width: this.maskWidth + "px",
height: this.maskWidth + "px",
backgroundColor: "rgba(200,170,0,0.3)",
position: "absolute",
display: "none"
});
Utils.insertCss(".zoom", {
width: this.zoomWidth + "px",
height: this.zoomWidth + "px",
border: "1px solid #CCCCCC",
position: "absolute",
left: this.smallWidth + 2 + "px",
display: "none"
});
}
//执行 zoom.addendTo(document.body);
appendTo(parent) {
parent.appendChild(this.elem);
}
//鼠标事件事件方法
smallMouseHandler(e) {
//事件类型
switch (e.type) {
//鼠标进入事件
case "mouseenter":
//如果this.rect没有值 this.small这个div的元素位置赋值给this.rect
//e.currentTarget始终是监听事件者,即 直接调用addEventlistener那个节点 document
if (!this.rect) this.rect = this.small.getBoundingClientRect();//getBoundingClientRect()获取元素位置,这个方法没有参数
e.currentTarget.addEventListener("mousemove", this.mouseHanlder);//鼠标移动事件 触发执行函数 进入case "mousemove":
e.currentTarget.addEventListener("mouseleave", this.mouseHanlder);//鼠标离开事件 触发执行函数 进入case "mouseleave":
//显示this.mask. this.zoom.这俩个div
this.mask.style.display = "block";
this.zoom.style.display = "block";
break;
//鼠标移动
case "mousemove":
//执行方法masKMove();
this.masKMove(e.clientX,e.clientY);//鼠标当前点击位置坐标
break;
//鼠标离开 移除事件监听 zoom mask 元素设置隐藏
case "mouseleave":
e.currentTarget.removeEventListener("mousemove", this.mouseHanlder);
e.currentTarget.removeEventListener("mouseleave", this.mouseHanlder);
this.mask.style.display = "none"
this.zoom.style.display = "none"
break;
}
}
// 鼠标移动 放大镜效果
masKMove(_x,_y){
//拖拽元素的中心位置
//this.rect.x:this.small这个div的元素位置的横坐标 maskWidth:mask容器宽度
var x=_x-this.rect.x-this.maskWidth/2;
var y = _y - this.rect.y - this.maskWidth / 2;
//拖拽事件只能在父容器的区域 拖拽
if(x<0) x=0;
if(y<0) y=0;
//small这个div的元素位置与子容器mask之间的距离横纵坐标
if (x > this.rect.width - this.maskWidth) x = this.rect.width - this.maskWidth;
if (y > this.rect.height - this.maskWidth) y = this.rect.height - this.maskWidth;
//this.mask子容器的位置变化
Object.assign(this.mask.style,{
left:x+"px",
top:y+"px"
});
//this.zoom 放大效果 的容器
Object.assign(this.zoom.style,{
//背景图的位置 与mask鼠标移动方式相反方向 计算出大小图之间的比例 实现放大镜效果
backgroundPositionX:-x*this.zoomWidth/this.maskWidth+"px",
backgroundPositionY: -y * this.zoomWidth / this.maskWidth + "px",
});
}
//抛发事件执行方法
setImage(src) {
Object.assign(this.small.style, {
backgroundImage: "url(" + src + ")",
backgroundSize: "100% 100%"
});
Object.assign(this.zoom.style, {
backgroundImage: "url(" + src + ")",
});
}
}
二 CarouselMenu.js 轮播图的封装
import Utils from "./Utils.js";//引用Utils.js工具类
export default class CarouselMenu{
num=5;//显示的个数 轮播图小图显示的个数
position=0;//页数
rre;//储存点击左右的e.target当前元素
//arr:数组,_width:参数储存为全局 如果未传参 初始值为450 _x//轮播图容器的x轴:_y://轮播图容器的y轴
constructor(arr,_width=450,_x=0,_y=0){
this.x=_x;//轮播图容器的x轴
this.y=_y;//轮播图容器的y轴
this.menuWidth=_width;//参数储存为全局 如果未传参 初始值为450
this.list=arr;//把数组保存到list属性中
this.elem=this.createElem(arr);//执行函数createElem(arr)的结果储存到this.elem属性中
}
createElem(arr) {
//防止重复创建 如果this.elem就结束方法运行
if(this.elem) return this.elem;
let div=Utils.ce("div");//Utils.js工具类 创建一个div
div.className="carousel";//给div添加一个类 carousel
//在div容器下面添加以下内容
//使用到了字符串模板,顺带arr.reduce这回数组方法
//img div>div>img*10 img
div.innerHTML = `
<img src='./img/prev.png' class='prev' id='prev'>
<div class='carouselDiv'>
<div class='imgCon' id='imgCon'>
${arr.reduce((value, item) => {
value += '<img src=./img/' + item + ' class=imgs>'
return value
}, '')}
</div>
</div>
<img src='./img/next.png' class='next' id='next'>
`;
//执行方法 添加样式
this.setStyle(arr);
Utils.getIdElem(div,this);//获取div包含子元素id属性 添加为这个类的全局属性
//获取的id 给元素添加事件
this.prev.addEventListener("click", e => this.bnClickHandler(e));//小轮播的左图标绑定点击事件
this.next.addEventListener("click", e => this.bnClickHandler(e));//小轮播的右图标绑定点击事件
this.imgCon.addEventListener("mouseover", e => this.mouseHandler(e));//小轮播图的小图添加鼠标经过事件
return div;
}
//执行 追加到元素的后面
appendTo(parent) {
parent.appendChild(this.elem);
}
//添加css样式的方法
setStyle(arr){
//轮播图父容器的父容器 top:this.y+2+"px",距离放大镜的top距离
Utils.insertCss(".carousel",{
width: this.menuWidth + "px",
height: "58px",
position: "absolute",
top:this.y+2+"px",
});
//小轮播图的左右图标
Utils.insertCss(".prev,.next", {
position: "absolute",
top: "0px",
bottom: "0px",
height: "32px",
margin: "auto"
})
//设置图标的左右位置
Utils.insertCss(".prev", { left: "5px" });
Utils.insertCss(".next", { right: "5px" });
//左右图标的宽度
var w=this.menuWidth-64;
// 轮播图的父元素的父元素
Utils.insertCss(".carouselDiv", {
width: w + "px",
height: "58px",
position: "absolute",
left: "32px",
overflow: "hidden",
});
//轮播图之间的间距 19.2
var gap = (w - 58 * this.num) / this.num;
//轮播图的的长度 772
var conW = arr.reduce(value => {
return value + 58 + gap;
}, 0);
//轮播图的父元素
Utils.insertCss(".imgCon", {
position: "absolute",
width: conW + "px",
height: "58px",
left: 0,
transition: "all 0.5s"
});
//轮播图的样式
Utils.insertCss(".imgs", {
width: "54px",
height: "54px",
border: `2px solid rgba(255,0,0,0)`,
marginRight: gap + "px"
})
}
//小轮播图左右点击事件执行
bnClickHandler(e){
//正则表达式查找prev e.target.src当前点击元素 的src
if(/prev/.test(e.target.src)){
this.position--;
if(this.position<0) this.position=0;
// if (this.position < 0) this.position = Math.ceil(this.list.length / this.num) - 1;
}else{
this.position++;
if (this.position > Math.ceil(this.list.length / this.num) - 1) this.position = Math.ceil(this.list.length / this.num) - 1;
// if (this.position > Math.ceil(this.list.length / this.num) - 1) this.position = 0;
}
//为计算后轮播图的宽度
var w=this.menuWidth-64;
//计算后点击左右按钮移动的 宽度
this.imgCon.style.left = -this.position * w + "px"
}
//小轮播图的小图添加鼠标经过事件
//e.target当前点击的元素
mouseHandler(e){
if (e.target.nodeName !== "IMG") return;
if (this.pre) {
this.pre.style.border = "2px solid rgba(255,0,0,0)";
}
this.pre = e.target;
this.pre.style.border = "2px solid rgba(255,0,0,1)";
//抛发事件 replace替换 _icon替换为空字符串
var evt=new Event("Change_Menu_Img");
evt.src=e.target.src.replace("_icon","");
document.dispatchEvent(evt);
}
}
三 ZoomMenu.js 为连接1,2的实现
import Zoom from "./Zoom.js";
import CarouselMenu from "./CarouselMenu.js";
import Utils from "./Utils.js";
export default class ZoomMenu{
constructor(arr){
this.elem=this.createElem(arr);//执行方法把返回的内容 (div) 储存为全局
}
//执行方法
createElem(arr){
if(this.elem) return this.elem;//单例吗模式 防止重复创建
//创建一个div 是放大镜和轮播图的 父容器
let div=Utils.ce("div",{
width:"1200px",
margin: "0 auto",
border: "1px solid slategrey",
position:"relative"
});
//Zoom 是放大镜的封装
//shilihua实例化
let zoom=new Zoom();
//把新建的div 作为参数传入
zoom.appendTo(div);
//CarouselMenu轮播图的封装
// //arr:数组,_width:参数储存为全局 如果未传参 初始值为450 _x//轮播图容器的x轴:_y://轮播图容器的y轴
let carousel=new CarouselMenu(arr,450,0,450);
carousel.appendTo(div);
return div;
}
//执行 this.elem)内容追加到body 【zoomMenu.appendTo(document.body);】
appendTo(parent){
parent.appendChild(this.elem);
console.log(this.elem);
}
}
0 - 0 - 知识点:
1. styleSheetsdocument.styleSheets
这个接口可以获取网页上引入的link样式表和style样式表document.styleSheets.length 获取页面上样式表的长度toLowerCase() 方法用于把字符串转换为小写。
2. cssRules返回的是一个规则集合,通过索引可以获取指定位置的规则。
**3. insertBefore(newItem,existingItem);**方法可在已有的子节点前插入一个新的子节点。insertBefore(插入的元素,插入的位置)
4. innerHTML 属性设置或返回表格行的开始和结束标签之间的 HTML。可以直接写HTML标签事件
5. 使用到的事件
- mousemove 鼠标移动
- mouseover 鼠标经过
- mouseout 鼠标滑出
- mouseenter 鼠标进入
- mouseleave 鼠标离开
6. getBoundingClientRect()获取元素位置,这个方法没有参数
7.currentTarget与targetcurrentTarget
始终是监听事件者,即 直接调用addEventlistener那个节点而target是事件的真正发出者, 即 触发事件的节点,在click事件中就是被点击的节点。
8.clientX、clientY鼠标当前点击位置坐标点击位置距离当前body可视区域的x,y坐标
9.reduce() 方法接收一个函数作为累加器,reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(上一次回调的返回值),当前元素值,当前索引,原数组。
arr.reduce(value=>{
return value+58+gap;
},0)
10.正则表达式test() 方法用于检测一个字符串是否匹配某个模式.
11事件抛发
EventTarget叫事件目标对象,Event实例的对象叫事件对象。侦听和派发的对象可以是DOM元素,也可以是EventTarget,或者继承EventTarget的类。
- // 如果侦听函数调用(addEventListener被使用),就会在内存中添加存储
- // 尽量减少事件的侦听,因此就会将事件委托给父容器做侦听,以达到减少事件侦听的存储
- // e.currentTarget 是事件侦听事件对象(什么对象执行addEventListener函数就是谁)
- // e.target 事件的目标对象 事件实际触发的目标阶段最后对象,e.srcElement兼容IE
- // 事件函数中this默认等同于e.currentTarget
- 用法
在CarouselMenu.js抛发事件
//抛发事件 replace替换 _icon替换为空字符串
var evt=new Event("Change_Menu_Img");
evt.src=e.target.src.replace("_icon","");
document.dispatchEvent(evt);
- 接收事件
在Zoom.js接收事件
//接收 //小轮播图的小图添加鼠标经过事件抛发的事件 CarouselMenu.js 执行函数
document.addEventListener("Change_Menu_Img",e=>this.setImage(e.src));
12.replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
13.添加标签:
div.innerHTML = `
<img src ='./ img / prev.png'class ='prev'id ='prev'>
<div class ='carouselDiv'>
<div class ='imgCon'id ='imgCon'>
$ {arr.reduce((value,item)=> {
value + ='<img src =。/ img /'+ item +'class = imgs> </ img>'
},'')}
< / div>
</ div>
<img src ='./ img / next.png'class ='next'id ='next'> ` ;
- 效果如下:
- 14.箭头指向函数 更改this指向为父方法。
- 15.innerHTML 可以添加字符串模板,模板內可以增加数组的方法进行结果的运算