Commit ffdc7cce authored by 郭铭瑶's avatar 郭铭瑶 🤘

动态化布局

parent 3e987c02
<template> <template>
<div class="card-wrapper"> <div class="card-wrapper">
<div class="card-title"> <div class="card-title">
<span class="dot" />
<p> <p>
{{ title }} {{ title }}
</p> </p>
</div> </div>
<div class="card-content"> <div class="card-content">
<span class="border" />
<span class="border" />
<slot /> <slot />
</div> </div>
</div> </div>
...@@ -30,33 +29,31 @@ export default defineComponent({ ...@@ -30,33 +29,31 @@ export default defineComponent({
<style scoped lang="stylus"> <style scoped lang="stylus">
@import '../main.styl' @import '../main.styl'
.card-wrapper .card-wrapper
background rgba(29,42,65,.9)
.card-title .card-title
display flex display flex
background url('@/assets/images/card-mode1-header.png') left bottom / 100% 60% no-repeat align-items center
padding 0 .1rem
background linear-gradient(to right, rgba(59,85,102,.8) 70%, transparent)
position relative
border-bottom .01rem solid #717F8C
>p >p
color $card-title-color font-size .12rem
font-size $card-title-size
font-weight bold font-weight bold
background url('@/assets/images/card-mode1-title.png') left bottom / 100% 60% no-repeat .dot
padding 0 .2rem display inline-block
margin 0 width .02rem
height .2rem
background #fadb71
position absolute
top 0
bottom 0
left 0
margin auto
.card-content .card-content
position relative position relative
box-sizing border-box box-sizing border-box
background $card-bg
padding .05rem padding .05rem
border-bottom $card-border
>.border
display block
position absolute
top 0
left 0
bottom 0
width .01rem
background linear-gradient(to bottom, rgba(148,236,255, 0), rgba(91,214,255,.5))
&:nth-of-type(2)
left auto
right 0
>div >div
$full() $full()
</style> </style>
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, onMounted, PropType, ref } from 'vue' import { computed, defineComponent, nextTick, PropType, ref, watch } from 'vue'
export default defineComponent({ export default defineComponent({
name: 'MyGrid', name: 'MyGrid',
...@@ -34,7 +34,18 @@ export default defineComponent({ ...@@ -34,7 +34,18 @@ export default defineComponent({
}, },
setup(props) { setup(props) {
const gridRef = ref<HTMLElement | null>(null) const gridRef = ref<HTMLElement | null>(null)
onMounted(() => { watch(
[() => props.template, () => props.columns, () => props.rows],
async ([val]) => {
console.log(val)
if (val && val.length > 0) {
await nextTick()
setChildrenArea()
}
},
{ immediate: true },
)
function setChildrenArea() {
if (!gridRef.value) return if (!gridRef.value) return
const { children } = gridRef.value as HTMLElement const { children } = gridRef.value as HTMLElement
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
...@@ -44,7 +55,7 @@ export default defineComponent({ ...@@ -44,7 +55,7 @@ export default defineComponent({
child.style.gridArea = area child.style.gridArea = area
} }
} }
}) }
const style = computed(() => { const style = computed(() => {
const { template, columns, rows, gap } = props const { template, columns, rows, gap } = props
if (!template || template.length === 0) return if (!template || template.length === 0) return
...@@ -72,8 +83,8 @@ export default defineComponent({ ...@@ -72,8 +83,8 @@ export default defineComponent({
<style scoped lang="stylus"> <style scoped lang="stylus">
@import '../main.styl' @import '../main.styl'
.my-grid .my-grid
$full()
position relative position relative
display grid display grid
overflow hidden overflow hidden
flex 1
</style> </style>
...@@ -130,8 +130,9 @@ export default defineComponent({ ...@@ -130,8 +130,9 @@ export default defineComponent({
align-items center align-items center
justify-content space-between justify-content space-between
padding 0 .1rem padding 0 .1rem
background linear-gradient(to right, rgba(59,85,102,.8), transparent) background linear-gradient(to right, rgba(59,85,102,.8) 70%, rgba(0,0,0,0.2))
position relative position relative
border-bottom .01rem solid #717F8C
>p >p
font-size .12rem font-size .12rem
font-weight bold font-weight bold
......
...@@ -58,6 +58,7 @@ export default defineComponent({ ...@@ -58,6 +58,7 @@ export default defineComponent({
position relative position relative
background-size cover background-size cover
background-position center background-position center
height .4rem
.date .date
z-index 2 z-index 2
position absolute position absolute
......
export default function useLayout(key: string) {
switch (key) {
case '2-6-1':
return {
template: ['box1 . box4', 'box2 . box5', 'box3 . box6'],
rows: '1fr 1fr 1fr',
boxNum: 6,
}
case '2-5-1':
return {
template: ['box1 . box3', 'box2 . box4', 'box2 . box5'],
rows: '1fr 1fr 1fr',
boxNum: 5,
}
case '2-5-2':
return {
template: ['box1 . box3', 'box1 . box4', 'box2 . box5'],
rows: '1fr 1fr 1fr',
boxNum: 5,
}
case '2-5-3':
return {
template: ['box1 . box4', 'box2 . box4', 'box3 . box5'],
rows: '1fr 1fr 1fr',
boxNum: 5,
}
case '2-5-4':
return {
template: ['box1 . box4', 'box2 . box5', 'box3 . box5'],
rows: '1fr 1fr 1fr',
boxNum: 5,
}
case '2-4-1':
return {
template: ['box1 . box3', 'box2 . box4', 'box2 . box4'],
rows: '1fr 1fr 1fr',
boxNum: 4,
}
case '2-4-2':
return {
template: ['box1 . box3', 'box1 . box3', 'box2 . box4'],
rows: '1fr 1fr 1fr',
boxNum: 4,
}
default:
return {
template: [],
rows: '',
boxNum: 0,
}
}
}
<template>
<m-modal
v-model="visible"
title="添加组件"
width="30vw"
height="80vh"
:mask-closable="false"
>
<div class="container">
<div class="tabs">
<div
v-for="tab in tabs"
:key="tab.key"
class="tab"
:class="{ on: curTab === tab.key }"
@click="curTab = tab.key"
>
{{ tab.name }}
</div>
</div>
<div class="list">
<template
v-if="componentList[curTab] && componentList[curTab].length > 0"
>
<div v-for="(component, i) in componentList[curTab]" :key="i">
<component :is="component" />
</div>
</template>
<m-empty v-else text="暂无组件" />
</div>
</div>
</m-modal>
</template>
<script lang="ts" setup>
import { PropType, ref, watch } from 'vue'
import Property from './property.vue'
const props = defineProps({
modelValue: {
type: Boolean as PropType<boolean>,
default: false,
},
})
const emit = defineEmits(['update:modelValue', 'select'])
const visible = ref(false)
watch(
() => props.modelValue,
(val) => (visible.value = val),
)
watch(
() => visible.value,
(val) => {
emit('update:modelValue', val)
},
)
const curTab = ref('1')
const tabs = [
{ name: '物业', key: '1' },
{ name: '市场', key: '2' },
{ name: '修缮', key: '3' },
{ name: '保障', key: '4' },
]
const componentList = {
'1': [Property],
}
</script>
<style lang="stylus" scoped>
.container
height 100%
display flex
flex-direction column
.list
flex 1
overflow-x hidden
overflow-y auto
margin-top .1rem
.tabs
display flex
background rgba(70,83,97,.5)
border-radius .04rem
width 100%
justify-content space-around
box-shadow 0 0.01rem 0.01rem 0 rgba(255,255,255,.2) inset
.tab
padding .04rem .2rem
cursor pointer
color gray
border-top .01rem solid transparent
font-size .09rem
&:hover
font-weight bold
color #fff
font-size .1rem
&.on
font-weight bold
color #fff
font-size .1rem
background linear-gradient(to bottom, rgba(50,197,255,.5), transparent)
border-top .01rem solid rgba(50,197,255,.8)
</style>
<template>
<m-modal
v-model="visible"
title="布局设定"
width="98vw"
height="93vh"
offset-y=".2rem"
bg-color="rgba(0,0,0,0.5)"
:mask-closable="false"
@close="onClose"
>
<div class="container">
<div v-for="item in layoutOptions" :key="item.title" class="row">
<div
v-for="img in item.list"
:key="img.key"
class="img"
:class="{ on: curKey === img.key }"
@click="onSelect(img.key)"
>
<img :src="img.src" />
</div>
<div class="title">
<p>{{ item.title }}</p>
</div>
</div>
</div>
</m-modal>
</template>
<script lang="ts" setup>
import { PropType, ref, watch } from 'vue'
import img1 from '@/assets/images/2-6-1.png'
import img2 from '@/assets/images/2-5-1.png'
import img3 from '@/assets/images/2-5-2.png'
import img4 from '@/assets/images/2-5-3.png'
import img5 from '@/assets/images/2-5-4.png'
import img6 from '@/assets/images/2-4-1.png'
import img7 from '@/assets/images/2-4-2.png'
const props = defineProps({
modelValue: {
type: Boolean as PropType<boolean>,
default: false,
},
})
const emit = defineEmits(['update:modelValue', 'select'])
const visible = ref(false)
watch(
() => props.modelValue,
(val) => (visible.value = val),
)
watch(
() => visible.value,
(val) => {
emit('update:modelValue', val)
},
)
const layoutOptions = [
{ title: '两列六块', list: [{ src: img1, key: '2-6-1' }] },
{
title: '两列五块',
list: [
{ src: img2, key: '2-5-1' },
{ src: img3, key: '2-5-2' },
{ src: img4, key: '2-5-3' },
{ src: img5, key: '2-5-4' },
],
},
{
title: '两列四块',
list: [
{ src: img6, key: '2-4-1' },
{ src: img7, key: '2-4-2' },
],
},
]
const curKey = ref<string | null>(null)
const onSelect = (key) => {
curKey.value = key
}
const onClose = () => {
emit('select', curKey.value)
}
</script>
<style lang="stylus" scoped>
.container
height 100%
display flex
flex-direction column
justify-content space-between
.row
.title
width 23%
text-align center
p
display inline-block
background rgba(70,83,97,.3)
color #B2DAEA
padding .03rem .12rem
box-shadow 0 0 0.06rem .01rem rgba(255,255,255,.1) inset
font-weight bold
.img
display inline-block
width 23%
margin-right 2%
cursor pointer
border-radius .04rem
position relative
>img
width 100%
height 100%
&:hover
box-shadow 0 0 .1rem .01rem rgba(255,255,255,.3)
&.on
&:before
position absolute
top .08rem
right .08rem
content ''
display inline-block
background url('/src/assets/images/checked.png') center/100% 100% no-repeat
width .12rem
height @width
</style>
<template>
<m-card title="物业"> 123 </m-card>
</template>
<script lang="ts" setup></script>
<style lang="stylus" scoped></style>
<template> <template>
<div class="main">
<m-title area="title" @touch="showLayoutModal = true">静安智慧房管</m-title>
<m-grid <m-grid
:template="[ v-if="layout.boxNum > 0"
'title title title', :template="layout.template"
'box1 . box3',
'box1 . box3',
'box2 . box3',
'box2 box4 box4',
]"
columns="1fr 1.5fr 1fr" columns="1fr 1.5fr 1fr"
rows="0.4rem 1fr 0.5fr 0.5fr 1fr" :rows="`${layout.rows}`"
> >
<m-title area="title" @touch="showFilterModal = true">静安智慧房管</m-title> <div
<m-modal v-for="(_, index) in new Array(layout.boxNum)"
v-model="showFilterModal" :key="index"
title="布局设定" class="box"
width="98vw" :area="`box${index + 1}`"
height="92vh"
offset-y=".2rem"
bg-color="rgba(0,0,0,0.5)"
> >
123 <component :is="componentList[index]" v-if="componentList[index]" />
</m-modal> <img
v-else
class="add-btn"
src="@/assets/images/add.png"
@click.prevent.stop="onClick(index)"
/>
</div>
</m-grid> </m-grid>
</div>
<LayoutModal v-model="showLayoutModal" @select="onChangeLayout" />
<ComponentModal v-model="showComponentModal" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue' import { ref } from 'vue'
const showFilterModal = ref(false) import LayoutModal from './components/layout-modal.vue'
import ComponentModal from './components/component-modal.vue'
import useLayout from '@/hooks/useLayout'
const showLayoutModal = ref(false)
const layout = ref<{ template: string[]; rows: string; boxNum: number }>({
template: [],
rows: '',
boxNum: 0,
})
const onChangeLayout = (key: string) => {
layout.value = useLayout(key)
}
const componentList = []
const showComponentModal = ref(false)
const onClick = (i: number) => {
showComponentModal.value = true
}
</script> </script>
<style lang="stylus"></style> <style lang="stylus" scoped>
@import '../components/MyComponent/main.styl'
.main
width 100%
height 100%
display flex
flex-direction column
.box
border-radius .02rem
border .01rem dashed #4270B3
background rgba(54,65,77,.5)
$blur(.01rem)
position relative
>.add-btn
width .2rem
height @width
position absolute
top 50%
left 50%
transform translate(-50%,-50%)
opacity .8
cursor pointer
transition all .2s ease-in-out
&:hover
opacity 1
width .24rem
height @width
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment