赞
踩
写的很简陋哈,只实现了基本功能,还有许多地方需要完善。下面分别为常用的三种模式:
<template> <s-table :dataSource="state.dataSource" layout="column"> <s-table-column prop="id" label="ID"/> <s-table-column prop="name" label="名字"/> <s-table-column prop="age" label="年龄"/> <s-table-column prop="phone" label="电话号码" /> <s-table-column prop="hobby" label="爱好"/> </s-table> <br/> <s-table :dataSource="state.dataSource" :header-style="{textAlign:'center',width:'100px'}" align="center"> <s-table-column prop="name" label="名字"/> <s-table-column prop="age" label="年龄"/> <s-table-column prop="phone" label="电话号码"/> <s-table-column prop="hobby" label="爱好"/> </s-table> <s-table :dataSource="state.dataSource" layout="column"> <s-table-column prop="id" label="ID"/> <s-table-column prop="name" label="名字"/> <s-table-column prop="age" label="年龄"/> <s-table-column prop="phone" label="电话号码"> <template #default="defaultProps"> <s-input :value="defaultProps.value" name="phone" :rules="[ { type: 'required', message: '电话号码不能为空' }, ]" @update="update($event, defaultProps.data.id)" /> </template> </s-table-column> <s-table-column prop="hobby" label="爱好"/> </s-table> </template> <script lang="ts" setup> import { reactive } from "vue" import { STable, STableColumn, SInput } from "@/components" const state = reactive({ dataSource: [ { id: 1, name: "小明", age: 98, hobby: "游泳", phone: "123456" }, { id: 2, name: "小红", age: 55, hobby: "跑步", phone: "954623" }, { id: 3, name: "小黑", age: 32, hobby: "打羽毛球", phone: "654513" } ] }) const update = (params:BaseForm, id:number) => { state.dataSource = state.dataSource.map((item) => { if (item.id === id) { return { ...item, [params.name]: params.value } } else { return item } }) } </script>
// Table 方向 type TableLayout = "horizon" | "column"; // Table 支持的头部样式 interface HeaderStyle { width?: string; // 头部宽度 height?: string; // 头部高度 textAlign?: TableAlign; // 头部文本排列方式 } // 真实运用到dom的头部样式 interface RealHeaderStyle extends HeaderStyle { minWidth?: string; minHeight?: string; lineHeight?: string; flex?: number; display?: string; alignItems?: string; justifyContent?: string; [index: string]: string | number | undefined; } // Table 文本方向 type TableAlign = "left" | "center" | "right"; // 每一条数据的格式(根据需要自定义) type TableCell = { id: number | string; [index: string]: any; };
写的有点烂,当时想着只改个layout属性就能改变表格方向,于是在样式的使用上花了很多时间,也写了许多样式的逻辑判断,挺绕。如果有其他更优雅的方案欢迎评论区提出。
<script lang="ts"> import { h, PropType, reactive, watchEffect } from "vue" import { TableCell, HeaderStyle, TableAlign } from "@types" export default { name: "STable", props: { // 数据源 dataSource: { type: Array as PropType<TableCell[]>, default: () => [] }, // 头部样式 headerStyle: Object as PropType<HeaderStyle>, // 表格展示方向 layout: { type: String, default: "horizon" }, // 表格体文本排列方式 align: { type: String as PropType<TableAlign>, default: "left" } }, setup (props, context) { if (!context.slots || !context.slots.default) return null let slots = reactive<any[]>([]) // 监听父组件传来的属性变化,让子组件跟着变化 watchEffect(() => { if (!context.slots || !context.slots.default) return null slots = context.slots.default().map((slot) => ({ ...slot, props: { ...props, ...slot.props } })) }) // 根据不同的方向应用不同的样式 if (props.layout === "column") { return () => h( "div", { className: "s-table table-layout-column" }, slots ) } else { return () => h( "div", { className: "s-table-wrap" }, [h("div", { className: "s-table table-layout-horizon" }, slots)] ) } } } </script> <style lang="less"> // 一开始用flex布局来处理正常情况下的表格样式(column) // 后面发现用在flex在横向时不管用,改用了grid布局,所以写的不是很统一,根据需求改哈~ .s-table-wrap { overflow: auto; .s-table { border-radius: @bigRadius; &.table-layout-horizon { display: grid; .table-columns { display: flex; .table-cell { flex: 1; } // 从第二行开始 &:nth-child(n + 2) { .table-title, .table-cell { border-right: 1px dotted @borderColor; border-bottom: 1px dotted @borderColor; } .table-title { background-color: @default; } } &:first-child { .table-title { color: @white; } .table-cell { background-color: @default; border-bottom: 1px dotted @borderColor; &:nth-child(n + 3) { border-left: 1px dotted @borderColor; } } } } } } } .s-table { overflow-x: auto; border-radius: @bigRadius; &.table-layout-column { display: flex; .table-columns { display: flex; flex-direction: column; // flex-basis: 100px; &:nth-child(n + 3) { .table-cell { border-top: 1px dotted @borderColor; } } .table-title { white-space: nowrap; border-bottom: 1px dotted @borderColor; background-color: @default; position: relative; } .table-cell { flex: 1; } } } } </style>
<template> <ul class="table-columns" :key="prop" :style="{...culumnStyle}"> <li :class="['table-title',textAlign]" :key="prop" :style="{...titleStyle}">{{label}}</li> <li :class="['table-cell',textAlign]" v-for="data in dataSource" :key="data.id"> <slot name="default" :data="data" :value="data[prop]"> {{data[prop]}} </slot> </li> </ul> </template> <script lang='ts'> import { PropType, ref } from "vue" import { TableCell, HeaderStyle, RealHeaderStyle, TableLayout, TableAlign } from "@types" export default { props: { prop: { type: String, default: "" }, label: { type: String, require: true }, width: { type: String, default: "" }, // 列的宽度 align: { type: String as PropType<TableAlign>, default: "left" } //继承父组件表格传来的 dataSource: { type: Array as PropType<TableCell[]>, default: () => [] }, headerStyle: Object as PropType<HeaderStyle>, layout: { type: String as PropType<TableLayout>, default: "horizon" }, }, setup (props, context) { const titleStyle = ref<RealHeaderStyle>({}) const culumnStyle = ref({}) const textAlign = ref(props.align) const colWidth = ref(props.width) // 头部的默认样式与自定义样式 const HS = props.headerStyle || undefined if (props.layout === "horizon") { // 【头左体右】表格 titleStyle.value.minWidth = "180px" // 默认样式 if (HS) { titleStyle.value = { ...titleStyle.value, ...HS } if (HS.width) { titleStyle.value.minWidth = HS.width } } } else { // 正常方向表格 【头上体下】表格 if (HS) { titleStyle.value = { ...HS } if (HS.width) { titleStyle.value.minWidth = HS.width // 避免头部的宽度小于内容宽度 } else { // 如果表格没有传头部的宽度,cell自动扩展 culumnStyle.value.flex = 1 } if (HS.height) { titleStyle.value.minHeight = HS.height titleStyle.value.lineHeight = HS.height } } else { // 如果表格没有传头部的样式,cell自动扩展 culumnStyle.value.flex = 1 } // 判断列是否有传宽度 if (colWidth.value) { titleStyle.value.minWidth = colWidth.value // 列的样式覆盖表格的样式 } } return { titleStyle, textAlign, culumnStyle } } } </script> <style lang="less"> .table-cell,.table-title{ padding: @itemSpace; } .table-columns{ .center{ text-align: center; } .left{ text-align: left; } .right{ text-align: right; } } </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。