flexbox/src/App.vue

625 lines
19 KiB
Vue
Raw Normal View History

2022-11-03 04:58:16 +08:00
<script setup lang="ts">
import {ref, watch, onMounted, reactive} from "vue";
/** 子项默认宽度 */
2022-11-03 05:42:03 +08:00
const itemWidth = ref(10);
2022-11-03 04:58:16 +08:00
/** 父Flex属性Flex容器 默认值 */
const flexContainerForm: { [key: string]: any } = reactive({
"flex-direction": "row",
"flex-wrap": "nowrap",
"justify-content": "flex-start",
"align-items": "stretch",
"align-content": "stretch",
});
/** 选项值,默认值 */
const flexContainerList = {
"flex-direction": {
title: "flex-direction",
2022-11-03 07:48:19 +08:00
titleTooltip: "排列方向",
2022-11-03 04:58:16 +08:00
list: ["row", "row-reverse", "column", "column-reverse"],
2022-11-03 07:48:19 +08:00
tooltip: ["主轴为水平方向,起点在左端", "row反方向", "主轴为垂直方向,起点在上沿", "column反方向"],
modelValue: "row"
2022-11-03 04:58:16 +08:00
},
"flex-wrap": {
title: "flex-wrap",
2022-11-03 07:48:19 +08:00
titleTooltip: "排不下,换行",
2022-11-03 04:58:16 +08:00
list: ["nowrap", "wrap", "wrap-reverse"],
2022-11-03 07:48:19 +08:00
tooltip: ["不换行", "换行,第一行在上方", "换行,第一行在下方"],
2022-11-03 04:58:16 +08:00
modelValue: "nowrap",
},
"justify-content": {
title: "justify-content",
2022-11-03 07:48:19 +08:00
titleTooltip: "主轴上的对齐方式",
2022-11-03 04:58:16 +08:00
list: ["flex-start", "flex-end", "center", "space-between", "space-around"],
2022-11-03 07:48:19 +08:00
tooltip: ["左对齐", "右对齐", "居中", "两端对齐,项目之间的间隔都相等", "每个项目两侧的间隔相等"],
2022-11-03 04:58:16 +08:00
modelValue: "flex-start",
},
"align-items": {
title: "align-items",
2022-11-03 07:48:19 +08:00
titleTooltip: "交叉轴上如何对齐",
2022-11-03 04:58:16 +08:00
list: ["stretch", "flex-start", "flex-end", "center", "baseline"],
2022-11-03 07:48:19 +08:00
tooltip: ["项目未设置高度或设为auto将占满整个容器的高度", "交叉轴的起点对齐", "交叉轴的终点对齐", "交叉轴的中点对齐", "目的第一行文字的基线对齐"],
2022-11-03 04:58:16 +08:00
modelValue: "stretch",
},
"align-content": {
title: "align-content",
2022-11-03 07:48:19 +08:00
titleTooltip: "多根轴线的对齐方式",
2022-11-03 04:58:16 +08:00
list: [
"stretch",
"flex-start",
"flex-end",
"center",
"space-between",
"space-around",
],
2022-11-03 07:48:19 +08:00
tooltip: ["轴线占满整个交叉轴", "与交叉轴的起点对齐", "与交叉轴的终点对齐", "与交叉轴的中点对齐", "与交叉轴两端对齐,轴线之间的间隔平均分布", "每根轴线两侧的间隔都相等"],
2022-11-03 04:58:16 +08:00
modelValue: "stretch",
},
};
/** 子项初始个数 */
const itemCount = 5;
/** 当前子项总数 */
let itemListCount = ref(itemCount);
/** 子项-单项默认值 */
const itemFormDefaultValue: { [key: string]: number | string } = {
order: 0,
"flex-grow": 0,
"flex-shrink": 1,
"flex-basis": "auto",
"align-self": "auto",
};
/** align-self 选项 */
const itemAlignSelf = [
"auto",
"stretch",
"center",
"flex-start",
"flex-end",
"baseline",
];
2022-11-03 07:48:19 +08:00
const itemAlignSelfTooltip = [
"为父元素的align-items值没有父容器则为stretch",
"适合容器",
"容器的中央",
"容器的开头",
"容器的末端",
"容器的基线",
];
2022-11-03 04:58:16 +08:00
/** 子项列表 JSON 数据 */
let flexItemForm: {
[key: string]: any;
} = reactive({});
/** 增加子项 */
const addItem = () => {
itemListCount.value++;
flexItemForm[`item-` + itemListCount.value] = JSON.parse(
JSON.stringify(itemFormDefaultValue)
);
};
/** 减少子项 */
const removeItem = (key: string | number) => {
delete flexItemForm[key];
delete flexItemFormStyle[key];
};
/** 横杆后的字母变大写 */
const toUp = (str: string) => {
let newStr = "";
let arr = str.split("-"); //先用字符串分割成数组
arr.forEach((item, index) => {
if (index > 0) {
return (newStr += item.replace(item[0], item[0].toUpperCase()));
} else {
return (newStr += item);
}
});
return newStr;
};
/** flexBox style */
let flexContainerFormStyle: { [key: string]: any } = reactive({});
const flexContainerFormStyleFun = () => {
Object.keys(flexContainerForm).forEach((key) => {
flexContainerFormStyle["display"] = "flex";
2022-11-06 13:07:36 +08:00
flexContainerFormStyle["height"] = "100%";
2022-11-03 06:05:39 +08:00
flexContainerFormStyle["minHeight"] = "160px";
flexContainerFormStyle["padding"] = "10px";
flexContainerFormStyle["backgroundColor"] = "goldenrod";
2022-11-03 04:58:16 +08:00
flexContainerFormStyle[toUp(key)] = flexContainerForm[key];
});
};
/** flexContainerForm 父属性 默认值监听*/
watch(flexContainerForm, () => {
// flexContainerFormStyle = {};
flexContainerFormStyleFun();
});
/** 子项 style 生成 */
let flexItemFormStyle: { [key: string]: any } = reactive({});
const flexItemFormStyleFun = () => {
Object.keys(flexItemForm).forEach((ikey) => {
let valueObj: any = {};
let flexItemFormIkey = flexItemForm[ikey];
Object.keys(flexItemFormIkey).forEach((_ikeys) => {
// valueObj['backgroundColor'] = 'cornsilk';
valueObj["width"] = itemWidth.value + "%";
// valueObj['minHeight'] = '80px';
// valueObj['display'] = 'inline-block';
valueObj[toUp(_ikeys)] = flexItemFormIkey[_ikeys];
});
flexItemFormStyle[ikey] = valueObj;
});
};
/** 监听子项 和 宽度样式变化 */
watch([flexItemForm, itemWidth], () => {
// flexItemFormStyle = {};
flexItemFormStyleFun();
});
/** 初始 子项 默认值 */
const initialFlexItemForm = () => {
for (let index = 0; index < itemCount; index++) {
flexItemForm[`item-` + index] = JSON.parse(
JSON.stringify(itemFormDefaultValue)
);
}
}
/**
* 准备html和css 打印准备
*/
/** 盒子dom */
let fiexBoxDom: any = ref(null);
/** 要输出的html */
let fiexBoxDomHtml: any = ref(``);
/** 外层 CSS */
let fiexBoxCssString: any = ref(``);
/** 子项 CSS */
let fiexItemCssString: any = ref(``);
/** 生成HTML方法 */
const fiexSubmitHtml = () => {
let html = `<div class="flexbox">`;
// 获取所有子项
Object.keys(flexItemForm).forEach((ikey, index) => {
2022-11-03 05:52:41 +08:00
const itemClass = "item-" + (index + 1);
html += `<div class="flex-item ${itemClass}">${itemClass}</div>`;
2022-11-03 04:58:16 +08:00
});
html += `</div>`;
fiexBoxDomHtml.value = html;
};
/** 生成CSS方法{} */
const fiexSubmitCss = () => {
/** 增加CSS外层{} */
const addKuohao = (css: string) => {
2022-11-06 13:07:36 +08:00
return `{` + '\n' + css + '\n' + `}`;
2022-11-03 04:58:16 +08:00
};
2022-11-06 13:07:36 +08:00
2022-11-03 04:58:16 +08:00
const flexboxitemDom = fiexBoxDom.value.querySelectorAll(".flexboxitem");
let css: string = ".flex-item{display: inline-block; min-height: 80px; background-color: cornsilk; margin: 5px; overflow: hidden;}";
flexboxitemDom.forEach((dom: any, index: string) => {
css += `.item-` + (index + 1) + addKuohao(dom.style.cssText);
});
fiexBoxCssString.value = `.flexbox{` + fiexBoxDom.value.style.cssText + `}`;
fiexItemCssString.value = css;
};
/** 获取打印html和css */
const fiexSubmit = () => {
fiexSubmitHtml();
fiexSubmitCss();
};
2022-11-03 08:52:57 +08:00
watch([flexContainerFormStyle, flexItemFormStyle], () => {
fiexSubmitHtml();
fiexSubmitCss();
})
2022-11-03 04:58:16 +08:00
/** 初始页面加载后只执行一次 */
onMounted(() => {
initialFlexItemForm();
flexContainerFormStyleFun();
flexItemFormStyleFun();
});
/**
* 底部
*/
const showTime: any = ref('');
const showTimeYear: any = ref(0);
const checkTime = function (i: any) {
if (i < 10) {
i = "0" + i;
}
return i;
};
const showTimeFun = function () {
const nowdate = new Date();
let year = nowdate.getFullYear(),
month = nowdate.getMonth() + 1,
date = nowdate.getDate(),
day = nowdate.getDay(),
week = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
h: string | number = nowdate.getHours(),
m: string | number = nowdate.getMinutes(),
s: string | number = nowdate.getSeconds();
h = checkTime(h);
m = checkTime(m);
s = checkTime(s);
// 年
showTimeYear.value = year.toString();
// 日期时间
showTime.value = year + "年" + month + "月" + date + "日" + week[day] + " " + h + ":" + m + ":" + s;
};
showTimeFun();
setInterval(() => {
showTimeFun();
}, 1000); //反复执行函数
</script>
<template>
2022-11-06 13:07:36 +08:00
<a-layout class="layout">
<a-layout-header>
<a-typography-title bold>CSS3 Flexbox 在线演示</a-typography-title>
</a-layout-header>
<a-layout-content>
<a-row class="layout-content-box" justify="justify-content" :wrap="false" :gutter="15"
:style="{ alignItems: 'stretch',flexGrow:1}">
<a-col :md="12" :span="24">
<div class="mainContent">
<a-typography-title :heading="4" bold>子项宽度</a-typography-title>
<a-space fill size="medium" class="itemWidth">
<a-typography-text>宽度</a-typography-text>
<a-input-number
:style="{ width: '80px' }"
:min="10"
:max="100"
v-model="itemWidth">
<template #suffix>%</template>
</a-input-number>
2022-11-03 04:58:16 +08:00
<a-slider
v-model="itemWidth"
2022-11-03 05:42:03 +08:00
:min="10"
2022-11-03 04:58:16 +08:00
:max="100"
:step="1"
2022-11-06 13:07:36 +08:00
show-ticks
2022-11-03 04:58:16 +08:00
/>
2022-11-06 13:07:36 +08:00
</a-space>
<a-typography-title :heading="4" bold>父Flex属性Flex容器</a-typography-title>
<a-row justify="justify-content" :wrap="false">
<a-col
class="containerCol"
v-for="(item, key) in flexContainerList"
:key="key"
>
<a-typography-title :heading="6" bold>
<a-tooltip
:content="item.titleTooltip"
background-color="goldenrod"
mini>
<strong>{{ item.title }}</strong>
</a-tooltip>
</a-typography-title>
<a-radio-group
direction="vertical"
v-model="flexContainerForm[key]"
2022-11-03 04:58:16 +08:00
>
2022-11-06 13:07:36 +08:00
<a-tooltip
v-for="(value, keys) in item.list"
:key="keys"
:content="item.tooltip[keys]"
background-color="#00bd7e"
mini
>
<a-radio :value="value">
{{ value }}
</a-radio>
</a-tooltip>
</a-radio-group>
</a-col>
</a-row>
<a-button
@click="fiexSubmit"
:style="{margin:'1em 0'}"
type="primary"
status="success" long>
生成
</a-button>
<div class="mainContentBox">
<a-split :style="{
height: '100%',
width: '100%',
backgroundColor:'var(--color-neutral-2)',
maxHeight:'358px'
}">
<template #first>
<a-split direction="vertical" :style="{height: '99.9%'}">
<template #first>
<a-typography-paragraph copyable>
<highlightjs language="html" :autodetect="false" :code="fiexBoxDomHtml"></highlightjs>
</a-typography-paragraph>
</template>
<template #second>
<a-typography-paragraph copyable>
<highlightjs language="css" :autodetect="false" :code="fiexBoxCssString"></highlightjs>
</a-typography-paragraph>
</template>
</a-split>
</template>
<template #second>
<a-typography-paragraph copyable>
<highlightjs language="css" :autodetect="false" :code="fiexItemCssString"></highlightjs>
</a-typography-paragraph>
</template>
</a-split>
2022-11-03 04:58:16 +08:00
</div>
2022-11-06 13:07:36 +08:00
</div>
</a-col>
<a-col :md="12" :span="24">
<div class="mainContent">
<a-typography-title :heading="4" bold>
2022-11-03 04:58:16 +08:00
实现效果
<a-button
type="primary"
@click="addItem"
:style="{ float: 'right' }"
>
<template #icon>
<icon-plus/>
</template>
新增子项
</a-button>
2022-11-06 13:07:36 +08:00
</a-typography-title>
<div class="mainContentBox">
2022-11-03 04:58:16 +08:00
<div
class="flexbox"
:style="flexContainerFormStyle"
ref="fiexBoxDom"
>
<div
class="flexboxitem"
v-for="(_, indexKey, index) in flexItemForm"
:key="index"
:style="flexItemFormStyle[indexKey]"
>
2022-11-03 08:06:12 +08:00
<a-card :title="(index + 1).toString()"
:bordered="false"
:header-style="{backgroundColor:'azure',fontWeight:'bold'}">
2022-11-03 04:58:16 +08:00
<template #extra>
<a-button
type="text"
shape="circle"
@click="removeItem(indexKey)"
>
<icon-close/>
</a-button>
</template>
<a-list>
<a-list-item>
2022-11-06 13:07:36 +08:00
<a-tooltip content="order排列顺序数值越小排列越靠前" mini>
2022-11-03 04:58:16 +08:00
<a-input-number
v-model="flexItemForm[indexKey].order"
:min="0"
model-event="input"
/>
</a-tooltip>
</a-list-item>
<a-list-item>
2022-11-06 13:07:36 +08:00
<a-tooltip content="flex-grow项目的放大比例" mini>
2022-11-03 04:58:16 +08:00
<a-input-number
v-model="flexItemForm[indexKey]['flex-grow']"
:min="0"
model-event="input"
/>
</a-tooltip>
</a-list-item>
<a-list-item>
2022-11-06 13:07:36 +08:00
<a-tooltip content="flex-shrink项目的缩小比例" mini>
2022-11-03 04:58:16 +08:00
<a-input-number
v-model="flexItemForm[indexKey]['flex-shrink']"
:min="1"
:max="100"
model-event="input"
/>
</a-tooltip>
</a-list-item>
<a-list-item>
2022-11-03 07:48:19 +08:00
<a-tooltip
content="flex-basis计算主轴是否有多余空间设为跟width或height属性一样的值将占据固定空间"
2022-11-06 13:07:36 +08:00
mini>
2022-11-03 04:58:16 +08:00
<a-input
v-model="flexItemForm[indexKey]['flex-basis']"
allow-clear
/>
</a-tooltip>
</a-list-item>
<a-list-item>
2022-11-03 07:48:19 +08:00
<a-tooltip content="align-self单个项目有与其他项目不一样的对齐方式覆盖align-items属性"
2022-11-06 13:07:36 +08:00
mini>
2022-11-03 04:58:16 +08:00
<a-select
v-model="flexItemForm[indexKey]['align-self']"
>
2022-11-03 07:48:19 +08:00
<a-tooltip
v-for="(ivalue,ikeys) in itemAlignSelf"
2022-11-03 04:58:16 +08:00
:key="ikeys"
2022-11-03 07:48:19 +08:00
:content="itemAlignSelfTooltip[ikeys]"
2022-11-06 13:07:36 +08:00
mini
2022-11-03 07:48:19 +08:00
background-color="#00bd7e">
<a-option>
{{ ivalue }}
</a-option>
</a-tooltip>
2022-11-03 04:58:16 +08:00
</a-select>
</a-tooltip>
</a-list-item>
</a-list>
</a-card>
</div>
</div>
</div>
2022-11-06 13:07:36 +08:00
</div>
</a-col>
</a-row>
</a-layout-content>
<a-layout-footer ref="showTimeDom">
<a-divider :margin="10" :size="2">
<icon-heart/>
</a-divider>
<a-row class="footer" :gutter="24">
<a-col :span="12">
<a-typography-text type="success">{{ showTime }}</a-typography-text>
</a-col>
<a-col :span="12">
<a-typography-text type="success">
Copyright © 2015-{{ showTimeYear }}
<a-link target="_blank" href="https://beian.miit.gov.cn/" status="success" rel="noopener">鲁ICP备10001546号
</a-link>
</a-typography-text>
</a-col>
</a-row>
</a-layout-footer>
</a-layout>
2022-11-03 04:58:16 +08:00
</template>
2022-11-06 13:07:36 +08:00
<style lang="less" scoped>
.arco-layout {
height: 100vh;
.arco-layout-header,
.arco-layout-footer,
.arco-layout-content {
display: flex;
/*垂直排列*/
flex-direction: column;
justify-content: center;
font-stretch: condensed;
text-align: center;
padding: 15px;
}
2022-11-03 04:58:16 +08:00
2022-11-06 13:07:36 +08:00
.arco-layout-header,
.arco-layout-footer {
height: 64px;
background-color: #00bd7e;
}
2022-11-03 04:58:16 +08:00
2022-11-06 13:07:36 +08:00
//头部
:deep(.arco-layout-header) {
.arco-typography {
margin: 0;
}
}
2022-11-03 04:58:16 +08:00
2022-11-06 13:07:36 +08:00
//底部
.arco-layout-footer {
background-color: transparent;
2022-11-03 04:58:16 +08:00
2022-11-06 13:07:36 +08:00
.arco-link {
font-size: initial;
}
}
2022-11-03 04:58:16 +08:00
}
2022-11-06 13:07:36 +08:00
//内容
.arco-layout :deep(.arco-layout-content) {
text-align: left;
height: calc(100vh - 64px - 64px);
padding-top: 0;
2022-11-03 04:58:16 +08:00
2022-11-06 13:07:36 +08:00
.layout-content-box {
.itemWidth .arco-space-item:last-child {
flex-grow: 1;
2022-11-03 04:58:16 +08:00
2022-11-06 13:07:36 +08:00
.arco-slider-ticks .arco-slider-tick {
margin-top: 5px;
}
}
2022-11-03 04:58:16 +08:00
2022-11-06 13:07:36 +08:00
.containerCol {
flex: 1 0 20%;
width: 20%;
flex-basis: 0;
}
2022-11-03 04:58:16 +08:00
2022-11-06 13:07:36 +08:00
.mainContent {
display: flex;
flex-direction: column;
height: 100%;
.mainContentBox {
flex-grow: 1;
pre {
white-space: normal;
code {
background: #23241f;
color: #f8f8f2;
//padding: 10px;
border: none;
}
}
.flexbox {
min-height: 300px;
.flexboxitem {
//min-height: 80px;
background-color: cornsilk;
display: inline-block;
margin: 5px;
overflow: hidden;
.arco-card {
background: transparent;
.arco-card-body {
padding: 5px;
.arco-list-wrapper,
.arco-list-medium .arco-list-content-wrapper .arco-list-content > .arco-list-item {
padding: 0;
}
.arco-list-bordered {
border: none;
.arco-input-wrapper,
.arco-select-view-single {
background-color: transparent;
}
}
}
}
}
}
}
}
}
2022-11-03 04:58:16 +08:00
}
2022-11-06 13:07:36 +08:00
@media (max-width: 768px) {
.arco-layout :deep(.arco-layout-content) {
height: auto;
2022-11-03 04:58:16 +08:00
2022-11-06 13:07:36 +08:00
.layout-content-box {
flex-wrap: nowrap;
}
}
2022-11-03 04:58:16 +08:00
}
</style>