Scale
前置知识
transform属性
通过平移,旋转,放大/缩小改变元素位置和大小
transition
CSS 中用于实现过渡效果的属性,它允许你在 CSS 属性值发生变化时平滑地改变属性值。过渡效果可以使元素在状态改变时呈现出平滑的动画效果,而不是突然地改变。
代码讲解
我们先来看对应的 dom 布局
<div class="text_class">
<h1>野生动物种类</h1>
<ul class="text_class_list">
<li><a href="class_Mammals.html"><img src="../images/哺乳类.jpg" alt=""><span>哺乳类</span></a></li>
<li><a href="class_fish.html"><img src="../images/鱼类.jpg" alt=""><span>鱼类</span></a></li>
<li><a href="class_Birds.html"><img src="../images/鸟类.jpg" alt=""><span>鸟类</span></a></li>
<li><a href="class_Reptiles.html"><img src="../images/爬行类.jpg" alt=""><span>爬行类</span></a></li>
</ul>
</div>
<div class="text_pictures">
<h1>动物世界</h1>
<ul class="text_pictures_list">
<li><a href="pictures.html"><img src="../images/g4.jpg" alt=""></a></li>
<li><a href="pictures.html"><img src="../images/g5.jpg" alt=""></a></li>
<li><a href="pictures.html"><img src="../images/g1.jpg" alt=""></a></li>
<li><a href="pictures.html"><img src="../images/g2.jpg" alt=""></a></li>
<li><a href="pictures.html"><img src="../images/g3.jpg" alt=""></a></li>
</ul>
</div>
就是两行,每行有不同的图片,hover上去时放大,离开时缩小,要实现这个功能,有两种思路,代码中实现的是思路一,js方式
方式一 JS 方式
js方式主要是监听js事件,执行不同的函数来达到目的
第一步,获取我们要放大缩小的元素,
// 获取图片列表
const picturesList = document.querySelector('.text_pictures_list');
第二步,注册鼠标事件,mouseover事件就是鼠标移入事件, mouseout就是鼠标移出事件
// 添加事件监听器,实现鼠标移过时放大图片的效果
picturesList.addEventListener('mouseover', function(event) {
// 他的这一种方式,是监听父元素,就是text_pictures_list这个元素,
// 触发这个事件可能是不同的元素触发的(只要是他的子级就触发),
// 所以要判断是不是 img 图片触发的,只要图片触发才放大
// 如果目标是图片,则放大
if (event.target.tagName === 'IMG') {
// 这就是前置知识中的transform属性,scale属性就是把该元素放大,放大到1.2倍
event.target.style.transform = 'scale(1.2)'; // 放大到原尺寸的 1.2 倍
// 'transform 0.5s ease'意思是 transform 属性发生变化时,做一个过渡效果,持续0.5s,变化曲线是ease类型
event.target.style.transition = 'transform 0.5s ease'; // 添加动画效果
}
});
// 添加事件监听器,实现鼠标移出时恢复原始大小的效果
picturesList.addEventListener('mouseout', function(event) {
// 同上面,要判断是谁触发的这个事件,然后把 他还原,scale(1) 就是默认大小
// 如果目标是图片,则恢复原始大小
if (event.target.tagName === 'IMG') {
event.target.style.transform = 'scale(1)';
event.target.style.transition = 'transform 0.5s ease'; // 添加动画效果
}
});
然后看他的另一种绑定方式,和上面大同小异,上面是绑定父元素,这是给每一个img元素都绑定上mouseover mouseout鼠标移入移出事件
// 获取野生动物种类列表
const animalListItems = document.querySelectorAll('.text_class_list li a');
console.log(animalListItems)
// 添加事件监听器,实现鼠标移过时放大图片的效果
// 对每一个img元素都绑定上⌚️
animalListItems.forEach(item => {
item.addEventListener('mouseover', function(event) {
// 原理同上
item.style.transform = 'scale(1.2)'; // 放大到原尺寸的 1.2 倍
item.style.transition = 'transform 0.5s ease'; // 添加动画效果
});
// 添加事件监听器,实现鼠标移出时恢复原始大小的效果
item.addEventListener('mouseout', function(event) {
item.style.transform = 'scale(1)';
item.style.transition = 'transform 0.5s ease'; // 添加动画效果
});
});
第二种方式 css
代码中没有,大概这么写
.text_class_list img {
transform: scale(1);
}
.text_class_list img:hover {
transform: scale(1.2);
transition: transform 0.5s ease;
}
轮播图
这里也用到了上面说的 transform 属性
我们可以先想一下大概思路,
- 把图片放成一排,每个图片宽高一样,然后只显示当前视口的那张图片,其他的图片在屏幕外,那么是不是需要一个
currentIndex变量记录一下当前的索引,是那张图片呢? - 那如何把当前图片滚动到可以看见的地方呢?假设每张图片宽度都是
100px,那第 i 个图片只需要向左移动100 * index px是不是就出现了呢? - 上一页、下一页的就是计算 index,移动位置就好了对嘛?自动播放就是每秒自动的 改变索引
currentIndex的值对嘛?
那我们接下来具体看看怎实现的?
- 获取轮播图元素,定义当前索引,显示第几张照片
let currentIndex = 0; // 当前幻灯片索引
// 获取所有幻灯片元素
const slides = document.querySelectorAll('.index_banner_list li');
let totalSlides = slides.length; // 幻灯片总数
let autoSlideInterval; // 存储自动轮播的 setInterval 函数
- 初始化我们的幻灯片
为什么有这一步?为什么要克隆第一张和最后一张
// 克隆第一张和最后一张幻灯片,并调整位置
const firstSlideClone = slides[0].cloneNode(true);
const lastSlideClone = slides[totalSlides - 1].cloneNode(true);
lastSlideClone.style.marginLeft = '-100%'; // 将最后一张幻灯片移至首位
document.querySelector('.index_banner_list').appendChild(firstSlideClone); // 在列表末尾添加第一张克隆
document.querySelector('.index_banner_list').insertBefore(lastSlideClone, slides[0]); // 将最后一张克隆插入到列表开头
- 实现下一页
// 向后切换幻灯片
function nextSlide() {
// 判断当前页是不是最后一页,如果不是,那么就直接 currentIndex + 1
// 否则,就应该切换到第一页,也就是 updateSlide(0);
// 克隆第一页的作用出现了,我们到了最后一页,实际后面有我们克隆的第一页
// 这时候 translateX(100%),就是显示了克隆的那页,表面上是第一页,实现了无缝切换
if (currentIndex === totalSlides - 1) {
document.querySelector('.index_banner_list').style.transform = `translateX(100%)`;
document.querySelector('.index_banner_list').style.transition = `none`;
document.querySelector('.index_banner_list').clientLeft;
updateSlide(0);
} else {
updateSlide(currentIndex + 1);
}
}
- updateSlide怎么实现的呢?
无非就是根据索引计算应该移动的距离
// 更新幻灯片显示
function updateSlide(index) {
currentIndex = index;
// 计算移动距离,以便切换到当前幻灯片
const distance = -index * 100;
// 应用 CSS transform 属性以移动幻灯片
document.querySelector('.index_banner_list').style.transform = `translateX(${distance}%)`;
document.querySelector('.index_banner_list').style.transition = `0.5s`;
// 这下面就是高亮小圆点,要先去掉所有的高亮,在对当前小圆点加上高亮效果
const active = document.querySelector('.indicator span.active');
active.classList.remove('active'); // 移除前一个激活的幻灯片指示器
indicators[currentIndex].classList.add('active'); // 添加当前幻灯片指示器的激活状态
}
- 实现上一页 大概原理和「下一页」一样,不同点在于这是判断是否是第一页
// 向前切换幻灯片
function prevSlide() {
// 判断是否是第一页,还要往前翻,那就是最后一页,这时候就克隆最后一页的效果了
if (currentIndex === 0) {
document.querySelector('.index_banner_list').style.transform = `translateX(-${totalSlides}00%)`;
document.querySelector('.index_banner_list').style.transition = `none`;
document.querySelector('.index_banner_list').clientLeft;
updateSlide(totalSlides - 1);
} else {
updateSlide(currentIndex - 1);
}
}
- 自动轮播
// 启动自动轮播
function startAutoSlide() {
// 开启定时器,每隔一段时间手动触发一下 nextSlide下一页函数就好了
autoSlideInterval = setInterval(nextSlide, 3 * 1000); // 每3秒切换一次
}
// 停止自动轮播
function stopAutoSlide() {
// 清除定时器
clearInterval(autoSlideInterval);
}
// 初始化时启动自动轮播
startAutoSlide();
- 小圆点 就是根据轮播图的长度,去生成小圆点,加入到 dom 元素中
// 创建幻灯片指示器
for (let i = 0; i < totalSlides; i++) {
//生成小圆点
let indicator = document.createElement('span');
// 加入到 dom 元素中
document.querySelector('.indicator').appendChild(indicator);
}
// 获取小圆点
let indicators = document.querySelectorAll('.indicator span')
// 将当前幻灯片指示器设置为激活状态
indicators[currentIndex].classList.add('active');
然后监听每个小圆点事件,调用updateSlide方法切换轮播图
// 为每个幻灯片指示器添加鼠标移入和移出事件
indicators.forEach((item, i) => {
// 鼠标移入事件
item.onmouseenter = function () {
stopAutoSlide(); // 鼠标移入时停止自动轮播
currentIndex = i; // 更新当前幻灯片索引为指示器的索引
updateSlide(currentIndex); // 更新幻灯片显示
}
// 鼠标移出事件
item.onmouseleave = startAutoSlide; // 鼠标移出时开始自动轮播
})
文字滚动
两种方式,
第一种 css
前置知识
- animaiton属性
- 固定定位,top属性
- requestAnimationFrame和cancelAnimationFrame
- animationPlayState
利用 css 的 animaiton属性,可以自定义一个动画,不同阶段有不同的表现,这就是不停的去改变 news-list-inner 元素的 top 值,最后动画结束时滚动到最上方,这用的是固定定位,开始 top = 0,在 6s内,滚动到 top= -440的位置,就实现了滚动。
animation: scroll 6s linear infinite normal;这句话意思是,使用了动画名为 scroll的动画,6s时间内,以linear的方式滚动,infinite是无限循环,也就是一直滚动
第二种方式 js
这种方式本质上也是采用的上面的原理,不断的改变 news-list-inner 元素的 top 值,来实现滚动。他使用requestAnimationFrame这个方法,每一帧都改变一次top值,requestAnimationFrame是浏览器提供的,一般每秒执行60次,跟定时器一样
第一步,第一滚动速度,开启自动滚动
// 获取需要操作的元素
const newsListContainer = document.querySelector('.news-list-container');
const newsListInner = document.querySelector('.news-list-inner');
const allItems = document.querySelectorAll('.news-list-inner div');
// 创建克隆节点
const clonedItems = cloneItems(Array.from(allItems));
// 将克隆节点添加到容器末尾
appendClonedItems(newsListInner, clonedItems);
// 初始化滚动速度和方向
let scrollSpeed = 1; // 初始滚动速度
let scrollDirection = 'up'; // 初始滚动方向
// 启动滚动
let animationFrameId = requestAnimationFrame(scrollNews(newsListInner, scrollDirection));
然后第二步,我们看一下 scrollNews 做了什么?
// 滚动元素
function scrollNews(element, direction) {
// element就是我们的滚动元素
// direction就是方向,
// 返回的函数就是每一帧都要执行的函数
return function() {
if (direction === 'up') {
// 向上滚动时,先获取当前滚动元素的的 top值,将 top + scrollSpeed速度的结果
//给到这个元素,那么 相当于将这个元素向上移动了,
// 比如开始是 0px,原地不同,第一次就是 -1px,那么元素top=-1px,元素会被向上移动1px
// 依次类推。。。
element.style.top = parseInt(element.style.top) - scrollSpeed + 'px';
if (parseInt(element.style.top) < -440) {
element.style.top = '0px';
}
} else if (direction === 'down') {
// 同理,区别在于 + 加上 - ,向上和向下移动
element.style.top = parseInt(element.style.top) + scrollSpeed + 'px';
if (parseInt(element.style.top) >= 0) {
element.style.top = '-440px';
}
}
// 每一帧都执行这个函数,建议百度一下requestAnimationFrame函数
animationFrameId = requestAnimationFrame(scrollNews(element, direction));
};
}
这样我们就实现了滚动了,那么如何实现鼠标移入停止呢?接着向下看
第三步
当然是监听mouseenter移入事件了,在移入时,执行一下函数
// 鼠标移入停止滚动
newsListContainer.addEventListener('mouseenter', handleMouseEnter(newsListInner, animationFrameId));
// 处理鼠标移入事件,暂停滚动
function handleMouseEnter(element, animationId) {
// 这个函数的功能就是 cancelAnimationFrame 清除动画帧,不要他每一帧都调用了
return function() {
cancelAnimationFrame(animationId);
// 通过css设置动画效果停止,建议看一下 animationPlayState 属性
stopScrollAnimation(element);
};
}
// 暂停滚动动画
function stopScrollAnimation(element) {
// paused是让动画继续停止
element.style.animationPlayState = 'paused';
}
第四步,鼠标移出继续滚动,原理同第三步,但是恰恰💡
// 鼠标移出继续滚动
newsListContainer.addEventListener('mouseleave', handleMouseLeave(newsListInner));
// 处理鼠标移出事件,恢复滚动
function handleMouseLeave(element) {
return function() {
resumeScrollAnimation(element);
};
}
// 恢复滚动动画
function resumeScrollAnimation(element) {
// runing是让动画继续执行
element.style.animationPlayState = 'running';
}
第五步鼠标移动时更新滚动速度原理差不多:监听事件,计算速度
newsListContainer.addEventListener('mousemove', adjustScrollSpeed(newsListContainer));
// 根据鼠标在容器内的位置调整滚动速度
function adjustScrollSpeed(container) {
return function(event) {
// 获取容器高度
const containerHeight = container.clientHeight;
// 根据鼠标位置和滚动容器在浏览器中的位置,计算一下速度,赋值给 scrollSpeed 就好了
const mouseY = event.clientY - container.getBoundingClientRect().top;
scrollSpeed = (mouseY / containerHeight) * 10; // 根据鼠标在容器内的位置调整滚动速度
};
}
以上就是它的功能了,但是我看好像没有用到