用JS类封装粒子特效(五)
本帖最后由 马黑黑 于 2023-7-10 22:02 编辑本讲,主要讲在类里使用字面量对象来设计和设置类的属性。
面向对象编程是几乎所有编程语言的编程理念。对象是一个集合,集合里面的数据,以键值对的方式存储各类信息,比方说,我们要存储 HTML 元素的 left 和 top 值,通常的做法是分开使用 left 和 top 来记录,记录的数据略显繁琐,而使用对象,left 和 top 可以整合在一个定义好的集合里,假设该集合名称为 pos(位置position的缩写) :
let pos = {x: 10, y: 10};
pos 变量以 x 作为健名记录 10 即 键值,代表 left,y 则代表 top。注意:① 集合数据写在花括号里;② 健名和键值用小角冒号分开;③ 两个键值对之间用小角逗号隔开。
字面量对象用在类的构造函数里:
class Lizi {
constructor(pa) {
this.pa = pa;
this.pos = {x: 10, y: 10};
}
}
this.pos = {x: 10, y: 10} 等同于前面的讲义中的:
this.left = 10;
this.top = 10;
换成字面量对象之后,后续的使用中,this.left 我们要写成 this.pos.x,this.top 写成 this.pos.y,希望这个不难理解。
使用对象的好处在于,当归属于某一类的集合数据有很多构成元素时,健名: 键值 的记录方式会更为直观,把它们当做一个集合来存储,数据逻辑更清晰,读写更容易。本讲,为了不复杂化,我们将尺寸、位置、步幅作为三个集合来构建类的构造函数(constructor)里的相关属性。试看:
//Lizi 类
class Lizi {
//构造函数 : 属性设计/设置(pa - 粒子宿主元素)
constructor(pa) {
this.pa = pa;
this.size = {x: 20, y: 20}; //宽高尺寸
this.pos = {x: 10, y: 10}; //位置
this.step = {x: 1, y: 1}; //运动步幅
this.ele = document.createElement('li-zi');
}
//类的方法代码暂略
}
上面,size 对象有两个键值对,分别是 x 和 y,它们记录元素的宽高(这意味着粒子的宽高可以不一样了);pos 对象记录 left 和 top 值;step 对象记录的是水平和垂直方向的行进步幅。
下面创建类的 creating 方法,即创建粒子元素的自定义函数:
//创建粒子函数
creating() {
this.ele.style.cssText = `
width: ${this.size.x}px;
height: ${this.size.y}px;
left: ${this.pos.x}px;
top: ${this.pos.y}px;
`;
this.pa.appendChild(this.ele);
}
该方法首先设定粒子的 CSS 属性:宽、高、左边和上边等值,分别使用 this.属性名.x/y 获取对应的对象值;最后粒子宿主 this.pa 追加粒子元素作为自己的子元素。
以下代码是本讲完整示例源码,纸飞机自左向右飞行,同时由于重力的作用,它们会慢慢往下坠落:
<style>
#mydiv {
margin: 20px auto;
width: 740px;
height: 500px;
background: linear-gradient(to top right,olive,black);
overflow: hidden;
cursor: pointer;
position: relative;
}
li-zi {
position: absolute;
clip-path: polygon(0% 0%, 100% 50%, 0% 100%, 15% 50%);
}
</style>
<div id="mydiv"></div>
<script>
//粒子运动开关
let canMove = true;
//Lizi 类
class Lizi {
//构造函数 : 属性设计/设置(pa - 粒子宿主元素)
constructor(pa) {
this.pa = pa;
this.size = {x: 20, y: 20};
this.pos = {x: 10, y: 10}
this.step = {x: 1, y: 1};
this.ele = document.createElement('li-zi');
}
//创建粒子
creating() {
this.ele.style.cssText = `
width: ${this.size.x}px;
height: ${this.size.y}px;
left: ${this.pos.x}px;
top: ${this.pos.y}px;
`;
this.pa.appendChild(this.ele);
this.chgColor();
this.moving();
}
//移动粒子
moving() {
if(canMove) {
this.pos.x += this.step.x;
this.pos.y += this.step.y;
if(this.pos.x >= this.pa.offsetWidth) {
this.pos.x = -this.size.x;
this.chgColor();
}
if(this.pos.y >= this.pa.offsetHeight) {
this.pos.y = -this.size.y;
this.chgColor();
}
this.ele.style.left = this.pos.x + 'px';
this.ele.style.top = this.pos.y + 'px';
}
requestAnimationFrame(this.moving.bind(this));
}
//变换颜色
chgColor() {
this.ele.style.background = '#' + Math.random().toString(16).substr(-6);
}
}
//实例化类
Array.from({length: 20}).forEach((element) => {
element = new Lizi(mydiv);
element.size = {
x: 40 + Math.random() * 40,
y: 20 + Math.random() * 30
}
element.pos = {
x: Math.floor(Math.random() * (mydiv.offsetWidth - element.size.x)),
y: Math.floor(Math.random() * (mydiv.offsetHeight - element.size.y))
}
element.step = {
x: 0.5 + Math.random(),
y: 0.2 + Math.random() * 0.2
};
element.creating();
});
mydiv.onclick = () => canMove = !canMove;
</script>
效果请看下楼。
<style>
#mydiv {
margin: 20px auto;
width: 740px;
height: 500px;
background: linear-gradient(to top right,olive,black);
overflow: hidden;
cursor: pointer;
position: relative;
}
li-zi {
position: absolute;
clip-path: polygon(0% 0%, 100% 50%, 0% 100%, 15% 50%);
}
</style>
<div id="mydiv"></div>
<script>
//粒子运动开关
let canMove = true;
//Lizi 类
class Lizi {
//构造函数 : 属性设计/设置(pa - 粒子宿主元素)
constructor(pa) {
this.pa = pa;
this.size = {x: 20, y: 20};
this.pos = {x: 10, y: 10}
this.step = {x: 1, y: 1};
this.ele = document.createElement('li-zi');
}
//创建粒子
creating() {
this.ele.style.cssText = `
width: ${this.size.x}px;
height: ${this.size.y}px;
left: ${this.pos.x}px;
top: ${this.pos.y}px;
`;
this.pa.appendChild(this.ele);
this.chgColor();
this.moving();
}
//移动粒子
moving() {
if(canMove) {
this.pos.x += this.step.x;
this.pos.y += this.step.y;
if(this.pos.x >= this.pa.offsetWidth) {
this.pos.x = -this.size.x;
this.chgColor();
}
if(this.pos.y >= this.pa.offsetHeight) {
this.pos.y = -this.size.y;
this.chgColor();
}
this.ele.style.left = this.pos.x + 'px';
this.ele.style.top = this.pos.y + 'px';
}
requestAnimationFrame(this.moving.bind(this));
}
//变换颜色
chgColor() {
this.ele.style.background = '#' + Math.random().toString(16).substr(-6);
}
}
//实例化类
Array.from({length: 20}).forEach((element) => {
element = new Lizi(mydiv);
element.size = {
x: 40 + Math.random() * 40,
y: 20 + Math.random() * 30
}
element.pos = {
x: Math.floor(Math.random() * (mydiv.offsetWidth - element.size.x)),
y: Math.floor(Math.random() * (mydiv.offsetHeight - element.size.y))
}
element.step = {
x: 0.5 + Math.random(),
y: 0.2 + Math.random() * 0.2
};
element.creating();
});
mydiv.onclick = () => canMove = !canMove;
</script> 本帖最后由 马黑黑 于 2023-7-10 21:17 编辑
二楼的代码再发一次:
<style>
#mydiv {
margin: 20px auto;
width: 740px;
height: 500px;
background: linear-gradient(to top right,olive,black);
overflow: hidden;
cursor: pointer;
position: relative;
}
li-zi {
position: absolute;
clip-path: polygon(0% 0%, 100% 50%, 0% 100%, 15% 50%);
}
</style>
<div id="mydiv"></div>
<script>
//粒子运动开关
let canMove = true;
//Lizi 类
class Lizi {
//构造函数 : 属性设计/设置(pa - 粒子宿主元素)
constructor(pa) {
this.pa = pa;
this.size = {x: 20, y: 20};
this.pos = {x: 10, y: 10}
this.step = {x: 1, y: 1};
this.ele = document.createElement('li-zi');
};
//创建粒子
creating() {
this.ele.style.cssText = `
width: ${this.size.x}px;
height: ${this.size.y}px;
left: ${this.pos.x}px;
top: ${this.pos.y}px;
`;
this.pa.appendChild(this.ele);
this.chgColor();
this.moving();
};
//移动粒子
moving() {
if(canMove) {
this.pos.x += this.step.x;
this.pos.y += this.step.y;
if(this.pos.x >= this.pa.offsetWidth) {
this.pos.x = -this.size.x;
this.chgColor();
}
if(this.pos.y >= this.pa.offsetHeight) {
this.pos.y = -this.size.y;
this.chgColor();
}
this.ele.style.left = this.pos.x + 'px';
this.ele.style.top = this.pos.y + 'px';
}
requestAnimationFrame(this.moving.bind(this));
};
//变换颜色
chgColor() {
this.ele.style.background = '#' + Math.random().toString(16).substr(-6);
};
}
//实例化类
Array.from({length: 20}).forEach((element) => {
element = new Lizi(mydiv);
element.size = {
x: 40 + Math.random() * 40,
y: 20 + Math.random() * 30
};
element.pos = {
x: Math.floor(Math.random() * (mydiv.offsetWidth - element.size.x)),
y: Math.floor(Math.random() * (mydiv.offsetHeight - element.size.y))
};
element.step = {
x: 0.5 + Math.random(),
y: 0.2 + Math.random() * 0.2
};
element.creating();
});
mydiv.onclick = () => canMove = !canMove;
</script>
有意思,因为尺寸的变化,这些飞机有点胖有的瘦{:4_173:} 属性名必须是这些个么,还是可以自己随便命名? 本帖最后由 小文 于 2023-7-10 22:25 编辑
很美很美,赶明我借来弄几张歼20上去。哈哈,问好!{:4_191:} 小文 发表于 2023-7-10 22:23
很美很美,赶明我借来弄几张歼20上去。哈哈,问好!
{:4_172:} 红影 发表于 2023-7-10 22:19
有意思,因为尺寸的变化,这些飞机有点胖有的瘦
全是手工折叠,非工厂模式生产{:4_170:} 醉美水芙蓉 发表于 2023-7-10 22:20
欣赏学习老师教程!
晚上好 红影 发表于 2023-7-10 22:20
属性名必须是这些个么,还是可以自己随便命名?
自定义,语义化的就好,各人按自己的习惯命名 马黑黑 发表于 2023-7-10 22:41
全是手工折叠,非工厂模式生产
就是啊各式各样的,挺好看的{:4_187:} 马黑黑 发表于 2023-7-10 22:42
自定义,语义化的就好,各人按自己的习惯命名
太好了,就不用管这些名字了,想用什么就用什么{:4_173:} 红影 发表于 2023-7-10 23:16
太好了,就不用管这些名字了,想用什么就用什么
除了JS、CSS、HTML规定的函数、选择器、标签以及围绕它们的东东等只能用它的,其余凡自定义的,就是随自己的心意命名,当然需要顾及自己和别人能看懂,也有一定规范的。 红影 发表于 2023-7-10 23:15
就是啊各式各样的,挺好看的
还可以进一步加工 原来这个是下雨的原理课{:4_199:} 马黑黑 发表于 2023-7-10 23:38
除了JS、CSS、HTML规定的函数、选择器、标签以及围绕它们的东东等只能用它的,其余凡自定义的,就是随自 ...
太好了,我只是问问它们是不是固定的,不一定去换它们{:4_173:} 马黑黑 发表于 2023-7-10 23:38
还可以进一步加工
这个已经很好看了。 红影 发表于 2023-7-11 16:05
这个已经很好看了。
那就好 红影 发表于 2023-7-11 16:01
太好了,我只是问问它们是不是固定的,不一定去换它们
变量呀,自定义函数呀,都是自己命名的