Maison  >  Article  >  interface Web  >  Comment implémenter un flux en cascade horizontal en JavaScript

Comment implémenter un flux en cascade horizontal en JavaScript

Guanhui
Guanhuiavant
2020-05-13 10:33:133523parcourir

Comment implémenter un flux en cascade horizontal en JavaScript

J'ai récemment travaillé sur un petit projet de programme et j'ai emprunté des conceptions d'interface utilisateur à d'autres applications. Parmi elles, il y a une interface utilisateur avec une disposition horizontale des images, qui semble. plutôt bien, semblable à une cascade traditionnelle. La disposition du flux est la même horizontalement. Je l'ai donc implémenté moi-même et étendu la méthode originale de deux images horizontales en une méthode permettant de personnaliser le nombre d'images affichées. Voici l'effet d'affichage de base :

Comment implémenter un flux en cascade horizontal en JavaScript

Afficher deux images sur une seule ligne

Comment implémenter un flux en cascade horizontal en JavaScript

Afficher cinq images sur une seule ligne ligne unique

Parlons d'abord de l'idée lors de l'écriture de cette méthode :

Analyse des effets

Comme vous pouvez le voir sur l'image ci-dessus, peu importe combien d'images sont affichées sur une seule ligne, il est presque garanti que l'image sera affichée complètement et la hauteur de chaque ligne est différente - ceci afin de garantir que chaque image peut être affichée presque complètement, donc la hauteur de la ligne doit être ajusté dynamiquement en fonction de l'image réelle à afficher.

Étant donné que le rendu des pixels doit être arrondi, il y aura une erreur de 1~2px dans le calcul de la largeur et de la hauteur de l'image. Cette erreur peut être directement ignorée et n’entraînera pas d’étirement visuel de l’image.

Après avoir analysé l'effet, nous nous posons les questions suivantes :

1. Comment s'assurer que chaque ligne peut afficher entièrement les images à l'intérieur ? Il faut savoir que la largeur et la hauteur de chaque image sont différentes

2. Comment calculer dynamiquement la hauteur de chaque rangée ?

3. Lorsque le nombre d'images restantes à la fin ne correspond pas au nombre d'images affichées sur une seule ligne, comment disposer les images dans la dernière ligne ?

4. ...

Analyse du problème

Regardons d'abord la première question : comment garantir que chaque image d'une seule ligne peut être affiché complètement.

Tout d'abord, nous pouvons déterminer le nombre d'images affichées sur une seule ligne. Ceci est prédéfini, comme la ligne unique de 5 images ci-dessus, numberInLine = 5. Chaque image de la même ligne a la même hauteur, vous pouvez donc calculer la largeur d'une seule ligne lorsque l'image est réellement rendue en fonction du rapport entre la largeur de l'image et la largeur totale de toutes les images. La formule est la suivante. :

imageRenderWidth = (imageWidth / imagesTotalWidth) * lineWidth

Bien que la largeur et la hauteur réelles des images soient différentes, puisque la hauteur d'une seule rangée d'images est la même, nous pouvons d'abord supposer une hauteur standard stdHeight et redimensionner la largeur de chaque image proportionnellement grâce à cette hauteur standard, afin que le calcul puisse être fluide. Obtenez le rapport entre la largeur d'une seule image et la largeur totale de toutes les images

Comment calculer la hauteur de chaque ligne

En partant du principe que la largeur de l'image peut être déterminée, chaque rangée doit être déterminée. La hauteur est relativement simple. En fonction de la première image de chaque ligne, calculez d'abord la largeur de rendu de la première image, puis calculez la hauteur de rendu de cette image et utilisez-la comme hauteur de ligne. Chaque image suivante calculera sa propre hauteur à travers la hauteur de ligne. largeur de rendu. Cependant, il convient de noter que pour remplir une seule ligne, la dernière image doit être calculée en fonction de la largeur totale - la somme des largeurs de toutes les images précédentes, sinon il y aura des espaces. La formule d'expression est la suivante :

// 第一张图片渲染宽度
firstImageRenderWidth = (firstImageWidth / imagesTotalWidth) * lineWidth
// 第一张图片渲染高度,即行高,即该行所有图片高度
lineHeight = imagesRenderHeight = firstImageRenderWidth / (firstImageWidth / firstImageHeight)
// 中间图片渲染宽度
middleImageRenderWidth = lineHeight * (middleImageWidth / middleImageHeight)
// 最后一张图片渲染宽度
lastImageRenderWidth = lineWidth - otherImagesTotalRenderWidth

Comment mettre en page lorsque le nombre d'images restantes est inférieur au nombre de lignes simples ?

Ce problème doit être pris en compte dans deux situations :

1 Lorsqu'une seule ligne nécessite 5 images, mais que le nombre restant est inférieur à 5 mais supérieur à 1 (comme par exemple. 4 images) : Cette ligne peut être disposée en fonction du nombre d'images restantes, et l'algorithme est toujours le même que ci-dessus. Par conséquent, pour ce point, le code doit être réutilisable ;

2 Lorsqu'il ne reste qu'une seule image, il existe plusieurs méthodes de traitement :

Cette image peut être remplie toute la ligne. la largeur est affichée complètement, mais si cette image est une image de très grande hauteur, cela affectera sérieusement l'esthétique de la mise en page

L'image remplira toujours la largeur de la ligne, mais étant donné une hauteur maximale, lorsque la hauteur Lorsque elle est inférieure à la hauteur maximale, elle sera affichée en totalité, et lorsqu'elle la dépasse, seule une partie sera affichée. Cela peut assurer la beauté de la mise en page, mais il y a des défauts dans l'affichage de la dernière image

Prendre la hauteur de ligne de la ligne précédente comme hauteur de ligne de la dernière ligne, comme ceci. L'image peut toujours être affichée complètement tout en assurant la cohérence de la mise en page globale, mais cela laissera beaucoup d'espace vide dans le dernière ligne

Pour les trois méthodes de traitement ci-dessus, l'auteur utilise la seconde. Les amis intéressés peuvent essayer les deux autres méthodes par eux-mêmes. Ou si vous avez une meilleure méthode de mise en page, vous pouvez également en informer l'auteur dans les commentaires !

Je me demande si vous comprenez les explications des trois questions ci-dessus ? Ce n'est pas grave si vous ne comprenez pas. Vous pouvez apprendre à résoudre ces problèmes directement via le code.

Implémentation du code

/* imagesLayout.js */
/*
 * 图片横向瀑布流布局 最大限度保证每张图片完整显示 可以获取最后计算出来的图片布局宽高信息 最后的瀑布流效果需要配合 css 实现(作者通过浮动布局实现)当然你也可以对代码进行修改 让其能够直接返回一段已经布局完成的 html 结构
 * 需要先提供每张图片的宽高 如果没有图片的宽高数据 则可以在代码中添加处理方法从而获取到图片宽高数据后再布局 但是并不推荐这样做
 * 尽量保证图片总数能被单行显示的数量整除 避免最后一行单张显示 否则会影响美观
 * 每张图由于宽高取整返回的宽高存在0-2px的误差 可以通过 css 保证视觉效果
 */
/*
 * @param images {Object} 图片对象列表,每一个对象有 src width height 三个属性
 * @param containerWidth {Integer} 容器宽度
 * @param numberInLine {Integer} 单行显示图片数量
 * @param limit {Integer} 限制需要进行布局的图片的数量 如果传入的图片列表有100张 但只需要对前20张进行布局 后面的图片忽略 则可以使用此参数限制 如果不传则默认0(不限制)
 * @param stdRatio {Float} 图片标准宽高比
 */
class ImagesLayout {
  constructor(images, containerWidth, numberInLine = 10, limit = 0, stdRatio = 1.5) {
    // 图片列表
    this.images = images
    // 布局完毕的图片列表 通过该属性可以获得图片布局的宽高信息
    this.completedImages = []
    // 容器宽度
    this.containerWidth = containerWidth
    // 单行显示的图片数量
    this.numberInLine = numberInLine
    // 限制布局的数量 如果传入的图片列表有100张 但只需要对前20张进行布局 后面的图片忽略 则可以使用此参数限制 如果不传则默认0(不限制)
    this.limit = limit
    // 图片标准宽高比(当最后一行只剩一张图片时 为了不让布局看上去很奇怪 所以要有一个标准宽高比 当图片实际宽高比大于标准宽高比时会发生截取 小于时按照实际高度占满整行显示)
    this.stdRatio = stdRatio
    // 图片撑满整行时的标准高度
    this.stdHeight = this.containerWidth / this.stdRatio
    this.chunkAndLayout()
  }
  // 将图片列表根据单行数量分块并开始计算布局
  chunkAndLayout () {
    // 当图片只有一张时,完整显示这张图片
    if (this.images.length === 1) {
      this.layoutFullImage(this.images[0])
      return
    }
    let temp = []
    for (let i = 0; i < this.images.length; i++) {
      if (this.limit && i >= this.limit) return
      temp.push(this.images[i])
      // 当单行图片数量达到限制数量时
      // 当已经是最后一张图片时
      // 当已经达到需要布局的最大数量时
      if (i % this.numberInLine === this.numberInLine - 1 || i === this.images.length - 1 || i === this.limit - 1) {
        this.computedImagesLayout(temp)
        temp = []
      }
    }
  }
  // 完整显示图片
  layoutFullImage (image) {
    let ratio = image.width / image.height
    image.width = this.containerWidth
    image.height = parseInt(this.containerWidth / ratio)
    this.completedImages.push(image)
  }
  // 根据分块计算图片布局信息
  computedImagesLayout(images) {
    if (images.length === 1) {
      // 当前分组只有一张图片时
      this.layoutWithSingleImage(images[0])
    } else {
      // 当前分组有多张图片时
      this.layoutWithMultipleImages(images)
    }
  }
  // 分组中只有一张图片 该张图片会单独占满整行的布局 如果图片高度过大则以标准宽高比为标准 其余部分剪裁 否则完整显示
  layoutWithSingleImage (image) {
    let ratio = image.width / image.height
    image.width = this.containerWidth
    // 如果是长图,则布局时按照标准宽高比显示中间部分
    if (ratio < this.stdRatio) {
      image.height = parseInt(this.stdHeight)
    } else {
      image.height = parseInt(this.containerWidth / ratio)
    }
    this.completedImages.push(image)
  }
  // 分组中有多张图片时的布局
    // 以相对图宽为标准,根据每张图的相对宽度计算占据容器的宽度
  layoutWithMultipleImages(images) {
    let widths = [] // 保存每张图的相对宽度
    let ratios = [] // 保存每张图的宽高比
    images.forEach(item => {
      // 计算每张图的宽高比
      let ratio = item.width / item.height
      // 根据标准高度计算相对图宽
      let relateWidth = this.stdHeight * ratio
      widths.push(relateWidth)
      ratios.push(ratio)
    })
    // 计算每张图片相对宽度的总和
    let totalWidth = widths.reduce((sum, item) => sum + item, 0)
    let lineHeight = 0 // 行高
    let leftWidth = this.containerWidth // 容器剩余宽度 还未开始布局时的剩余宽度等于容器宽度
    images.forEach((item, i) => {
      if (i === 0) {
        // 第一张图片
        // 通过图片相对宽度与相对总宽度的比值计算出在容器中占据的宽度与高度
        item.width = parseInt(this.containerWidth * (widths[i] / totalWidth))
        item.height = lineHeight = parseInt(item.width / ratios[i])
        // 第一张图片布局后的剩余容器宽度
        leftWidth = leftWidth - item.width
      } else if (i === images.length - 1) {
        // 最后一张图片
        // 宽度为剩余容器宽度
        item.width = leftWidth
        item.height = lineHeight
      } else {
        // 中间图片
        // 以行高为标准 计算出图片在容器中的宽度
        item.height = lineHeight
        item.width = parseInt(item.height * ratios[i])
        // 图片布局后剩余的容器宽度
        leftWidth = leftWidth - item.width
      }
      this.completedImages.push(item)
    })
  }
}
rrree

Tutoriel recommandé : "

Tutoriel JS"

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer