效果图
调用方式
< template>
< grid class = " grid-demo" isScale >
< grid-item class = " grid-demo-item" > 1</ bg-grid-item>
< grid-item class = " grid-demo-item" > 2</ bg-grid-item>
< grid-item class = " grid-demo-item" > 3</ bg-grid-item>
< grid-item class = " grid-demo-item" > 4</ bg-grid-item>
< grid-item class = " grid-demo-item" > 5</ bg-grid-item>
< grid-item class = " grid-demo-item" > 6</ bg-grid-item>
< grid-item class = " grid-demo-item" > 7</ bg-grid-item>
< grid-item class = " grid-demo-item" > 8</ bg-grid-item>
< grid-item class = " grid-demo-item" > 9</ bg-grid-item>
</ grid>
< template>
< style scoped >
.grid-demo {
background-color : #2b2d42;
}
.grid-demo-item {
color : #fff;
background-color : #41497D;
}
</ style>
grid-item组件代码
< script setup>
import { ref, inject, watch} from 'vue'
defineOptions ( {
name : 'GridItem'
} )
const isScale = inject ( "isScale" ) ;
const liDom = ref ( ) ;
const height = ref ( "" ) ;
watch ( ( ) => liDom. value, ( dom ) => {
if ( isScale) {
height. value = dom. clientWidth + "px" ;
} else {
height. value = "" ;
}
} , {
deep : true ,
} ) ;
< / script>
< template>
< li class = "grid-layout-item" ref= "liDom" >
< slot / >
< / li>
< / template>
< style scoped lang= "scss" >
. grid- layout- item {
float : left;
list- style: none;
height : v- bind ( height) ;
line- height: v- bind ( height) ;
text- align: center;
vertical- align: middle;
margin- bottom: 10px;
}
< / style>
grid组件代码
< script setup>
import { useSlots, provide, ref, computed, watch, onMounted} from "vue" ;
defineOptions ( {
name : "Grid"
} )
const props = defineProps ( {
gutter : { type : Number, default : 10 } ,
column : { type : Number, default : 3 } ,
isScale : { type : Boolean, default : false } ,
} )
provide ( 'isScale' , props. isScale)
const slotList = useSlots ( ) ?. default ( ) || [ ]
const renderList = ref ( [ ] )
const columnNum = ref ( props. column || 1 )
const lastRow = ref ( 0 ) ;
const gridStyles = computed ( ( ) => {
return {
overflow : "hidden" ,
padding : ` ${ props. gutter} px ` ,
margin : "0px"
}
} )
function _SlotListHandler ( el, index ) {
if ( typeof el. type === "object" && el. type. name === "GridItem" ) {
if ( ! el. props) el. props = { } ;
if ( ! el. props. style) el. props. style = { } ;
el. props. style. width = ` calc((100% - ${ props. gutter * ( columnNum. value - 1 ) } px) / ${ columnNum. value} ) ` ;
el. props. style. marginRight = ` ${ props. gutter} px ` ;
el. props. style. marginBottom = ` ${ props. gutter} px ` ;
if ( ( index + 1 ) % columnNum. value === 0 ) el. props. style. marginRight = "0px" ;
if ( ( index + 1 ) >= lastRow. value * columnNum. value) {
el. props. style. marginBottom = 0 ;
} else {
el. props. style. marginBottom = ` ${ props. gutter} px `
}
return el;
} else if ( typeof el. type === 'symbol' ) {
let _list = [ ] ;
el. children. forEach ( ( childrenEl, childrenIndex ) => {
_list. push ( _SlotListHandler ( childrenEl, childrenIndex) ) ;
} )
return _list;
}
return false ;
}
function renderSlot ( list ) {
renderList. value = [ ] ;
lastRow. value = Math. ceil ( ( list[ 0 ] ?. children|| [ ] ) . length / columnNum. value) - 1 ;
list. forEach ( ( el, index ) => {
let _e = _SlotListHandler ( el, index) ;
if ( _e instanceof Array ) {
renderList. value. push ( ... _e) ;
} else if ( typeof _e === 'object' ) {
renderList. value. push ( _e) ;
}
} ) ;
}
watch (
( ) => slotList,
( list ) => {
console. log ( 'list:' , list)
renderSlot ( list) ;
} ,
{ deep : true }
)
onMounted ( ( ) => {
renderSlot ( slotList) ;
} )
< / script>
< template>
< div class = "grid-layout" >
< ul : style= "gridStyles" >
< component v- for = "(element, key) in renderList" : key= "key"
: is= "element" / >
< / ul>
< / div>
< / template>
< style scoped lang= "scss" >
. grid- layout {
list- style: none;
}
< / style>