vue中实现css布局(flex)

在vue中通过flex布局实现css的s型结构

通过数组截取循环布局,奇数行从左到右,在偶数行从右到左实现s型结构

主要内容分为三部分

中间内容部分

数据格式

js 复制代码
     items: [
           {
               nodeList: [1, 2, 3, 4, 5, 6]
           },
           {
               nodeList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
           }, {
               nodeList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
           },
           {
               nodeList: [1, 2, 3, 4]
           }
       ],
js 复制代码
<template>
	<a-row class="row" id="row" :class="alignItem(index)" :style="styleRow(index)">
	  <template v-for="(ite,inde) in it">
	      <a-col :xxl="4" :xl="6" :lg="8" :md="12">
	          <div class="lineBg" :style="{height: lineHeight+'px'}"
	               :class="{
	                    'lineBorderLeft':it.length<row && inde===0 && index!=0  && inde!=it.length-1 && index%2!=0 || (item.nodeList.length===row*index+1 && index % 2 !== 0),
	                    'lineBorderRight':(it.length<row && inde==it.length-1 && index%2==0)}">
	              <div class="line-title">
	                  <div class="boxGrey">{{ ite }}</div>
	              </div>
	          </div>
	          <template>
	              <div class="item">
	                  <div>
	                      row:{{ row }}<br/>
	                      it:{{ it.length }}<br/>
	                      index:{{ index }}<br/>
	                  </div>
	              </div>
	          </template>
	          <!--   半圆的时候设置占位   -->
	          <div v-if="!hasRightAngle" :style="{height: lineHeight+'px'}"></div>
	      </a-col>
	  </template>
	</a-row>
</template>
computed:{
    styleRow() {
           return function (index) {
               if (index > 0) {
                   return {
                       marginTop: !this.hasRightAngle ? `-${this.lineHeight}px` : 0
                   }
               }
           }
       },
       alignItem() {
           return function (index) {
               return index % 2 !== 0 ? 'justify-end' : ''
           }
       },
}
两端拼接的直接和半圆处理

linexx-round-r 和 linexx-round-l 代表拐角处的半圆处理

linexx-l和linexx-r两端的直角

可以切换为直角和半圆

js 复制代码
    Vue.component('linexx-round-r', {
        template: `
          <div class="linexx-body" :style="styleRoundRow(index)">
          <div class="linexxrRound"
               v-if="index%2==0 && index!=splitArrayByLength(item.nodeList,row).length-1">
            <div class="innerxx-inner"></div>
          </div>
          <template v-else>
            <div style="width: 130px" class="linexxr-box" v-if="index<=0 && it.length>=row"
                 :style="styleRoundRow(index)">
            </div>
            <div style="width: 130px" v-else :style="styleRoundRow(index)"></div>
          </template>
          </div>`,
        props: ['it', 'item', 'index', 'row', "lineHeight"],
        inject: ['splitArrayByLength'],
        computed: {
            styleRoundRow() {
                return function (index) {
                    if (index > 0) {
                        return {
                            marginTop: `-${this.lineHeight}px`
                        }
                    }
                }
            },
        }
    })

    Vue.component('linexx-round-l', {
        template: `
          <div class="linexx-body" :style="styleRoundRow(index)">
          <div class="linexxlRound"
               v-if="index%2!=0 && index!=splitArrayByLength(item.nodeList,row).length-1">
            <div class="innelxx-inner"></div>
          </div>
          <template v-else>
            <div style="width: 130px" class="linexxl-box" v-if="index<=0"
                 :style="styleRoundRow(index)"></div>
            <div v-else style="width: 130px" :style="styleRoundRow(index)"></div>
          </template>
          </div>`,
        props: ['it', 'item', 'index', 'row', 'lineHeight'],
        inject: ['splitArrayByLength'],

        computed: {
            styleRoundRow() {
                return function (index) {
                    if (index > 0) {
                        return {
                            marginTop: `-${this.lineHeight}px`
                            // marginTop: `-17px`
                        }
                    }
                }
            },
        }
    })

    Vue.component('linexx-l', {
        template: `
          <div class="linexx-body">
          <div class="linexxl linexxLeft"
               v-if="index%2!=0 && index!=splitArrayByLength(item.nodeList,row).length-1">
          </div>
          <template v-else>
            <div class="linexxl-box" v-if=" index%2==0 || it.length===row"></div>
            <div v-else style="width: 25px"></div>
          </template>
          </div>`,
        props: ['it', 'item', 'index', 'row'],
        inject: ['splitArrayByLength'],
    })

    Vue.component('linexx-r', {
        template: `
          <div class="linexx-body">
          <div class="linexxr linexxRight"
               v-if="index%2==0 && index!=splitArrayByLength(item.nodeList,row).length-1">
          </div>
          <template v-else>
            <div class="linexxr-box" v-if=" index%2!=0 || it.length===row" style="width: 25px"></div>
            <div v-else style="width: 25px"></div>
          </template>
          </div>`,
        props: ['it', 'item', 'index', 'row'],
        inject: ['splitArrayByLength'],
    })
顶点处理

判断有点复杂 应该还可以优化优化

js 复制代码
<div class="lineBg" :style="{height: lineHeight+'px'}"
        :class="{
             'lineBorderLeft':it.length<row && inde===0 && index!=0  && inde!=it.length-1 && index%2!=0 || (item.nodeList.length===row*index+1 && index % 2 !== 0),
             'lineBorderRight':(it.length<row && inde==it.length-1 && index%2==0)}">
       <div class="line-title">
           <div class="boxGrey">{{ ite }}</div>
       </div>
   </div>
完整代码
html 复制代码
<div id="app">
    <div class="container-bg">
        <div class="container" :style="containerStyle">
            <div class="container-list" v-for="(item,inx) in items">
                <div class="row-title">
                    <div class="row-title-text">{{ inx }}</div>
                </div>
                <div style="width: 100%" :id="`row${inx}`">
                    <template v-for="(it,index) in splitArrayByLength(item.nodeList,row)">
                        <div style="width: 100%;position: relative;display: flex">
                            <template v-if="hasRightAngle">
                                <linexx-l :it="it" :item="item" :index="index"
                                          :row="row"></linexx-l>
                            </template>
                            <template v-else>
                                <linexx-round-l :line-height="lineHeight" :it="it" :item="item" :index="index"
                                                :row="row"></linexx-round-l>
                            </template>
                            <a-row class="row" id="row" :class="alignItem(index)" :style="styleRow(index)">
                                <template v-for="(ite,inde) in it">

                                    <a-col :xxl="4" :xl="6" :lg="8" :md="12">

                                        <div class="lineBg" :style="{height: lineHeight+'px'}"
                                             :class="{
                                                  'lineBorderLeft':it.length<row && inde===0 && index!=0  && inde!=it.length-1 && index%2!=0 || (item.nodeList.length===row*index+1 && index % 2 !== 0),
                                                  'lineBorderRight':(it.length<row && inde==it.length-1 && index%2==0)}">
                                            <div class="line-title">
                                                <div class="boxGrey">{{ ite }}</div>
                                            </div>
                                        </div>
                                        <template>
                                            <div class="item">
                                                <div>
                                                    row:{{ row }}<br/>
                                                    it:{{ it.length }}<br/>
                                                    index:{{ index }}<br/>
                                                </div>
                                            </div>
                                        </template>
<!--                                        -->
                                        <div v-if="!hasRightAngle" :style="{height: lineHeight+'px'}"></div>
                                    </a-col>
                                </template>
                            </a-row>

                            <template v-if="hasRightAngle">
                                <linexx-r :it="it" :item="item" :index="index"
                                          :row="row"></linexx-r>
                            </template>
                            <template v-else>
                                <linexx-round-r :line-height="lineHeight" :it="it" :item="item" :index="index"
                                                :row="row"></linexx-round-r>
                            </template>

                        </div>
                    </template>
                </div>
            </div>
        </div>
    </div>
</div>

js部分

js 复制代码
 new Vue({
        el: '#app',
        data() {
            return {
                hasRightAngle: false,
                lineHeight: 25,
                row: 6,
                hasAcknowledgeAlarm: false,
                items: [
                    {
                        nodeList: [1, 2, 3, 4, 5, 6]
                    },
                    {
                        nodeList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
                    }, {
                        nodeList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
                    },
                    {
                        nodeList: [1, 2, 3, 4]
                    }
                ],
            }
        },
        provide() {
            return {
                splitArrayByLength: this.splitArrayByLength,
                styleRoundRow: this.styleRoundRow
            }
        },

        computed: {
            splitArrayByLength() {
                return function (array, length) {
                    let result = []
                    for (let i = 0; i < array.length; i += length) {
                        let chunk = array.slice(i, i + length)
                        // 反转偶数位置的子数组
                        if ((i / length) % 2 === 1) {
                            chunk = chunk.reverse()
                        }
                        result.push(chunk)
                    }
                    // console.log(result)
                    return result
                }
            },

            alignItem() {
                return function (index) {
                    return index % 2 !== 0 ? 'justify-end' : ''
                }
            },

            containerStyle() {
                if (this.hasAcknowledgeAlarm) {
                    return {
                        width: `calc(100% - 280px)`,
                        marginRight: '10px'
                    }
                } else {
                    return {
                        width: '100%',
                        marginRight: '0'
                    }
                }
            },

            styleRow() {
                return function (index) {
                    if (index > 0) {
                        return {
                            marginTop: !this.hasRightAngle ? `-${this.lineHeight}px` : 0
                        }
                    }
                }
            }
        },

        mounted() {
            this.handleResize()
            // 监听浏览器窗口
            window.addEventListener('resize', this.handleResize);
        },

        methods: {
            handleResize() {
                const bp = window.innerWidth >= 1600 ? 'xxl' :
                    window.innerWidth >= 1200 ? 'xl' :
                        window.innerWidth >= 992 ? 'lg' :
                            window.innerWidth >= 768 ? 'md' : 'sm'

                let emunRow = {
                    xxl: 4,
                    xl: 6,
                    lg: 8,
                    md: 12,
                    sm: 12
                }
                this.row = 24 / emunRow[bp]
                console.log('handleResize', bp)
            },
        }
    })

css部分

css 复制代码
<style lang="less">
    .container-bg {
      background: #f2f2f2;
    }

    .container {
      box-sizing: border-box;
      padding: 20px;
      width: 100%;
      background: linear-gradient(to right, #e8e8e8 1px, transparent 1px),
      linear-gradient(to bottom, #e8e8e8 1px, transparent 1px);
      background-repeat: repeat;
      background-size: 50px 50px;
      overflow-y: auto;
    }

    .container-list {
      display: flex;
      //background: #f2f2f2;
    }

    .lineBg {
      box-sizing: border-box;
      height: 25px;
      background: #bec8d1;
      width: 100%;
      border-top: 4px solid #ffffff;
      border-bottom: 4px solid #ffffff;
      cursor: pointer;
    }

    .boxGrey {
      max-width: 80%;
      position: relative;
      top: -5px;
      padding: 5px 15px;
      //background-color: rgba(40, 140, 115, 0.1);
      background-color: #768997;
      color: #ffffff;
      border-radius: 25px;

      &::before {
        content: "";
        position: absolute;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
        border-radius: 25px;
        border: 1px solid #768997;
        clip-path: polygon(calc(50% - 7px) 0, 50% 5px, calc(50% + 7px) 0, 100% 0, 100% 100%, 0 100%, 0 0);
      }

      &::after {
        content: "";
        position: absolute;
        /*top: -5px;*/
        bottom: -4px;
        left: calc(50% - 5px);
        width: 8px;
        height: 8px;
        /*transform: rotate(135deg);*/
        transform: rotate(315deg);
        //border: 1px solid #fc5454;
        background-color: #768997;
        clip-path: polygon(0 0, 0 100%, 100% 100%);
      }
    }

    .lineBorderLeft {
      border-left: 4px solid lawngreen;
    }

    .lineBorderRight {
      border-right: 4px solid rebeccapurple;
    }

    .line-title {
      display: flex;
      justify-content: space-around;
    }

    .row-title {
      align-self: flex-start;
      width: 80px;
      min-width: 80px;
      background: #ffffff;
      box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.16);
      text-align: center;
      margin-right: 25px;

    }

    .row-title-text {
      box-sizing: border-box;
      padding: 5px 0;
    }

    .row-title-num {
      background: #fc5454;
      color: #ffffff;
      box-sizing: border-box;
      padding: 3px 0;
    }

    .row {
      display: flex;
      flex-wrap: wrap;
      width: calc(100% - 260px);
      margin-bottom: 10px;
      position: relative;
    }

    .justify-end {
      justify-content: end;
    }

    .item {
      box-sizing: border-box;
      text-align: center;
      min-height: 63px;
      color: #333333;
      box-sizing: border-box;
      padding: 10px 0;
      margin: 5px 30px;
      box-shadow: 0px 0px 16px rgba(0, 0, 0, 0.08);
      cursor: pointer;
    }

    .value {
      margin-bottom: 8px;
    }

    .bgGrey {
      background: #f0f0f0;
    }

    .itemBorder {
      border: 1px solid #666666;
    }


    .setWidth {
      width: 50%
    }

    .linexxlRound {

      display: flex;
      justify-content: end;
      align-items: center;
      box-sizing: border-box;
      background: #bec8d1;
      //background: antiquewhite;
      width: 130px;
      height: 100%;
      border-radius: 200px 0 0 200px;
      border: 4px solid #ffffff;
      border-right: none;
    }

    .innelxx-inner {
      height: calc(100% - 34px);
      box-sizing: border-box;
      width: 105px;
      background: #f2f2f2;
      //background: green;
      border-radius: 200px 0 0 200px;
      border: 4px solid #ffffff;
      border-right: none;
    }

    .linexxrRound {
      box-sizing: border-box;
      background: #bec8d1;
      //background: antiquewhite;
      width: 130px;
      height: 100%;
      display: flex;
      justify-content: start;
      align-items: center;
      border-radius: 0 200px 200px 0;
      border: 4px solid #ffffff;
      border-left: none;

      .innerxx-inner {
        height: calc(100% - 34px);
        box-sizing: border-box;
        width: 105px;
        background: #F2F2F2;
        //background: green;
        border-radius: 0 200px 200px 0;
        border: 4px solid #ffffff;
        border-left: none;
      }
    }

    .linexxr {
      box-sizing: border-box;
      width: 25px;
      height: 100%;
      background: #bec8d1;
      border-top: 4px solid #ffffff;
      border-bottom: none;
      border-left: none;
      position: relative;

      &::after {
        content: "";
        position: absolute;
        top: 17px;
        left: 0;
        width: 4px;
        height: calc(100% - 17px);
        background: #ffffff;
      }

      &::before {
        content: "";
        position: absolute;
        left: 0px;
        bottom: -4px;
        width: 100%;
        height: 4px;
        background: #bec8d1;
        z-index: 1;
        //border-right: 4px solid #ffffff;
        box-sizing: border-box;
        border-left: 4px solid #ffffff;
      }
    }

    .linexxr-box {
      width: 25px;
      height: 25px;
      background: #bec8d1;
      //background: red;
      border: 4px solid #ffffff;
      border-left: none;
    }

    .linexxl {
      box-sizing: border-box;
      width: 25px;
      height: 100%;
      background: #bec8d1;
      border-top: 4px solid #ffffff;
      border-bottom: none;
      border-left: none;
      position: relative;

      &::after {
        content: "";
        position: absolute;
        top: 17px;
        right: 0;
        width: 4px;
        height: calc(100% - 17px);
        background: #ffffff;
      }

      &::before {
        content: "";
        position: absolute;
        right: 0;
        bottom: -4px;
        width: 100%;
        height: 4px;
        background: #bec8d1;
        z-index: 1;
        border-right: 4px solid #ffffff;
        box-sizing: border-box;
        //border-left: 4px solid #ffffff;
      }
    }

    .linexxl-box {
      width: 25px;
      height: 25px;
      box-sizing: border-box;
      background: #bec8d1;
      //background: red;
      border: 4px solid #ffffff;
      border-right: none;
    }

    .linexxRight {
      border-right: 4px solid #ffffff;
    }

    .linexxLeft {
      border-left: 4px solid #ffffff;
      border-bottom: none;
    }
  </style>
相关推荐
小旺仔爱代码14 分钟前
AJAX和JSON
前端·ajax·json
风清扬_jd44 分钟前
Chromium HTML5 新的 Input 类型search对应c++
前端·c++·html5
逸狼1 小时前
快速入门HTML
前端·css·html
海绵宝宝不喜欢侬1 小时前
vue + elementui 全局Loading效果
前端·vue.js·elementui
qq_544329172 小时前
从0学习React(10)
服务器·前端·javascript·react.js
AR7_2 小时前
App开发Flutter支持Harmony OS Next方案
前端
聪明的墨菲特i2 小时前
VUE组件学习 | 六、v-if, v-else-if, v-else组件
前端·vue.js·学习·前端框架·vue
Wonderful_Wan83 小时前
【前端项目工程】Uni-app 离线打包apk
前端·uni-app
木子七3 小时前
Js内建对象
前端·javascript
GDAL4 小时前
HTML入门教程2:HTML发展历史
前端·html