移动端常见布局方案

specialCoder -
移动端常见布局方案
场景一:自动切分子页

image.png

要求

根据页面容器大小自动装填对话内容。当屏幕中仅能显示一段对话还过大时,缩小字号以适应容器大小。

实现原理

使用一个隐藏的内容区域元素作为虚拟容器去丈量内容渲染所需要的实际空间,然后通过得到的实际空间去计算分页。

父组件:

<template>
    <div
      id="view-container"
      
  >
      <!-- 虚拟容器 -->
      <virtual-content 
        :index="index"
        :sentences="sentences"
      />
     <!-- 实际内容 -->
      <div 
        v-for="(sentenceInfo, sliderIndex) of list"
        :key="sliderIndex"
        :
      >
        <p
          v-for="(item,pIndex) of sentenceInfo"
          :key="pIndex"
          
          :
         >
         ...

     </div>
  </div>
...

</template>

虚拟元素组件:

<template>
  <div
    :id="`nodes-parent-${index}`"
    
  >
    <p
      
      v-for="(sentence,sententceIndex) of sentences"
      :key="sententceIndex"
    >
      <br v-if="sentence.empty">
      <span 
        v-else
        
      >{{ 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>

注意: 为了保证虚拟容器在实际目标容器前加载,可以将虚拟容器作为和目标容器同级的子组件。

分页计算
// 增加索引
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-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 '';
    }
  }
场景二:每排三个卡片适应

image.png

要求

3个一排,小于3个从左往右依次排列。

场景四:内容左,整体居中

image.png

实现上面的布局: 在长度长短不一的段落中要保持所有段落的内容居左显示,段落外的一层容器在页面中间显示。

参考资料:

https://zhuanlan.zhihu.com/p/...
特别申明:本文内容来源网络,版权归原作者所有,如有侵权请立即与我们联系(cy198701067573@163.com),我们将及时处理。

Tags 标签

csshtml5

扩展阅读

加个好友,技术交流

1628738909466805.jpg