整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

js如何控制一次只加载一张图片,加载完成后再加载下一

js如何控制一次只加载一张图片,加载完成后再加载下一张

天看到一个面试题,是关于img图片加载方面的,有必要记录一下。其实关于这个问题,只要知道图片什么时候加载完成就能解决了。

通过onload事件判断Img标签加载完成

实现逻辑:新建一个Image对象实例,为实例对象设置src属性等,在onload事件中添加此实例对象到父元素中,然后将图片地址数组中的第一个元素剔除,继续调用此方法直到存储图片地址的数组为空。

代码

const imgArrs=[...]; // 图片地址
const content=document.getElementById('content');
const loadImg=()=> {
if (!imgArrs.length) return;
const img=new Image(); // 新建一个Image对象
img.src=imgArrs[0];
img.setAttribute('class', 'img-item');
img.onload=()=> { // 监听onload事件
// setTimeout(()=> { // 使用setTimeout可以更清晰的看清实现效果
content.appendChild(img);
imgArrs.shift();
loadImg();
// }, 1000);
}
img.onerror=()=> {
// do something here
}
}
loadImg();

</script>

实现效果

加上setTimeout后,看到的效果更加明显,我这里加了500毫秒的延迟(录屏软件只支持录制8秒的时间...)

其实我在网上还看到了一种答案,通过onreadystatechange事件实现监听,于是在我本地调试了一下,发现并不能实现,img实例对象上并没有这个属性方法。查了查MDN,发现目前仅有XmlHttpRequest对象和Document对象中存在onreadystatechange属性,而对于其它元素onreadystatechange此属性并不存在。

因此对于其它元素需要慎用onreadystatechange事件

不过我电脑上目前只有Chorme和Safari两种浏览器,对于onreadystatechange测试的覆盖面不全,所以我上面的结论可能还需要进一步验证才行,感兴趣的掘友可以调试一下~。

扩展知识

img标签是什么时候发送图片资源请求的?

  1. HTML文档渲染解析,如果解析到img标签的src时,浏览器就会立刻开启一个线程去请求图片资源。
  2. 动态创建img标签,设置src属性时,即使这个img标签没有添加到dom元素中,也会立即发送一个请求。
// 例1:
const img=new Image();
img.src='http://xxxx.com/x/y/z/ccc.png';

上面的代码如果运行起来后,就会发送请求。 如图:

再看一个例子:创建了一个div元素,然后将存放img标签元素的变量添加到div元素内,而div元素此时并不在dom文档中,页面不会展示该div元素,那么浏览器会发送请求吗?

// 例2:
const img=`<img src='http://xxxx.com/x/y/z/ccc.png'>`;
const dom=document.createElement('div');
dom.innerHtml=img;

答案:会请求。如图:

通过设置css属性能否做到禁止发送图片请求资源?

  1. 给img标签设置样式display:none或者visibility: hidden,隐藏img标签,无法做到禁止发送请求。
<img src="http://xxx.com/x/sdf.png" style="display: none;">
或者
<img src="http://xxx.com/x/sdf.png" style="visibility: hidden;">
  1. 将图片设置为元素的背景图片,但此元素不存在,可以做到禁止发送请求。
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<title></title>
<style>
.test {
height: 200px;
background-image: url('http://eb118-file.cdn.bcebos.com/upload/39148b2a545b48bf9b4ee95fd1b7f1eb_1515564089.png?');
}
</style>
</head>
<body>
<div></div>
</body>
</html>

dom文档中不存在test元素时,即使设置了背景图片,也不会发送请求,只有test元素存在时才会发送请求。

另外这个例子其实有点不太贴切,img标签和background-image二者有着本质的区别。一个属于HTML标签,另一个属于css样式,加载机制和解析顺序也不同。

一个完整的页面是由js、html、css组成的,按照解析机制,html元素会优先解析,尽管css样式是放在head标签内的,但也不意味着它会优先加载,它只有等到html文档加载完成后才会执行。而img标签属于网页内容,所以img标签会随着网页解析渲染优先于css样式表加载出来。


作者:娜个小部呀
链接:https://juejin.cn/post/7340167256267391012

、认识网页

在学习之初,我们需要认识一下网页的概念,因为网页与我们的 html是息息相关的。

那么接下来我们来看一下,我们经常去通过浏览器查看的网页,它的本质是什么?在此我们需要去做一个对比。我们眼中看到的网页与程序员眼中看到的网页,到底有什么不同?

首先就是我们用户眼中看到的网页,这是一个普通的网页,它的一个首页的效果。这个里面大家可以看到有很多的文字内容,包括一些图片内容,并且呢它按照一定的格式去进行了一个排版,那么这些就是我们用户看到的网页。


用户眼中看到的网页


而同样这样一个网页,在程序员眼中是什么样的效果呢?实际上程序员眼中的网页,都是由这样一系列的代码组成,这个代码里面并不能直观的去展示成我们眼中看到的,比如图片以及其他的内容效果。那么程序员的这眼中的网页是怎么制作出来的。而用户眼中的这个网页又是怎么去呈现出来的?这是我们需要去思考的问题?

程序员眼中看到的网页

接下来我们先解决第一个问题,程序员是如何去制作网页文件的,其实程序员用的就是我们的 html 技术来去制作网页文件。而我们通过浏览器查看到的网页都是这种扩展名为点 html 或者是点 htm 的文件。

二、 HTML 是什么呢

HTML叫做超文本标记语言(Hypertext Markup Language),它是一种标记语言,主要就是用来去搭建网页的结构用的。

那么程序员制作的网页就是 html 文件吗?也不全是。网页的组成呢很复杂 它除了 HTML之外,还有其他的内容。

三、网页的组成

首先我们来看一下我们网页的里面,组成的一个相关技术,也就是我们前端所需要学习的三层技术:

这个里面 html 实际上它是我们制作网页的时候,第一层叫做结构层,他用来去搭建网页的整个的结构骨架;

第二层 css 是样式层,用来去美化我们的网页结构;

第三层叫做 javascript,它是行为层,这个行为实际上就是用来去制作,我们网页中的很多交互效果;比如用户点击的效果,我们的页面切换的其他效果等等;

我们通过一个小小的案例,来带大家好好理解一下什么是前端三层,大家都去自己绘画或者是观察过别人绘画的过程。如果我们去绘制一个人物的时候,那么我们首先需要绘制的就是这个人物的结构,这个结构比如说人物包含头部、身体以及四肢、我们需要去首先绘制一下它的轮廓,哪个地方是头部,哪个地方是身体,其实这个过程就相当于前端里面 html 在搭建结构;

搭建完结构之后,这样的一个人物是不好看的,所以我们需要用到 css 去对它进行美化,我可以给他去化妆穿衣服,这样我们就可以得到一个类似照片效果的人物,但是真正的人物效果它是可以去动的,是有各种各样的运动,各种各样的动作,这个动作和运动效果由谁来制作呢?就是我们 javascript 它的一个功能,它就相当于我们把一个静态的,美化之后的一个人物让它动起来。

当然我们网页除了这三层技术之外,它还包含其他的内容,就比如说我们看到的图片、视频、音频、超级链接等等;那么这些内容包括我们之前所讲的前端三层,它都是我们要去制作的具体存在的文件。

wagger 是一个简单、功能强大、非常流行的API 表达工具。基于Swagger 生成API,可以得到交互式文档、自动生成代码的SDK,以及API 的发现方式。

Swagger 允许用户在一个html5 web 页面中,对API 进行文档化和交互。

优点:

  • 功能丰富:支持多种注解,自动生成接口文档界面,支持在界面测试API接口功能;
  • 及时更新:开发过程中花一点写注释的时间,就可以及时的更新API文档,省心省力;
  • 整合简单:通过添加pom依赖和简单配置,内嵌于应用中就可同时发布API接口文档界面,不需要部署独立服务。

如下是自动生成的API 文档界面:

实现 Swagger 文档

1. 添加依赖

主要是 添加 swagger2 核心包 以及 swagger-ui界面包的依赖。

<dependency>

<groupId>io.springfox</groupId>

<artifactId>springfox-swagger2</artifactId>

<version>2.7.0</version>

</dependency>

<dependency>

<groupId>io.springfox</groupId>

<artifactId>springfox-swagger-ui</artifactId>

<version>2.7.0</version>

</dependency>

2. 编写Swagger的配置类

package com.rickie;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.ApiInfoBuilder;

import springfox.documentation.builders.PathSelectors;

import springfox.documentation.builders.RequestHandlerSelectors;

import springfox.documentation.service.ApiInfo;

import springfox.documentation.spi.DocumentationType;

import springfox.documentation.spring.web.plugins.Docket;

import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration

@EnableSwagger2

public class Swagger2 {

@Bean

public Docket createRestApi() {

return new Docket(DocumentationType.SWAGGER_2)

.apiInfo(apiInfo())

.select()

.apis(RequestHandlerSelectors.basePackage("com.rickie.rest"))

.paths(PathSelectors.any())

.build();

}

private ApiInfo apiInfo() {

return new ApiInfoBuilder()

.title("Swagger构建RESTful API")

.description("")

.termsOfServiceUrl("")

.version("1.0")

.build();

}

}

3. 在controller 中编写自己的api 文档,主要是参数和接口的描述

如下是ProductController.java 的示例代码。

package com.rickie.rest;

import com.rickie.dto.Product;

import io.swagger.annotations.ApiImplicitParam;

import io.swagger.annotations.ApiOperation;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;

import java.util.List;

@RestController

@RequestMapping(value="/products") // 通过这里配置使下面的映射都在/products下

public class ProductController {

private List<Product> productList;

//初始化

public ProductController(){

productList=new ArrayList<Product>();

for (int i=0; i < 10; i++) {

Product product=new Product();

product.setId(i);

product.setCount(i+10);

product.setName("watch"+i);

product.setDesc("watch desc"+i);

productList.add(product);

}

}

@ApiOperation(value="获取产品列表", notes="获取产品列表")

@RequestMapping(value={""}, method=RequestMethod.GET)

public List<Product> getProductList() {

return productList;

}

@ApiOperation(value="获取产品详细信息", notes="根据url的id来获取产品详细信息")

@ApiImplicitParam(name="id", value="产品ID", required=true, dataType="Integer",paramType="path")

@RequestMapping(value="/{id}", method=RequestMethod.GET)

public Product getProduct(@PathVariable Integer id) {

return productList.get(id);

}

}

@ApiOperation:

作用在方法上,表示一个http请求的操作 。

@ApiImplicitParam:

作用在方法上,表示单独的请求参数

参数:

1. name :参数名。

2. value : 参数的具体意义,作用。

3. required : 参数是否必填。

4. dataType :参数的数据类型。

5. paramType :查询参数类型,这里有几种形式:

@ApiImplicitParams:

用于方法,包含多个 @ApiImplicitParam。

@Api:

作用在类上,用来标注该类具体实现内容。标识这个类是swagger的资源 。

参数:

1. tags:允许您为操作设置多个标签的属性。

2. description:可描述该类的作用。

4. 启动应用程序,访问Swagger

访问如下链接,可以看到第一张图片所示,显示所有的API 列表方法。

http://localhost:8080/swagger-ui.html

点击查看第一个方法/products,如下图所示,可以进行交互操作。

访问 http://localhost:8080/v2/api-docs 可以获取接口的JSON 描述文件,如下图所示。