javascript和css实现瀑布流排列

Grid 布局 实现瀑布流

  • html

    <div class="gridDiv">
      <div
        v-for="(item,index) in 20"
        :style="{
           
           'grid-row': `auto / span ${heightArray[index]}`}"
      >
        <div class="gridItemConten">
          <div class="gridText">
            {
         
         {item}}-{
         
         {index}}
            <div v-for="el in item" v-if="item<6">
              item:{
         
         {item}}--{
         
         {el}} ++ item:{
         
         {item}}--{
         
         {el}}
            </div>
          </div>
        </div>
      </div>
    </div>
    <style lang="scss" scoped>
      .gridDiv {
            
            
        width: calc(100% - 20px);
        margin: 0 auto;
        display: grid;
        grid-template-columns: repeat(3, 1fr); // 指定三列,自动宽度
        grid-column-gap: 30px; //横向间隔
        grid-auto-flow: row dense; // 是否自动补齐空白
        grid-auto-rows: 1px; // base高度,grid-row基于此运算
        // justify-items: center;
        .gridItemConten {
            
            
          padding-bottom: 10px; // 纵向间距
          .gridText {
            
            
            text-align: center;
            background-color: red;
          }
        }
      }
    </style>
    
  • js

     data() {
          
          
        return {
          
          
          heightArray:[]
        }
      },
      created(){
          
          
         this.$nextTick(()=>{
          
          
                const gridHeightFn=()=>{
          
          
                        Array.prototype.slice.call(document.querySelectorAll('.gridDiv .gridItemConten')).forEach((item,index)=>{
          
          
                                this.heightArray.splice(index,1,parseInt(item.getBoundingClientRect().height))
                        })
                }
                window.onresize=()=>{
          
          
                        gridHeightFn()
                }
                gridHeightFn()
        })
      },
    
  • 实现:
    在这里插入图片描述

multi-column 多列布局实现瀑布流

  • html:

    <div class="gapDiv">
      <div class="gapItem" v-for="item in 10">
        {
         
         {item}}
        <div v-for="el in item" v-if="item<6">
          item:{
         
         {item}}--{
         
         {el}} ++ item:{
         
         {item}}--{
         
         {el}}
        </div>
      </div>
    </div>
    <style lang="scss" scoped>
      .gapDiv {
            
            
        width: calc(100% - 20px);
        margin: 0 auto;
        column-count: 4; // 默认列数
        column-gap: 30px; // 列间距
        .gapItem {
            
            
          break-inside: avoid; // 防止item展示不全裂开
          width: 150px;
          background-color: red;
          margin-bottom: 10px;
        }
      }
    </style>
    
  • 实现:
    在这里插入图片描述

flex 布局实现瀑布流

  • html:

    <div class="flexDiv">
      <div class="flexItem" v-for="item in 10">
        {
         
         {item}}
        <div v-for="el in item" v-if="item<6">
          item:{
         
         {item}}--{
         
         {el}} ++ item:{
         
         {item}}--{
         
         {el}}
        </div>
      </div>
    </div>
    <style lang="scss" scoped>
      .flexDiv {
            
            
        width: calc(100% - 20px);
        margin: 0 auto;
        display: flex;
        flex-flow: column wrap;
        height: 30vh;
        .flexItem {
            
            
          background-color: red;
          margin-bottom: 10px;
          width: calc(100% / 3 - 20px);
        }
      }
    </style>
    
  • 实现:

    在这里插入图片描述

js 实现

  • html:

    <div class="divBox" id="divBox1">
      <div class="boxItem" v-for="item in 10">
        {
         
         {item}}
        <div v-for="el in item" v-if="item<6">
          item:{
         
         {item}}--{
         
         {el}} ++ item:{
         
         {item}}--{
         
         {el}}
        </div>
      </div>
      <div class="div-main"></div>
    </div>
    <style lang="scss" scoped>
      .divBox {
            
            
        width: calc(100% - 20px);
        margin: 0 auto;
        .boxItem {
            
            
          // width:150px;
          background-color: red;
        }
        .div-main {
            
            
          margin-top: 20px;
          width: 100%;
          height: 300px;
          background-color: #3772f6;
        }
      }
    </style>
    
  • js:

    created(){
          
          
      this.$nextTick(()=>{
          
          
          window.onresize=()=>{
          
          
            this.waterfallView('#divBox1',{
          
          itemEl:'.boxItem',paddingX:20,paddingY:10,isFollow:true,justifyContent:'center'})
          }
          this.waterfallView('#divBox1',{
          
          itemEl:'.boxItem',paddingX:20,paddingY:10,isFollow:true,justifyContent:'center'})
        })
    },
    methods:{
          
          
      // 瀑布流
        /**
         * elName:父级元素的class 或者id,如:'.boxItem'、'#boxItem'
        * objectData:{
          * itemEl:对应item的calss,如:'.boxItem',不传入默认是父级元素下面的所有元素
          * paddingX:横向的间距
          * paddingY:竖向的间距
          * rowNum:显示多少列,不传就设置固定宽度
          * justifyContent:横向的位置,left、center、right(设置这个的时候,不需要传入rowNum才会生效)
          * isFollow:是否自动填充到最小列
        * }
        * */
        waterfallView(elName,objectData){
          
          
          let thisIsReset=false
          const elDom=document.querySelectorAll(elName)
          const changeView = async (el)=>{
          
          
            const {
          
          itemEl=null,paddingX=0,paddingY=0,rowNum=0,isFollow=false,justifyContent=''}=objectData
            let thisRowNum=rowNum
            let thisPaddingX=paddingX
            const allWidth = el.offsetWidth
            const thisBlaknDom=el.querySelector('.--blakn-div--')
            if(thisBlaknDom && el.getAttribute('elWidth')){
          
          
              if(thisBlaknDom.offsetWidth!=Number(el.getAttribute('elWidth'))){
          
          
                thisIsReset=true
              }else{
          
          
                thisIsReset=false
              }
            }
            el.setAttribute('elWidth',allWidth)
            el.style.position='relative'
            // 获取已经存在的对应列的数组
            const heightArray=thisIsReset?[]:(el.getAttribute('heightArray')?JSON.parse(el.getAttribute('heightArray')):[]);
            // 获取需要瀑布流的dom的元素组
            const elChildrenArray=itemEl? Array.prototype.slice.call(el.querySelectorAll(itemEl)):Array.prototype.slice.call(el.children).filter(n=>n.className.indexOf('--blakn-div--')==-1)
            let firstLeft=0
            let itemWidth =0
            if(thisRowNum>0){
          
          
              itemWidth = (allWidth-(thisRowNum-1)*thisPaddingX)/thisRowNum
            }else{
          
          
              itemWidth = elChildrenArray[0].offsetWidth
              thisRowNum = parseInt((allWidth+thisPaddingX) / (itemWidth + thisPaddingX))
              if(justifyContent!=''){
          
          
                thisPaddingX=0
                if(justifyContent=='left'){
          
          
                  thisPaddingX=paddingX
                  thisRowNum = parseInt((allWidth+thisPaddingX) / (itemWidth + thisPaddingX))
                }else if(justifyContent=='center'){
          
          
                  let newRowNum= parseInt(allWidth/itemWidth)
                  newRowNum=newRowNum>elChildrenArray.length?elChildrenArray.length:newRowNum
                  if(newRowNum-1>0){
          
          
                    thisPaddingX = (allWidth - itemWidth*newRowNum)/(newRowNum-1)-0.5
                  }else{
          
          
                    thisPaddingX=0
                    firstLeft=(allWidth-itemWidth) /2
                  }
                  thisRowNum = parseInt((allWidth+thisPaddingX) / (itemWidth + thisPaddingX))
                }else{
          
          
                  thisPaddingX=paddingX
                  thisRowNum = parseInt((allWidth+thisPaddingX) / (itemWidth + thisPaddingX))
                  firstLeft = allWidth-(itemWidth*thisRowNum + thisPaddingX*(thisRowNum-1))
                  if(allWidth <= itemWidth){
          
          
                    firstLeft = 0
                  }
                }
              }
    
            }
            thisRowNum = thisRowNum<=0?1:thisRowNum
            const elLength=elChildrenArray.length
            // 获取开始循环的index
            const addIndex=thisIsReset?0:(el.getAttribute('lastIndex')?Number(el.getAttribute('lastIndex')):0)
            for (let i=addIndex+1;i<=elLength;i++){
          
          
              const thisIndex=i-1
              const item=elChildrenArray[thisIndex]
              const indexNum=i%thisRowNum==0?thisRowNum:i%thisRowNum
              // --------------------
              // const itemHeight=elChildrenArray[0].offsetHeight
              // item.style.height=itemHeight+(indexNum-1)*40+'px'
              // --------------------
              let newIndex=indexNum
              // 动态将item追加到最小高度列的数组位置
              if(isFollow){
          
          
                const newHeightArray=heightArray.map(n=>n+item.offsetHeight+(thisIndex-thisRowNum<0?0:paddingY))
                if(newHeightArray.length>=thisRowNum){
          
          
                  newIndex=newHeightArray.indexOf(Math.min(...newHeightArray))+1
                }
              }
              const styleObject={
          
          }
              // 获取对应列的高度,并计算当前item对应的top
              let thisTop=heightArray[newIndex-1]?heightArray[newIndex-1]:0
              thisTop=(thisTop + (thisIndex-thisRowNum<0?0:paddingY))
              // 计算对应item的left
              let thisLeft=(newIndex-1)*itemWidth
              thisLeft =firstLeft+thisLeft+(newIndex==1?0:thisPaddingX*(newIndex-1))
              // 设置item对应的style
              styleObject['position']='absolute'
              styleObject['top']=thisTop+'px'
              styleObject['left']=thisLeft+'px'
              styleObject['width']=itemWidth+'px'
              Object.keys(styleObject).forEach(key=>{
          
          
                item.style[key]=styleObject[key]
              })
              // 给对应列的高度增加当前item的高度
              heightArray[newIndex-1]=thisTop+item.offsetHeight
    
              // 设置当前的index
              item.setAttribute('index',thisIndex)
            }
            // 在父级元素设置每列高度的数组
            el.setAttribute('heightArray',JSON.stringify(heightArray))
            // 设置当前循环的最后一个元素的index
            el.setAttribute('lastIndex',elLength)
            // 为父级元素填充占位div
            const blaknDivStyle=`width:100%;height:${
            
            Math.max(...heightArray)}px`
            if(el.querySelectorAll('.--blakn-div--').length>0){
          
          
              Array.prototype.slice.call(el.querySelectorAll('.--blakn-div--'))[0].style=blaknDivStyle
            }else{
          
          
              const blaknDom=document.createElement('div')
              blaknDom.setAttribute('class','--blakn-div--')
              blaknDom.style=blaknDivStyle
              el.insertBefore(blaknDom, elChildrenArray[0]);
            }
          }
          Array.prototype.slice.call( elDom ).forEach(elItem=>{
          
          
            changeView(elItem)
          })
        },
    }
    
  • 实现:
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_40591925/article/details/131478588