[“吊打面试官“系列之] 一晚带你玩转图片懒加载及其底层原理

news/2023/12/4 20:09:15

一晚带你玩转图片懒加载及其底层原理

课程大纲

  • 从浏览器底层渲染机制分析懒加载的意义
  • 最初基于JS盒模型实现的懒加载方案
  • 基于getBoundingClientRect的进阶方案
  • 手撕Lodash源码中的debounce(函数防抖)
  • 手撕Lodash源码中的throttle(函数节流)
  • 终极方案:IntersectionObserver
  • 未来设想:img.loading=lazy

基于JS盒模型的花瓣网瀑布流懒加载

一. 实现思路

比如页面就是一个容器,里面有三列,分别从服务器拿到很多数据,比如从服务器拿到50条数据。50条数据按照一定规则插入到三列当中,首先我会把50条数据里的前3条拿到,第一次插的时候直接往进插就可以了,每个card的图片大小不一样,每个card的高度也就不一样,宽度固定,但高度不一样。现在已经把前3个数据插进去了,3个插完之后,我从50个数据里再拿下一组三个,我首先会看一下这三列当中现在的高度的排列顺序,然后按三列现有的高度按它的内容由高到低进行排序,并且也会把我拿到的3条数据进行由低到高进行排序。把当前拿到的3条数据中最小的最低的插入上一条数据最高的那一列里;把第二小的插入到第二列里,把当前拿到的最高的插入到最小的列。这样就保证三列布局每3个往进插每3个往进插,最后三列的高度相差也不是特别大,这就是瀑布流无规则排列。宽度固定,调整图片高度排列顺序。
在这里插入图片描述

(二)实现步骤:

1.实现瀑布流效果

代码思路详细解剖
(1)最早期的模块化思想[没有用vue和react]
(2)写业务逻辑,我们会return个对象来,我们会写一个方法,叫init(),init()是我们当前模块的唯一入口。
(3)一会我们再在页面里要干什么都会调init()方法,在init()里控制先干什么后干什么。
(4)未来我们想实现功能,只需要用命名空间或用模块的名字调它的init()方法。
(5)这就是我们早期的基于闭包、基于惰性函数惰性思想的JS高阶编程技巧实现业务开发的模块化思想。
接下来
(6)第一步从服务器获取数据才能干我们接下来的事了,用async await请求utils的ajax方法请求本地里有一个data.json
(7)有数据后接下来该做数据绑定了,写个方法叫bindHTML(),把data传进去实现数据绑定
(8)数据绑定思路:一共有三列,接下来就把从服务器拿到的50条数据每3个为一组分别插入到3列当中,这么一步步处理就好了
但是在处理之前,从服务器拿到的数据data有一个特点,每一个数据里都包含图片的高和宽,宽和高是按照图片本身来的
实现瀑布流就要有宽高,没有宽高就要服务器处理,一般服务器返回的图片都会有宽和高。服务器返回的数据里图片的宽度是300,
但是我们要把数据插入这个列里,每一列是240,每一列左右还有5px padding,真实的是230.把300的图片放到230的区域里呈现
宽度就要缩小,从300缩到230,那高度也要同比例缩小一些才不会导致图片的变形。
(9)根据服务器返回的图片宽高,动态计算出图片放到230容器中,高度应该怎么缩放。因为我们后期要做图片的延迟加载,在没有图片之前,我们也需要知道未来图片要渲染的高度,这样才能用一个容器先占位。
(10)元素集合是类数组集合不是数组,未来想进行排序操作得要转换成数组。用Array.from把类数组集合转换成数组。
(11)data是50条数据50条数据要每3个去拿。
(12)js盒子模型的13个属性,clientHeight、clientWidth、clientLeft、clientTop、offsetHeight、offsetWidth、offsetLeft、offsetTop、offsetParent、scrollHeight、scrollWidth、scrollLeft、scrollTop

index.html
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="ie=edge"><meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"><title>珠峰在线Web高级课</title><!-- IMPORT CSS --><link rel="stylesheet" href="css/reset.min.css"><link rel="stylesheet" href="css/index.css">
</head><body><div class="container clearfix"><div class="column"><!-- <div class="card"><a href="#"><div class="lazyImageBox"><img src="" alt="" data-image="images/1.jpg"></div><p>泰勒·斯威夫特(Taylor Swift),19891213日出生于美国宾州,美国歌手、演员。2006年出道,同年发行专辑《泰勒·斯威夫特》,该专辑获得美国唱片业协会的白金唱片认证</p></a></div> --></div><div class="column"></div><div class="column"></div></div><!-- IMPORT JS --><script src="js/utils.js"></script><script src="js/index.js"></script>
</body></html>
/*index.js*/
let  imageModule=(function(){//元素集合是类数组集合不是数组,未来想进行排序操作得要转换成数组。用Array.from把类数组集合转换成数组let columns= Array.from(document.querySelectorAll('.column'));//数据绑定function bindHTML(data){//根据服务器返回的图片宽高,动态计算出图片放到230容器中,高度应该怎么缩放//因为我们后期要做图片的延迟加载,在没有图片之前,我们也需要知道未来图片要渲染的高度//这样才能用一个容器先占位data=data.map(item=>{let {width,height} = item;item.height=height/(width/230);item.width=230;return  item;});//每3个为一组获取数据for(let i = 0;i<data.length;i+=3){let group =data.slice(i,i+3);//实现每一列的降序columns.sort((a,b)=>{return b.offsetHeight - a.offsetHeight;});//把一组数据的进行升序group.sort((a,b)=>{return a.height - b.height;});//分别把最小数据插入到最大的列中group.forEach((item,index)=>{let{width,height,title,pic} = item;let card= document.createElement('div');card.className = "card";card.innerHTML =`<a href="#"><div class="lazyImageBox" style="height:${height}px"><img src="" alt="" data-image="${pic}"></div><p>${title}</p></a>`;columns[index].appendChild(card);});}}return {async init(){let data = await utils.ajax('./data.json');// console.log(data);获取到50条数据了bindHTML(data);}}})();
imageModule.init();

瀑布流效果
在这里插入图片描述

2.图片显示

let imageModule = (function () {//元素集合是类数组集合不是数组,未来想进行排序操作得要转换成数组。用Array.from把类数组集合转换成数组let columns = Array.from(document.querySelectorAll('.column'));//数据绑定function bindHTML(data) {//根据服务器返回的图片宽高,动态计算出图片放到230容器中,高度应该怎么缩放//因为我们后期要做图片的延迟加载,在没有图片之前,我们也需要知道未来图片要渲染的高度//这样才能用一个容器先占位data = data.map(item => {let {width,height} = item;item.height = height / (width / 230);item.width = 230;return item;});//每3个为一组获取数据for (let i = 0; i < data.length; i += 3) {let group = data.slice(i, i + 3);//实现每一列的降序columns.sort((a, b) => {return b.offsetHeight - a.offsetHeight;});//把一组数据的进行升序group.sort((a, b) => {return a.height - b.height;});//分别把最小数据插入到最大的列中group.forEach((item, index) => {let {width,height,title,pic} = item;let card = document.createElement('div');card.className = "card";card.innerHTML = `<a href="#"><div class="lazyImageBox" style="height:${height}px"><img src="" alt="" data-image="${pic}"></div><p>${title}</p></a>`;columns[index].appendChild(card);});}}//实现图片的延迟加载let lazyImageBoxs;function lazyFunc() {!lazyImageBoxs ? lazyImageBoxs = Array.from(document.querySelectorAll('.lazyImageBox')) : null;lazyImageBoxs.forEach(lazyImageBox => {//已经处理过则不再处理let isLoad = lazyImageBox.getAttribute('isLoad');if (isLoad) return;lazyImg(lazyImageBox);});}function lazyImg(lazyImageBox) {let img = lazyImageBox.querySelector('img'),trueImg = img.getAttribute('data-image');img.src = trueImg;img.onload = function () {//   图片加载成功utils.css(img, 'opacity', 1);};img.removeAttribute('data-image');//记录当前图片都处理过了lazyImageBox.setAttribute('isLoad', 'true');}return {async init() {let data = await utils.ajax('./data.json');// console.log(data);获取到50条数据了bindHTML(data);setTimeout(lazyFunc, 500);//window.onload也可以}}})();
imageModule.init();

图片显示
在这里插入图片描述

3.图片的延迟加载的详细原因、思路及实现

浏览器渲染页面

  • 1.构建DOM树
  • 2.构建CSSOM树
  • 3.生成RENDER TREE
  • 4.布局
  • 5.分层
  • 6.珊格化
  • 7.绘制
  • 构建DOM树中如果遇到img
  • 老版本:阻碍DOM渲染
  • 新版本:不会阻碍 每一个图片请求都会占用一个HTTP(浏览器同时发送的HTTP 6个)
  • 拿回来资源后会和RENDER TREE一起渲染
  • 开始加载图片,一定会让页面第一次渲染速度变慢(白屏)
  • 图片延迟加载:第一次不请求也不渲染图片,等页面加载完,其他资源都渲染好了,再去请求加载图片.
    懒加载的思路
    在这里插入图片描述
css
.card a .lazyImageBox {/* height: xxx;  如果是需要进行图片延迟加载,在图片不显示的时候,我们要让盒子的高度等于图片的高度,这样才能把盒子撑开(服务器返回给我们的数据中,一定要包含图片的高度和宽度) *//* background: url("../images/default.gif") no-repeat center center #F4F4F4; */overflow: hidden;
}
html<div class="lazyImageBox" style="height:${height}px"><img src="" alt="" data-image="${pic}"></div>

分析条件
临界点:如图当盒子刚刚完全显示在浏览器当前窗口中时,盒子顶部距离body的偏移量加上盒子本身的高度恰等于滚动条卷去的高度+浏览器的高度。
在这里插入图片描述
那么如果盒子底部距离页面顶部的长度小于滚动条卷去的高度+浏览器的高度,那么说明图片完全显示在页面视口中,就需要做延迟加载。

//实现图片的延迟加载let lazyImageBoxs;+ let winH = document.documentElement.clientHeight;function lazyFunc() {!lazyImageBoxs ? lazyImageBoxs = Array.from(document.querySelectorAll('.lazyImageBox')) : null;lazyImageBoxs.forEach(lazyImageBox => {//已经处理过则不再处理let isLoad = lazyImageBox.getAttribute('isLoad');if (isLoad) return;+ //加载条件:盒子底边距离BODY距离(盒子顶部距离body的偏移量加上盒子本身的高度)<浏览器距离BODY的高度(滚动条卷去的高度+浏览器的高度)+   let B=utils.offset(lazyImageBox).top+lazyImageBox.offsetHeight,+     A=winH+document.documentElement.scrollTop;+ if(B<=A){+    lazyImg(lazyImageBox);}});}

在这里插入图片描述
那么如何实现随着滚动页面而实现的延迟加载?

 return {async init() {let data = await utils.ajax('./data.json');// console.log(data);获取到50条数据了bindHTML(data);setTimeout(lazyFunc, 500);//window.onload也可以+  window.onscroll = lazyFunc;}}})();

在这里插入图片描述

基于getBoundingClientRect的进阶方案

(一)在浏览器中打开1.html。在控制台输入此方法,DOMRect包含了当前的盒子及盒子的样式,最下面的x和y一般不用,因为它兼容性特别差,width和height在ie678下是不兼容的。bottom、left、right、top都是兼容浏览器的。真实项目中已经完全用这种方案代替JS盒模型了,因为盒子模型太麻烦了,要计算很多值
在这里插入图片描述
在这里插入图片描述

let imageModule = (function () {//元素集合是类数组集合不是数组,未来想进行排序操作得要转换成数组。用Array.from把类数组集合转换成数组let columns = Array.from(document.querySelectorAll('.column'));//数据绑定function bindHTML(data) {//根据服务器返回的图片宽高,动态计算出图片放到230容器中,高度应该怎么缩放//因为我们后期要做图片的延迟加载,在没有图片之前,我们也需要知道未来图片要渲染的高度//这样才能用一个容器先占位data = data.map(item => {let {width,height} = item;item.height = height / (width / 230);item.width = 230;return item;});//每3个为一组获取数据for (let i = 0; i < data.length; i += 3) {let group = data.slice(i, i + 3);//实现每一列的降序columns.sort((a, b) => {return b.offsetHeight - a.offsetHeight;});//把一组数据的进行升序group.sort((a, b) => {return a.height - b.height;});//分别把最小数据插入到最大的列中group.forEach((item, index) => {let {width,height,title,pic} = item;let card = document.createElement('div');card.className = "card";card.innerHTML = `<a href="#"><div class="lazyImageBox" style="height:${height}px"><img src="" alt="" data-image="${pic}"></div><p>${title}</p></a>`;columns[index].appendChild(card);});}}//实现图片的延迟加载let lazyImageBoxs;let winH = document.documentElement.clientHeight;function lazyFunc() {!lazyImageBoxs ? lazyImageBoxs = Array.from(document.querySelectorAll('.lazyImageBox')) : null;lazyImageBoxs.forEach(lazyImageBox => {//已经处理过则不再处理let isLoad = lazyImageBox.getAttribute('isLoad');if (isLoad) return;//加载条件:盒子底边距离BODY距离(盒子顶部距离body的偏移量加上盒子本身的高度)<浏览器距离BODY的高度(滚动条卷去的高度+浏览器的高度)_   // let B=utils.offset(lazyImageBox).top+lazyImageBox.offsetHeight,//     A=winH+document.documentElement.scrollTop;// if(B<=A){//     lazyImg(lazyImageBox);// }+  let {bottom}=lazyImageBox.getBoundingClientRect();+    if(bottom<=winH){+    lazyImg(lazyImageBox);}});}function lazyImg(lazyImageBox) {let img = lazyImageBox.querySelector('img'),trueImg = img.getAttribute('data-image');img.src = trueImg;img.onload = function () {//   图片加载成功utils.css(img, 'opacity', 1);};img.removeAttribute('data-image');//记录当前图片都处理过了lazyImageBox.setAttribute('isLoad', 'true');}return {async init() {let data = await utils.ajax('./data.json');// console.log(data);获取到50条数据了bindHTML(data);setTimeout(lazyFunc, 500);//window.onload也可以window.onscroll = lazyFunc;}}})();
imageModule.init();

在这里插入图片描述
这么做了之后,我们当前的延迟就达到我们的效果了吗?No,还没有达到呢?我们说了在index.js,我们刚开始进来要做延迟加载,滚动的时候也要执行lazyFunc做延迟加载。
在这里插入图片描述
做个小测验,在lazyFunc(),打印OK。我们发现在浏览器向下滚动时中有很多个OK打印,说明lazyFunc被频繁触发了好多次,虽然最终没有达到条件和定义延迟加载,但这些东西被触发很多次,说明性能就会有所差距。所以在这个基础上要进行优化。
在这里插入图片描述
在这里插入图片描述
onscroll触发频率太高了,滚动一下可能要被触发很多次,导致很多没必要的计算和处理,消耗性能=>我们需要降低onscrll的时候的触发频率(节流)。

 return {async init() {let data = await utils.ajax('./data.json');// console.log(data);获取到50条数据了bindHTML(data);setTimeout(lazyFunc, 500);//window.onload也可以//onscroll触发频率太高了,滚动一下可能要被触发很多次,导致很多没必要的计算和处理,消耗性能=>我们需要降低onscrll//的时候的触发频率(节流)+ window.onscroll = utils.throttle(lazyFunc,500);}}

在这里插入图片描述
整个频率降低了很多很多,达到了性能优化的过程。

终极方案:IntersectionObserverIntersectionObserver

上一步用的是getBoundingClientRect+节流进行了性能优化,看起来很好,这种方案现在不需要做什么防抖节流,即使节流也会触发很多没必要的操作,真实想做的操作就是只要它一出来就让它加载。不出来就不管它了,不是在onscroll随时校验,是真正达到这个条件再去做这个事情。那一定比我们的节流还要做的更好。我们节流也只是把之间的频率降低了而已,降低了也会有很多没必要的操作。IntersectionObserverIntersectionObserver能把上面讲的东西全部优化了,新出来的,这种方案的兼容性不是特别好,低版本浏览器是不兼容的。polyfill处理不了它,移动端不考虑低版本浏览器,一般都是这种方案。但是这个性能超好,不需要节流处理。
**IntersectionObserverIntersectionObserver**的简介。

1.html
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>珠峰在线Web高级课</title><link rel="stylesheet" href="css/reset.min.css"><style>.box {width: 300px;margin: 1300px auto;}.box img {width: 100%;}</style>
</head><body><div class="box" id="box"><img src="images/1.jpg" alt=""></div><script>let observer = new IntersectionObserver(changes => {// changes包含所有监听对象的信息// target当前监听的对象// isIntersecting 是否出现在视口中// boundingClientRect // ...console.log(changes);});observer.observe(box);</script>
</body></html>

在这里插入图片描述

由截图可知,这个方法刚开始会触发一次,当滚动到图片出现在视窗口中会再触发一次。完全离开的时候再触发一次。
离开时移除监听

    <script>let observer = new IntersectionObserver(changes => {// changes包含所有监听对象的信息// target当前监听的对象// isIntersecting 是否出现在视口中// boundingClientRect // ...console.log(changes);+ let item = changes[0];+ if (item.isIntersecting) {// 进入到视口// ...+    observer.unobserve(item.target);+ }});observer.observe(box);</script>

index2.js

let imageModule = (function () {let columns = Array.from(document.querySelectorAll('.column'));// 数据绑定function bindHTML(data) {// 根据服务器返回的图片的宽高,动态计算出图片放在230容器中,高度应该怎么缩放// 因为我们后期要做图片的延迟加载,在没有图片之前,我们也需要知道未来图片要渲染的高度,这样才能又一个容器先占位data = data.map(item => {let {width,height} = item;item.height = height / (width / 230);item.width = 230;return item;});// 每三个为一组获取数据for (let i = 0; i < data.length; i += 3) {let group = data.slice(i, i + 3);// 实现每一列的降序columns.sort((a, b) => {return b.offsetHeight - a.offsetHeight;});// 把一组的数据进行升序group.sort((a, b) => {return a.height - b.height;});// 分别把最小数据插入到最大的列中group.forEach((item, index) => {let {height,title,pic} = item;let card = document.createElement('div');card.className = "card";card.innerHTML = `<a href="#"><div class="lazyImageBox" style="height:${height}px"><img src="" alt="" data-image="${pic}"></div><p>${title}</p></a>`;columns[index].appendChild(card);});}}// 实现图片的延迟加载// IntersectionObserver 监听DOM对象,当DOM元素出现和离开视口的时候触发回调函数+   let lazyImageBoxs,+      observer = new IntersectionObserver(changes => {+          changes.forEach(item => {+              console.log(changes)//刚开始有50个+              let {+                  isIntersecting,+                  target+              } = item;+              if (isIntersecting) {//出现在视口中+                  lazyImg(target);+                 observer.unobserve(target);//处理过的移除监听+                }+         });+     });function lazyFunc() {!lazyImageBoxs ? lazyImageBoxs = Array.from(document.querySelectorAll('.lazyImageBox')) : null;lazyImageBoxs.forEach(lazyImageBox => {observer.observe(lazyImageBox);});}function lazyImg(lazyImageBox) {let img = lazyImageBox.querySelector('img'),trueImg = img.getAttribute('data-image');img.src = trueImg;img.onload = function () {// 图片加载成功utils.css(img, 'opacity', 1);};img.removeAttribute('data-image');}return {async init() {let data = await utils.ajax('./data.json');bindHTML(data);setTimeout(lazyFunc, 500);__   }}
})();
imageModule.init();

在这里插入图片描述

加载的效果几乎看不到下面没加载图片的空白区域,只有快速滚动才能看到效果。
这个方案还可以实现哪些功能?
加载到底部加载更多数据,在移动端如果不需要考虑太多低版本操作系统,做延迟加载时基本都用这种方案。思路如下:
在这里插入图片描述

未来设想:img.loading=lazy

未来的设想,啥也不用管,只要设置lazy,浏览器就会帮我们做延迟加载。 这种方案目前只兼容 Chrome 76,并且窗口高度 网速 滚动 窗口大小改变。
img.loading=lazy ,下一步要做的事情:我们自己在不兼容的情况下,写一个插件,兼容它(其实就是自己去实现一套处理方法).
index.html

	<script src="js/utils.js"></script><script src="js/index3.js"></script>

index3.js

let imageModule = (function () {let columns = Array.from(document.querySelectorAll('.column'));// 数据绑定function bindHTML(data) {// 根据服务器返回的图片的宽高,动态计算出图片放在230容器中,高度应该怎么缩放// 因为我们后期要做图片的延迟加载,在没有图片之前,我们也需要知道未来图片要渲染的高度,这样才能又一个容器先占位data = data.map(item => {let {width,height} = item;item.height = height / (width / 230);item.width = 230;return item;});// 每三个为一组获取数据for (let i = 0; i < data.length; i += 3) {let group = data.slice(i, i + 3);// 实现每一列的降序columns.sort((a, b) => {return b.offsetHeight - a.offsetHeight;});// 把一组的数据进行升序group.sort((a, b) => {return a.height - b.height;});// 分别把最小数据插入到最大的列中group.forEach((item, index) => {let {height,title,pic} = item;let card = document.createElement('div');card.className = "card";// Chrome 76// 窗口高度 网速 滚动 窗口大小改变 ...card.innerHTML = `<a href="#"><div class="lazyImageBox" style="height:${height}px"><img src="${pic}" alt="" loading="lazy"></div><p>${title}</p></a>`;columns[index].appendChild(card);});}}return {async init() {let data = await utils.ajax('./data.json');bindHTML(data);}}
})();
imageModule.init();/* // 下一步要做的事情:我们自己在不兼容的情况下,写一个插件,兼容它(其实就是自己去实现一套处理方法)
if ('loading' in (new Image)) {console.log('ok');
} */
// typeof IntersectionObserver==="undefined"
// ...

在这里插入图片描述


http://www.ppmy.cn/news/377906.html

相关文章

面向对象+爬虫+队列+多线程+生产者消费者模式一键爬取全网霉霉图片

霉粉们的福利来啦!!! 面向对象爬虫队列多线程生产者消费者模式一键爬取全网霉霉图片 先介绍一波霉霉: 泰勒斯威夫特&#xff08;Taylor Swift&#xff09;&#xff0c;1989年12月13日出生于美国宾夕法尼亚州&#xff0c;美国女歌手、词曲作者、音乐制作人、演员。2006年&…

Python 3.5_简单上手、爬取百度图片的高清原图

利用工作之余的时间&#xff0c;学习Python差不多也有小一个月的时间了&#xff0c;路漫漫其修远兮&#xff0c;我依然是只菜鸟。 感觉学习新技术确实是一个痛并快乐着的过程&#xff0c;在此分享些心得和收获&#xff0c;并贴一个爬取百度图片原图的代码。 代码主要参考了xi…

使用selenium下载百度图片

简单说明 通过输入想要查找的关键词&#xff0c;使用selenium自动化工具下载其图片 网址为:‘https://image.baidu.com/search/index?tnbaiduimage&word’关键词 使用工具及模块 Pycharm-----python3.7selenium:pip install selenium -i https://pypi.douban.com/simpl…

Cenos7 --- Redis下载和安装(Linux版本)

1.下载和安装 Download | Redis进入官网Download | Redis&#xff0c; 上边点击下载7.0.11,右键复制下载衔接 https://download.redis.io/releases/redis-7.0.2.tar.gz 1.weget获取 我这个安装包放在 /tools/installbags下 cd /tools/installbags wget https://download.red…

一些实用的电脑办公软件推荐

软件一&#xff1a;多摸鱼 多摸鱼是一款基于Windows平台的轻量级软件&#xff0c;它可以帮助用户在电脑屏幕上创建一个浮动窗口&#xff0c;让用户可以在不影响正常工作的前提下&#xff0c;随时随地地摸鱼、看视频、听音乐等&#xff0c;提高工作时的放松效果。这个软件的好处…

推荐几款我用的Windows必装的办公软件,办公必备,效率提升

推荐几款我用的Windows必装的办公软件&#xff01; 让电脑成为真正的利器&#xff08;上&#xff09; ①桌面日历&#xff1a;日历与桌面融合高效办公。免费&#xff0c;支持手机和PC同步&#xff0c;兼容windows11&#xff0c;界面美观&#xff0c;完美替代WallCal3。 同时支…

超好用的办公软件推荐,总有一个你喜欢

逆天的办公软件&#xff0c;说白了就是功能强大、实用又方便的软件啦……我们工作中如果可以使用到一些逆天的办公软件&#xff0c;不止工作轻松&#xff0c;效率也是杠杠的。 接下来&#xff0c;我就根据实战经验给大家推荐几款办公神器。 一、行政办公类 1、极办公 移动办…

5款办公必备的好软件,你值得拥有

随着网络信息技术的发展&#xff0c;越来越多的人在办公时需要用到电脑了。如果你想提高办公效率&#xff0c;那么就少不了工具的帮忙&#xff0c;今天给大家分享5款办公必备的好软件。 1.文件管理工具——TagSpaces TagSpaces 是一款开源的文件管理工具,它可以通过标签来组织…

自媒体之路:只有富有能量的心才能看透三种人,掌握道术法器,迎接成熟五大表现

前言 本文是近期的思考与总结,发布在了知识星球,把内容摘录过来,做个分享,也是为了做个备份。 人无完人,每个人都有自己的思考,每个人都在成长,在分享的只言片语之中,如果对你有用,是我莫大的荣幸。 我每天会拿出6个多小时的时间来读书学习,近期主要研究方向是国学…

名字中间加一空格

B2IF(LEN(A2)>3,A2,(MID(A2,1,1)&" "&MID(A2,2,1)))

EXCEL怎么批量在两字姓名中间加空格

今天跟大家分享一下EXCEL怎么批量在两字姓名中间加空格 1.如下图我们想要批量在两个字姓名之间添加空格 2.首先我们选中姓名数据单元格区域 3.点击diy工具箱&#xff08;Excel工具箱&#xff0c;百度即可了解详细下载安装信息&#xff0c;本文这里就不做详细解说。&#xff09;…

cka证书名字前面的点和空格

CKA-CN 有的证书名称前面会多出一个英文的 . 和一个空格 可通过发邮件的方式联系官方进行修改 联系邮箱&#xff1a;helpdesklinuxfoundation.cn 详情可参考下图&#xff0c;记得附上证书的截图 之后会收到回复&#xff0c;是因为注册账号的时候没有填写 first name 导致的 由…

Linux中创建带空格的文件夹名称

Linux中创建带空格的文件夹名称 在终端中想要使用mkdir命令创建一个叫Hello World这样的文件夹的时候&#xff0c;需要使用连字符-将两个字符连起来&#xff0c;否则就是创建两个文件夹。创建之后文件夹的名字就是Hello-World&#xff0c;中间会带一个-。如果不想带-&#xff0…

文件名字空格变为加号

下载文件文件名空格被替换成了加号 自己在写demo的时候&#xff0c;遇到了这样的问题&#xff0c;在上传文件时&#xff0c;文件名字中带有空格&#xff0c;存入数据库也是正常显示&#xff0c;但是下载下来的时候就变了&#xff0c;空格被替换成了号。在网上查了资料&#xf…

Linux 命令行访问名字中包含空格的文件或文件夹

Linux 命令行访问名字中包含空格的文件或文件夹 在 Windows 下命名文件或文件夹名有空格是可以的&#xff0c;甚至在 Windows 和 Ubuntu 虚拟机共享的文件中也可以这么做&#xff0c;但是在 Ubuntu 中空格要用下划线代替&#xff0c;养成好习惯。Linux 会把空格当成分割符处理…

Qt 程序名称加上空格

Qt程序名称中加空格 ​ 今天这个记录只是在编码过程中&#xff0c;想给程序名称加上空格&#xff1b;例如xxx jjj.exe。发现在Qt不同的版本中&#xff0c;方式也不一样。 文章目录 Qt程序名称中加空格给程序名字加上空格 关键字&#xff1a; 小程序、TARGET、关键字3、空格、名…

C++中cin输入空格

我们往往在cin中输入的都是连续的字符串或者整数&#xff0c;比如&#xff1a; 在上面的代码中我们输入用户名字并输出名字&#xff0c;可以发现我们输入的是连续的字符串然后按回车进行输出名字。但是如果我们的名字改为wang xiaoming呢&#xff1f;这时会发生什么呢&#xff…

python什么时候用空格_python编码规范——空格的使用

渣渣的Leetcode之旅(Python3)_8. 字符串转换整数 (atoi)(中等) 请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。 函数 myAtoi(string s) 的算法如下: 读入字符串并丢弃无用的前导空格 检查第一个字符(假设还未…

php 过滤所有空格_php从文本中去除空格、特殊字符的4种情况

在日常的开发中,处理一些提交的内容时,经常需要考虑其中的空白内容。因为如果提交的数据存在空白,则会给程序造成问题。例如,用户在填写邮箱的时候,在结尾或者开始的时候不 小心加上了空格,那么就会导致用户提交的电子邮箱不正确,那么为了避免这种情况的存在,我们就要将…

linux删除文件名中的空格,linux – 删除目录中文件名中的空格

我有一个目录,其中一些文件名被错误地命名为.pdf而不是something.pdf.是否有一个快速的单行程序,我可以用来删除文件名中的空格. 我试过找-name“* .pdf”-type f |重命名’s / // g’ 但这没用. 解决方法: 在zsh中,使用zmv功能可以轻松完成.将autoload -U zmv放在〜/ .zshrc中…
最新文章