1

Scene 1: Automatically cut molecular pages

image.png

Require

The dialog content is automatically filled according to the size of the page container. When the screen is too large to display only one dialogue, reduce the font size to fit the container size.

Realization principle

Use a hidden content area element as a virtual container to measure the actual space required for content rendering, and then use the actual space obtained to calculate paging.

Parent component:

<template>
    <div
      id="view-container"
      class="slide-page-container swiper-wrapper"
  >
      <!-- 虚拟容器 -->
      <virtual-content 
        :index="index"
        :sentences="sentences"
      />
     <!-- 实际内容 -->
      <div 
        v-for="(sentenceInfo, sliderIndex) of list"
        :key="sliderIndex"
        :class="[
          'slide-page-content',
          'swiper-slide',
          `swiper-slide-${sliderIndex}`
        ]"
      >
        <p
          v-for="(item,pIndex) of sentenceInfo"
          :key="pIndex"
          class="reality-content"
          :style="getPStyle(item,sliderIndex, pIndex)"
         >
         ...

     </div>
  </div>
...

</template>

Virtual element components:

<template>
  <div
    :id="`nodes-parent-${index}`"
    class="slide-page-all"
  >
    <p
      class="virtual-content"
      v-for="(sentence,sententceIndex) of sentences"
      :key="sententceIndex"
    >
      <br v-if="sentence.empty">
      <span 
        v-else
        class="word"
      >{{ sentence.englishSubtitle}}</span>
    </p>
  </div>
</template>
<style lang="less" scoped>
.slide-page-all{
  visibility: hidden;
  position:absolute;
  top:0;
  left:0;
  right: 0;
  .virtual-content{
    font-size: 20px;
    line-height: 1.5;
  }
}
</style>

Note: In order to ensure that the virtual container is loaded before the actual target container, the virtual container can be used as a subcomponent at the same level as the target container.

Paging calculation

// 增加索引
const addIndexToValue = arr => {
  return arr.map((v, i) => {
    return {
      index: i,
      height: v
    };
  });
};

/** 分页算法【重点】
 * arr: 每一段内容所占的实际高度的集合
 * max: 目标容器的最大高度
 * /
const getPages = (arr, max) => {
  if (max <= 0 ) {
    return [];
  }
  const result = [];
  const data = addIndexToValue(arr);

  let pre = 0;
  let tmp = [];
  for (let i = 0, len = data.length; i < len; i++) {

    const current = pre + data[i].height;
    if (current >= max) {
        if (tmp.length > 0) {
          result.push(tmp);
          tmp = [{ ... (data[i] || {}), currentIndex: 0}];
          pre = data[i].height;
          if (i === data.length - 1) {
            result.push(tmp);
          }
        } else {
          result.push([{ ... (data[i] || {}), currentIndex: 0}]);
          tmp = [];
        }
    } else {
      tmp.push({ ...(data[i] || {}), currentIndex: tmp.length});
      pre = pre + data[i].height;
      if (i === data.length - 1) {
        result.push(tmp);
      }
    }
  }
  return result;
};

// 缓冲值15
const OFFSET = 15;

// 在页面中的实际应用
export const  getComputedNode = index => {
  const wrap = document.getElementById('view-container');
  if (!wrap) {
    return [];
  }
  const parent = document.getElementById(`nodes-parent-${index}`);
  const wrapHeight = wrap.clientHeight;
  const children = Array.from(parent.children);
  const arr = [];
  children.reduce((pre, node) => {
     const height = node.clientHeight;
     pre.push(height);
    return pre;
  }, arr);

  const result = getPages(arr, wrapHeight - OFFSET);
  return result;
};

Font reduction judgment

  // font-size
  public getResizeStyle(sliderIndex, pIndex) {
    const swiperPages = this.list[sliderIndex];
    if (swiperPages.length === 1) {
      // 只有一句话的时候
      const { height } = this.list[sliderIndex][pIndex]; // height:自适应时预设的高度
      const parentHeight = document.getElementById('view-container').clientHeight; // parentHeight:实际父容器高度

      const wordEl = document.querySelector('.virtual-content .word');
      if (!wordEl) {
        // 元素还未渲染的时候
        return '';
      }
      const fontSizeStr = window.getComputedStyle(wordEl)['font-size'] || '';
      const fontSize = parseFloat(fontSizeStr);
    // 当预设的高度大于实际父容器高度时,字体要缩小以适应显示
      if ( height > parentHeight) {
        return `font-size: ${Math.floor(fontSize * parentHeight / height)}px`;
      }
      return '';
    } else {
      return '';
    }
  }

Expand

encounters the need for adaptation in the future, you can use virtual elements to measure and then calculate the adaptation.

Scenario 2: Adapt to three cards in each row

image.png

Require

3 in a row, less than 3 are arranged in order from left to right.

Realization principle

  • Three elements are fixed in each line, the height of each element is fixed, the spacing in the horizontal and vertical directions is fixed, and the width is adaptive
  • In order to support justify-content:space-between well, you need to deal with sum % 3 is 2 : insert an empty element in the data
.content{
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
}

Scene 3: The content is left, the whole is centered

image.png

Require

In paragraphs of varying lengths, the contents of all paragraphs should be displayed on the left, and a layer of containers outside the paragraphs should be displayed in the middle of the page.

Realization principle

  • The layout is divided into three levels: text paragraph, text paragraph container, and chapter container
  • In order to realize the text content reaches the upper limit in the horizontal direction and then wrap again, the text paragraph container adopts display:inline-block , so that the text content will automatically wrap after the horizontal direction is filled. The text paragraph container text-align:left realizes left alignment

    .pcontainer{
      display:inline-block;
      text-align:left
    }
  • The content of the text container can be aligned in the center

    .chapter{
      display:flex;
      justify-content: center;
    }

Reference materials:


specialcoder
2.2k 声望170 粉丝

前端 设计 摄影 文学