原生javascript手写一个丝滑的轮播图

news2024/9/25 1:25:58

通过本文,你将学到:

  • html
  • css
  • js

没错,就是html,css,js,现在是框架盛行的时代,所以很少会有人在意原生三件套,通过本文实现一个丝滑的轮播图,带你重温html,css和js基础知识。

为什么选用轮播图做示例?有如下几点:

  • 业务当中最常用
  • 轮播图说简单也不简单,说复杂也不复杂,可以说是一切项目的基石
  • 轮播图更适合考察你对html,css,js的基础掌握

废话不多说,让我们先来看一下效果图,如下:

通过上图,我们可以知道,一个轮播图包含了三大部分,第一部分是轮播图的部分,第二部分则是轮播翻页部分,第三部分则是上一页和下一页。

所以一个轮播图的结构我们基本上就清晰了,让我们来详细看一下吧。

html文档结构

首先我们要有一个容器元素,如下:

<!--容器元素-->
<div class="carousel-box"></div> 

然后,我们第一部分轮播图也需要一个容器元素,随后就是轮播图的元素列表,结构如下:

 <div class="carousel-content"><div class="carousel-item active"><img src="https://www.eveningwater.com/img/segmentfault/1.png" alt="" class="carousel-item-img"></div><div class="carousel-item"><img src="https://www.eveningwater.com/img/segmentfault/2.png" alt="" class="carousel-item-img"></div><div class="carousel-item"><img src="https://www.eveningwater.com/img/segmentfault/3.png" alt="" class="carousel-item-img"></div><div class="carousel-item"><img src="https://www.eveningwater.com/img/segmentfault/4.png" alt="" class="carousel-item-img"></div><div class="carousel-item"><img src="https://www.eveningwater.com/img/segmentfault/5.png" alt="" class="carousel-item-img"></div><div class="carousel-item"><img src="https://www.eveningwater.com/img/segmentfault/6.png" alt="" class="carousel-item-img"></div><div class="carousel-item"><img src="https://www.eveningwater.com/img/segmentfault/7.png" alt="" class="carousel-item-img"></div>
</div> 

分析下来就三个,容器元素,每一个轮播图元素里面再套一个图片元素。

接下来是第二部分,同样的也是一个容器元素,套每一个轮播点元素,如下:

<div class="carousel-sign"><div class="carousel-sign-item active">0</div><div class="carousel-sign-item">1</div><div class="carousel-sign-item">2</div><div class="carousel-sign-item">3</div><div class="carousel-sign-item">4</div><div class="carousel-sign-item">5</div><div class="carousel-sign-item">6</div>
</div> 

无论是轮播图部分还是轮播分页部分,都加了一个active类名,作为默认显示和选中的轮播图和轮播分页按钮。

第三部分,则是上一页和下一页按钮,这里如果我们将最外层的轮播容器元素设置了定位,这里也就不需要一个容器元素了,我们直接用定位,下一节写样式会详细说明。我们还是来看结构,如下:

<div class="carousel-ctrl carousel-left-ctrl">&lt;</div>
<div class="carousel-ctrl carousel-right-ctrl">&gt;</div> 

这里采用了html字符实体用作上一页和下一页文本,关于什么是html字符实体,可以参考相关文章,这里不做详解。

通过以上的分析,我们一个轮播图的文档结构就完成了,接下来,让我们编写样式。

编写样式

首先我们根据效果图可以知道,容器元素,轮播图部分容器元素以及每一个轮播图元素都是百分之百宽高的,样式如下:

.carousel-box,.carousel-content,.carousel-item ,.carousel-item-img {width: 100%;height: 100%;
} 

其次,容器元素和轮播图元素,我们需要设置成相对定位,为什么轮播图也要设置成相对定位?因为我们这里是使用的绝对定位加left和right偏移从而实现的滑动轮播效果。

.carousel-box,.carousel-item {position: relative;
} 

然后,由于轮播图只显示当前的轮播图,而超出的部分也就是溢出部分我们需要截断隐藏,因此为容器元素设置截断隐藏。

.carousel-box {overflow: hidden;
} 

接着,每一个轮播图元素默认都是隐藏的,只有加了active类名,才显示。

.carousel-item {display: none;
}
.carousel-item.active {display: block;left: 0;
} 

再然后分别是向左还是向右,这里我们是通过添加类名的方式来实现滑动,所以我们在这里额外为轮播元素增加了left和right类名,如下:

.carousel-item.active.left {left: -100%;
}
.carousel-item.active.right {left: 100%;
} 

有意思的点还在这里,就是每一个轮播图元素还额外的增加了next和prev类名,为什么要增加这两个类名?试想我们当前轮播图显示的时候,前面的是不是应该被隐藏,而后面的下一个应该是紧紧排在当前轮播图之后,然后做准备,而这两个类名的目的就是在这里,让效果看起来更加丝滑一些。

.carousel-item.next,
.carousel-item.prev {display: block;position: absolute;top: 0;
}
.carousel-item.next {left: 100%;
}
.carousel-item.prev {left: -100%;
}
.carousel-item.next.left,
.carousel-item.prev.right {left: 0%;
} 

最后补充一个轮播图片元素的样式,如下:

.carousel-item-img {object-fit: cover;
} 

到了这里,其实轮播图的核心思路已经出现了,就是利用的绝对定位加left偏移来实现,而在javascript逻辑中,我们只需要操作类名就可以了。

这样做的好处很显然,我们将动画的逻辑包装在css中,因此轮播的动画逻辑也比较好修改,修改css代码总比修改js代码简单吧?

到了这里,轮播部分的样式我们就已经完成了,接下来看分页按钮组的样式。

根据图片示例,分页按钮组元素是在底部的,其实分页按钮组也可以说是很常规的按钮布局,所以样式都是一些很基础的,也没有必要做太多的详解。

.carousel-sign {position: absolute;bottom: 10px;left: 50%;transform: translateX(-50%);padding: 5px 3px;border-radius: 6px;user-select: none;background: linear-gradient(135deg,#73a0e4 10%,#1467e4 90%);
}

.carousel-sign-item {width: 22px;height: 20px;font-size: 14px;font-weight: 500;line-height: 20px;text-align: center;float: left;color:#f2f3f4;margin: auto 4px;cursor: pointer;border-radius: 4px;
}
.carousel-sign-item:hover {color:#fff;
}
.carousel-sign-item.active {color:#535455;background-color: #ebebeb;
} 

最后就是上一页下一页的样式,有意思的是上一页下一页默认是不应该显示的,鼠标悬浮到轮播图容器元素上,才会显示,所以这里也用到了定位。

.carousel-ctrl {position: absolute;top: 50%;transform: translateY(-50%);font-size: 30px;font-weight: 300;user-select: none;background: linear-gradient(135deg,#73a0e4 10%,#1467e4 90%);color: #fff;border-radius: 5px;cursor: pointer;transition: all .1s cubic-bezier(0.075, 0.82, 0.165, 1);text-align: center;padding: 1rem;
}
.carousel-ctrl.carousel-left-ctrl {left: -50px;
}
.carousel-ctrl.carousel-right-ctrl {right: -50px;
}
.carousel-box:hover .carousel-ctrl.carousel-left-ctrl {left: 10px;
}
.carousel-box:hover .carousel-ctrl.carousel-right-ctrl {right: 10px;
}
.carousel-ctrl:hover {background-color: rgba(0,0,0,.8);
} 

到了这里,样式的布局就完成了,接下来是javascript核心逻辑,让我们一起来看一下吧。

轮播图的核心逻辑

我们将轮播图封装在一个类当中,然后通过构造函数调用的方式来使用它,我们先来看使用方式,如下:

const options = {el: '.carousel-box',speed: 1000, // 轮播速度(ms)delay: 0, // 轮播延迟(ms)direction: 'left', // 图片滑动方向monitorKeyEvent: true, // 是否监听键盘事件monitorTouchEvent: true // 是否监听屏幕滑动事件
}
const carouselInstance = new Carousel(options);
carouselInstance.start(); 

通过使用方式,我们得到了什么?

  • 轮播图的配置对象* el: 容器元素* speed: 轮播速度* delay: 轮播执行延迟时间* direction: 滑动方向,主要有left和right两个值* monitorKeyEvent: 是否监听键盘事件,也就是说是否可以通过点击键盘上的左右来切换轮播图* monitorTouchEvent: 是否监听屏幕滑动事件,也就是说是否可以通过滑动屏幕来切换图片* Carousel是一个构造函数* carousel构造函数内部提供了一个start方法用来开始轮播,很显然这里是开始自动轮播根据以上的分析,让我们来一步步实现Carousel这个东西吧。

首先它是一个构造函数,支持传入配置对象,所以,我们定义一个类,并且这个类还有一个start方法也初始化,如下:

class Carousel {constructor(options){//核心代码}start(){//核心代码}
} 

在初始化的时候我们需要做什么?

首先我们要获取到轮播元素,还有上一页下一页按钮以及我们的分页按钮元素。如下:

class Carousel {constructor(options){// 容器元素this.container = $(options.el);// 轮播图元素this.carouselItems = this.container.querySelectorAll('.carousel-item');// 分页按钮元素组this.carouselSigns = $$(('.carousel-sign .carousel-sign-item'),this.container);// 上一页与下一页this.carouselCtrlL = $$(('.carousel-ctrl'),this.container)[0];this.carouselCtrlR = $$(('.carousel-ctrl'),this.container)[1];}start(){//核心代码}
} 

这里用到了 和 和 $方法,看起来和jQuery的获取DOM很像,用到了jQuery?那当然不是了,我们来看这2个方法的实现。

const $ = (v,el = document) => el.querySelector(v);
const $$ = (v,el = document) => el.querySelectorAll(v); 

也就是获取dom元素的简易封装啦。

  • document.querySelector API
  • document.querySelectorAll API

就是基于以上两个dom查询节点的方法封装的,让我们来看下一步,首先我们需要有一个确定当前轮播图的索引值,然后获取所有轮播图元素的长度,然后就是初始化配置对象。代码如下:

class Carousel {constructor(options){//省略了代码// 当前图片索引this.curIndex = 0;// 轮播盒内图片数量this.numItems = this.carouselItems.length;// 是否可以滑动this.status = true;// 轮播速度this.speed = options.speed || 600;// 等待延时this.delay = options.delay || 3000;// 轮播方向this.direction = options.direction || 'left';// 是否监听键盘事件this.monitorKeyEvent = options.monitorKeyEvent || false;// 是否监听屏幕滑动事件this.monitorTouchEvent = options.monitorTouchEvent || false;}//省略了代码
} 

初始化完成之后,接下来我们有两个逻辑还需要在初始化里面完成,第一个逻辑是添加动画过渡效果,也就是让动画看起来更丝滑一些,第二个就是添加事件逻辑。继续在构造函数中调用2个方法,代码如下:

class Carousel {constructor(options){//省略了代码// 添加了事件this.handleEvents();// 设置过渡效果this.setTransition();}//省略了代码
} 

我们先来看最简单的setTransition方法,其实这个方法很简单,就是通过在head标签内添加一个style标签,通过insertRule方法添加样式。代码如下:

setTransition() {const styleElement = document.createElement('style');document.head.appendChild(styleElement);const styleRule = `.carousel-item {transition: left ${this.speed}ms ease-in-out}`styleElement.sheet.insertRule(styleRule, 0);
} 

很显然这里是为每个轮播图元素添加过渡效果,接下来我们来看绑定事件方法内部,我们可以尝试思考一下,都有哪些事件呢?总结如下:

  • 上一页与下一页
  • 分页按钮组
  • 滑动事件
  • 键盘事件
  • 轮播盒子元素的鼠标悬浮与鼠标移出事件

根据以上分析,我们的handleEvents方法就很好实现了,如下:

handleEvents() {// 鼠标从轮播盒上移开时继续轮播this.container.addEventListener('mouseleave', this.start.bind(this));// 鼠标移动到轮播盒上暂停轮播this.container.addEventListener('mouseover', this.pause.bind(this));// 点击左侧控件向右滑动图片this.carouselCtrlL.addEventListener('click', this.clickCtrl.bind(this));// 点击右侧控件向左滑动图片this.carouselCtrlR.addEventListener('click', this.clickCtrl.bind(this));// 点击分页按钮组后滑动到对应的图片for (let i = 0; i < this.carouselSigns.length; i++) {this.carouselSigns[i].setAttribute('slide-to', i);this.carouselSigns[i].addEventListener('click', this.clickSign.bind(this));}// 监听键盘事件if (this.monitorKeyEvent) {document.addEventListener('keydown', this.keyDown.bind(this));}// 监听屏幕滑动事件if (this.monitorTouchEvent) {this.container.addEventListener('touchstart', this.touchScreen.bind(this));this.container.addEventListener('touchend', this.touchScreen.bind(this));}
} 

这里有意思的点在于bind方法更改this对象,使得this对象指向当前轮播实例元素,还有一点就是我们为每个分页按钮设置了一个slide-to的索引值,后续我们就可以根据这个索引值来切换轮播图。

接下来,让我们看看每一个事件对应的回调方法,首先是start方法,其实很容易就想到,start方法就是开始轮播,开始轮播也就是自动轮播,自动轮播我们需要用到定时器,因此我们的start函数就很好实现了,代码如下:

start() {const event = {srcElement: this.direction == 'left' ? this.carouselCtrlR : this.carouselCtrlL};const clickCtrl = this.clickCtrl.bind(this);// 每隔一段时间模拟点击控件this.interval = setInterval(clickCtrl, this.delay, event);
} 

这里有意思的点在于我们的自动轮播,是直接去模拟点击上一页下一页进行切换的,除此之外,这里根据方向将srcElement元素作为事件对象传递,也就是说后面我们会根据这个元素来做方向上的判断。

接下来我们来看暂停函数,很简单,就是清除定时器即可,如下:

// 暂停轮播
pause() {clearInterval(this.interval);
} 

接下来,让我们来看clickCtrl方法,思考一下,我们是如何修改当前轮播图的索引值的,正常情况下,比如说,我们是向左滑动,索引值实际上就是将当前索引值相加,然后再判断是否超出了轮播图元素组的长度,重置索引值。

但是这里有一个更为巧妙的实现方式,那就是取模,将当前索引值加1然后与轮播图元素组的长度取模,这样也就保证了我们的索引值始终不会超过轮播图元素组的长度。

如果是向右滑动,那么我们应该是加上轮播图元素组的长度 - 1再取模,也就是与向左方向相反,根据以上分析,我们的代码就好实现了,如下:

// 处理点击控件事件
clickCtrl(event) {if (!this.status) return;this.status = false;let fromIndex = this.curIndex, toIndex, direction;if (event.srcElement == this.carouselCtrlR) {toIndex = (this.curIndex + 1) % this.numItems;direction = 'left';} else {toIndex = (this.curIndex + this.numItems - 1) % this.numItems;direction = 'right';}this.slide(fromIndex, toIndex, direction);this.curIndex = toIndex;
} 

在这个方法里面还有一个slide方法,顾名思义就是轮播图的滑动方法,其实通篇下来,最核心的就是这个slide方法,这个方法主要做的逻辑就是根据索引值来切换class。代码如下:

slide(fromIndex, toIndex, direction) {let fromClass, toClass;if (direction == 'left') {this.carouselItems[toIndex].className = "carousel-item next";fromClass = 'carousel-item active left';toClass = 'carousel-item next left';} else {this.carouselItems[toIndex].className = "carousel-item prev";fromClass = 'carousel-item active right';toClass = 'carousel-item prev right';}this.carouselSigns[fromIndex].className = "carousel-sign-item";this.carouselSigns[toIndex].className = "carousel-sign-item active";setTimeout((() => {this.carouselItems[fromIndex].className = fromClass;this.carouselItems[toIndex].className = toClass;}).bind(this), 50);setTimeout((() => {this.carouselItems[fromIndex].className = 'carousel-item';this.carouselItems[toIndex].className = 'carousel-item active';this.status = true;// 设置为可以滑动}).bind(this), this.speed + 50);
} 

这里分成了两块替换类名的逻辑,第一块是轮播图元素的替换类名,需要判断方向,第二块则是分页按钮组的类名替换逻辑,当然分页按钮组的逻辑是不需要替换类名的。

其实分析到这里,这个轮播图的核心基本已经完成了,接下来就是完善了,让我们继续看分页按钮组的事件回调逻辑。

其实这里的逻辑也就是拿到索引值,前面为每个分页按钮组设置了一个slide-to属性,这里很显然就通过获取这个属性,然后生成slide方法所需要的参数,最后调用slide方法就行了。代码如下:

clickSign(event) {if (!this.status) return;this.status = false;const fromIndex = this.curIndex;const toIndex = parseInt(event.srcElement.getAttribute('slide-to'));const direction = fromIndex < toIndex ? 'left' : 'right';this.slide(fromIndex, toIndex, direction);this.curIndex = toIndex;
} 

最后还剩两个逻辑,一个是键盘事件,另一个是滑动事件逻辑,我们先来看键盘事件逻辑,键盘事件逻辑无非就是利用keyCode判断用户是否点击的是上一页和下一页,然后像自动开始轮播那样模拟调用上一页下一页按钮事件逻辑即可。代码如下:

keyDown(event) {if (event && event.keyCode == 37) {this.carouselCtrlL.click();} else if (event && event.keyCode == 39) {this.carouselCtrlR.click();}
} 

最后就是滑动事件了,滑动事件最难的点在于如何判断用户滑动的方向,其实我们可以通过计算滑动角度来判断,这里的计算逻辑是来自网上的一个公式,感兴趣的可以查阅相关资料了解。我们来看代码如下:

touchScreen(event) {if (event.type == 'touchstart') {this.startX = event.touches[0].pageX;this.startY = event.touches[0].pageY;} else {// touchendthis.endX = event.changedTouches[0].pageX;this.endY = event.changedTouches[0].pageY;// 计算滑动方向的角度const dx = this.endX - this.startXconst dy = this.startY - this.endY;const angle = Math.abs(Math.atan2(dy, dx) * 180 / Math.PI);// 滑动距离太短if (Math.abs(dx) < 10 || Math.abs(dy) < 10) return;if (angle >= 0 && angle <= 45) {// 向右侧滑动屏幕,模拟点击左控件this.carouselCtrlL.click();} else if (angle >= 135 && angle <= 180) {// 向左侧滑动屏幕,模拟点击右控件this.carouselCtrlR.click();}}
} 

到此为止,我们的一个轮播图就完成了,总结一下我们学到了什么?

  • CSS过渡效果
  • CSS基本布局
  • javascript事件* 鼠标悬浮与移出事件* 滑动事件* 键盘事件* 元素点击事件
  • javascript定时器

PS: 以后再也不用自己写轮播了,业务当中遇到,可以直接拿去用了,😄。

最后

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/382580.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络运维和网络安全运维有什么区别?就业前景如何?

随着互联网的高速发展&#xff0c;运维安全已经成了大多数企业安全保障的基石。在如今的信息时代&#xff0c;无论是网络运维还是网络安全运维都成了不可缺少的一部分。因此导致很多人都容易把两者弄混淆。首先我们来了解一下网络运维和网络安全运维有什么区别呢&#xff1f;网…

Linux vi/vim教程

所有的 Unix Like 系统都会内建 vi 文本编辑器&#xff0c;其他的文本编辑器则不一定会存在。 但是目前我们使用比较多的是 vim 编辑器。 vim 具有程序编辑的能力&#xff0c;可以主动的以字体颜色辨别语法的正确性&#xff0c;方便程序设计。 ** 什么是 vim&#xff1f;** Vim…

将vue-devtools打包成edge插件

文章目录一、从github拉vue-devtools源码二、用npm安装yarn三、使用yarn安装并编译源码四、将vue-devtools打包成edge插件五、离线安装edge插件一、从github拉vue-devtools源码 目前最新的版本是v6.5.0&#xff0c;地址&#xff1a;https://github.com/vuejs/devtools 二、用n…

第四阶段17-关于Redis中的list类型,缓存预热,关于Mybatis中的`#{}`和`${}`这2种格式的占位符

关于Redis中的list类型 Redis中的list是一种先进后出、后进先出的栈结构的数据。 在使用Redis时&#xff0c;应该将list想像为以上图例中翻转了90度的样子&#xff0c;例如&#xff1a; 在Redis中的list数据&#xff0c;不仅可以从左侧压入&#xff0c;也可以选择从右侧压入…

Linux04-冯诺依曼体系结构||操作系统||进程概念

1.认识冯诺依曼系统 1.1冯诺依曼体系结构 我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&#xff0c;如服务器&#xff0c;大部分都遵守冯诺依曼体系。 截至目前&#xff0c;我们所认识的计算机&#xff0c;都是有一个个的硬件组件组成 输入单元&#xff1a;包括…

Linux: 中断只被GIC转发到CPU0问题分析

文章目录1. 前言2. 分析背景3. 问题4. 分析4.1 ARM GIC 中断芯片简介4.1.1 中断类型和分布4.1.2 拓扑结构4.2 问题根因4.2.1 设置GIC SPI 中断CPU亲和性4.2.2 GIC初始化&#xff1a;缺省的CPU亲和性4.2.2.1 boot CPU亲和性初始化流程4.2.2.1 其它非 boot CPU亲和性初始化流程5.…

【蓝桥杯入门不入土】变幻莫测的链表

文章目录一&#xff1a;链表的类型单链表双链表循环链表二&#xff1a;链表的存储方式三&#xff1a;链表的定义删除节点添加节点四&#xff1a;实战练习1.设计链表2. 移除链表元素最后说一句一&#xff1a;链表的类型 单链表 什么是链表&#xff0c;链表是一种通过指针串联在…

最经典的黑客技术入门知识大全

第一节、什么是黑客 以我的理解&#xff0c;“黑客”大体上应该分为“正”、“邪”两类&#xff0c;正派黑客依靠自己掌握的知识帮助系统管理员找出系统中的漏洞并加以完善&#xff0c;而邪派黑客则是通过各种黑客技能对系统进行攻击、入侵或者做其他一些有害于网络的事情&…

LCR数字电桥软件下载安装教程

软件&#xff1a;LCR数字电桥软件NS-LCR 语言&#xff1a;简体中文 环境&#xff1a;NI-VISA 安装环境&#xff1a;Win10以上版本&#xff08;特殊需求请后台私信联系客服&#xff09; 硬件要求&#xff1a;CPU2GHz 内存4G(或更高&#xff09;硬盘500G(或更高&#xff09; …

ProcDump+Mimikatz绕过杀毒软件抓密码

抓密码的奇淫技巧背景1、原理2、实操演示背景 如果主机上装了杀毒软件&#xff0c;开了防火墙&#xff0c;例如&#xff1a;360、火绒之类的话。Mimikatz就会被检测为病毒&#xff0c;无法使用&#xff0c;而想要对Mimikatz进行二次开发或者免杀难度会比较大&#xff0c;那有办…

边缘计算开源项目解读——kubeedge mappers实现

0 背景 本文重点解读kubeedge项目中的mapper模块。该模块位于kubeedge的edgecore的南向边缘侧&#xff0c;主要对接入kubeedge的终端设备&#xff0c;进行协议的适配和转换&#xff0c;使其可以和边缘设备通信&#xff0c;转换后的协议是我们前面描述的mqtt协议&#xff0c;当然…

玩转ThreadLocal

前言 ThreadLocal想必都不陌生&#xff0c;当多线程访问同一个共享变量时&#xff0c;就容易出现并发问题&#xff0c;为了保证线程安全&#xff0c;我们需要对共享变量进行同步加锁&#xff0c;但这又带来了性能消耗以及使用者的负担&#xff0c;那么有没有可能当我们创建一个…

只知道删除单张表的数据?不知道删除多张表的数据?

一些废话 可能在某某一天&#xff0c;你在表删除表数据的时候&#xff0c;不想一张表一张表的去删除&#xff0c;想把两个表的数据同时删除&#xff1b;然后你就会去搜索&#xff0c;然后你就很有很有很有很有可能会看到 me 的这篇优质&#xff08;呸&#xff01;&#xff01;…

HOT100--(5)最长回文子串

点击查看题目详情 中心扩散法 思路&#xff1a; 遍历字符串&#xff0c;以每个字符为中心点向两边扩散&#xff0c;如果遇到不一样的就跳出循环。以此类推&#xff0c;最后截取最大回文串返回。 细节 字符个数不一定都是奇数。当个数是偶数的是时候&#xff0c;我们可以“忽…

学习红客技术必备,手把手教你成为“安防第一人”

互联网时代已悄悄来临&#xff0c;作为新时代的人们&#xff0c;我们日常生活、工作、学习方面都需要借助互联网来完成&#xff0c;这样&#xff0c;又产生一种新的问题&#xff0c;那就是网络安全的问题&#xff0c;有时我们拼命加班好不容易完成的东西&#xff0c;在一夜之间…

优化Linux系统性能的必杀技:调整进程优先级!学会使用nice命令,让你的系统飞一般的顺畅!

文章目录前言一. nice命令介绍1.1 nice的介绍1.2 cpu资源的调度1.3 nice是控制内核吗&#xff1f;二. 语法格式及常用选项三. 参考案例3.1 将ls命令的优先级调整为最高3.2 将 find 命令的优先级调整为最低3.3 如何查看nice值四. nice和renice的区别总结前言 大家好&#xff0c…

Zookeeper的安装

目录 Zookeeper的安装 1、环境准备 2、上传 3、解压文件到opt/zookeeper目下 4、安装完后进入zookeeper&#xff0c;找到conf目录 5、复制zoo_sample.cfg 6、编辑zoo.cfg 7、复制一份会话&#xff0c;进入zookeeper安装目录&#xff0c;创建一个文件夹zkdata&#xff0…

Linux·DMA 与零拷贝技术

DMA 与零拷贝技术注意事项&#xff1a;除了 Direct I/O&#xff0c;与磁盘相关的文件读写操作都有使用到 page cache 技术。1. 数据的四次拷贝与四次上下文切换很多应用程序在面临客户端请求时&#xff0c;可以等价为进行如下的系统调用&#xff1a;File.read(file, buf, len);…

NOC2021年测试卷3

1. 角色初始位置坐标是(0,0),执行下面程序后,角色会出现在什么位置上?( ) A. x坐标为10,y坐标为50B. x坐标为40,y坐标为50C. x坐标为50,y坐标为40D. x坐标为30,y坐标为502. 执行下面程序后,按一次→键,兔子会?() A. 向右移动10步B. 向左移动10步C. 向上移动…

入职外包三个月,我提桶跑路了

有一种打工人的羡慕&#xff0c;叫做“大厂”。 真是年少不知大厂香&#xff0c;错把青春插稻秧。 但是&#xff0c;在深圳有一群比大厂员工更庞大的群体&#xff0c;他们顶着大厂的“名”&#xff0c;做着大厂的工作&#xff0c;还可以享受大厂的伙食&#xff0c;却没有大厂…