基础表格首先开发table组件之前,先想好要用什么样式的api,因为笔者在生产工作中用的都是element,所以前面几个组件风格和element类似,但是这次不打算用element的风格了,打算换一种,直接展示:
我们期望用户这样使用:
<script setup>const datalist = [ { id: 1, name: '《javaee企业应用实战》', author: 'dev1ce', price: '10.22', desc: '书中最后讲解的项目案例,涵盖从前期设计到最终实施的整个过程,对全书知识点进行串联和巩固,使读者融会贯通,掌握java web开发的精髓。' }, { id: 2, name: '《代码整洁之道》', author: 'r0bert', price: '10.22', desc: '整洁代码并非遵循一组规则编写的。不可能因为学习一套金规玉律就成为软件大师。专业精神和手工艺来自于推动规则形成的价值。' }, { id: 3, name: '《ecmascript 6 入门教程》', author: 'y1feng', price: '10.22', desc: '本书是一本开源的 javascript 语言教程,全面介绍 ecmascript 6 新引入的语法特性。' },]const columnslist = [ { title: '书名', key: 'name' }, { title: '作者', key: 'author' }, { title: '价格', key: 'price' }, { title: '简介', key: 'desc' }]</script><template> <sanorin-table :columns="columnslist" :data="datalist"/></template>
依照这个写出以下代码
<script setup> import { ref, computed } from 'vue' import { useprop, useneumorphism } from '../mixin/neumorphism' const props = defineprops({ ...useprop, ...{ data: { // datalist type: array, default: () => [], }, columns: { // columnslist type: array, default: () => [], }, } }) const { basestyleobject } = useneumorphism(props) let styleobject = computed(() => ({ // '--font-size': `${props.size-26}px`, '--line-height': `${props.size-20}px`, '--limit-size': `${props.size-28}px` }))</script><template> <div :> <table > <thead> <tr class="neumorphism"> <!-- 表头循环 --> <th v-for="col in columns" :key="col.key">{{col.title}}</th> </tr> </thead> <tbody> <!-- 表体循环 --> <tr class="neumorphism" v-for="row in data" :key="row.id"> <td v-for="col in columns" :key="col.key"> <span> {{row[col.key]}} </span> </td> </tr> </tbody> </table> </div></template><script> export default { name: 'sanorin-table', }</script><style scoped> @import "../../style/index.css"; @import "../../style/neumorphism.css"; table { width: 100%; /* border-collapse: collapse; */ empty-cells: show; border-collapse:separate; border-spacing:0px 10px; } table td, table th { color: var(--text-color); padding: 8px 16px 8px 16px; text-align: left; } table th { color: var(--text-back-color) !important; font-weight: 600; white-space: nowrap; } table tr{ margin-top: 20px; }</style>
最后出来的效果就是:
然后实现了这个后我们开始做后面的,先从固定表头开始。
固定表头这里先采用第一种,以后不能满足需求了再改成后面的方法。
效果和代码如下:
<script setup> import { ref, computed } from 'vue' import { useprop, useneumorphism } from '../mixin/neumorphism' const props = defineprops({ ...useprop, ...{ data: { // datalist type: array, default: () => [], }, columns: { // columnslist type: array, default: () => [], }, } }) const { basestyleobject } = useneumorphism(props) let styleobject = computed(() => ({ }))</script><template> <div class="san-table scrollbar" :> <table> <thead> <tr class="neumorphism"> <!-- 表头循环 --> <th v-for="col in columns" :key="col.key">{{col.title}}</th> </tr> </thead> <tbody> <!-- 表体循环 --> <tr class="neumorphism" v-for="row in data" :key="row.id"> <td v-for="col in columns" :key="col.key"> <span> {{row[col.key]}} </span> </td> </tr> </tbody> </table> </div></template><script> export default { name: 'sanorin-table', }</script><style scoped> @import "../../style/index.css"; @import "../../style/neumorphism.css"; .san-table{ padding: 0px 20px 20px 20px; height: 200px; position: relative; width: 700px; overflow: auto; } table { width: 100%; table-layout: fixed; empty-cells: show; border-collapse:separate; border-spacing:0px 10px; } thead { position: sticky; top: 10px; } thead:before{ position: absolute; content: ''; width: calc(100% + var(--shadow-blur) * 2); transform: translate(calc(var(--shadow-blur) * -1) , -10px); height: 20px; background-color: var(--main-color); z-index: -1; } table td, table th { color: var(--text-color); padding: 8px 16px 8px 16px; text-align: left; } table th { color: var(--text-back-color) !important; font-weight: 600; white-space: nowrap; }</style>
高度/流体高度可以为 table 设置一个高度。(height)
当数据量动态变化时,可以为 table 设置一个最大高度。(maxheight) 通过设置max-height属性为 table 指定最大高度。此时若表格所需的高度大于最大高度,则会显示一个滚动条。
只要在sanorin-table元素中定义了height或者maxheight属性,即可实现固定表头的表格,而不需要额外的代码。
代码如下:
<script setup> import { ref, computed, reactive } from 'vue' import { useprop, useneumorphism } from '../mixin/neumorphism' const props = defineprops({ ...useprop, ...{ data: { // datalist type: array, default: () => [], }, columns: { // columnslist type: array, default: () => [], }, height: { type: number, }, maxheight: { type: number, } } }) // 高度设置 let tableheightstyleobj = computed(() => { let styleobj = ((e) => { if (e.maxheight) return { maxheight: e.maxheight + 'px' } if (e.height) return { height: e.height + 'px' } return {} })({...props}) return styleobj }) const { basestyleobject } = useneumorphism(props) let styleobject = computed(() => ({ ...tableheightstyleobj.value }))</script><template> <div class="san-table scrollbar" :> <table> <colgroup> <col v-for="(col, index) in columns" :key="index"> </colgroup> <thead> <tr class="neumorphism"> <th v-for="col in columns" :key="col.key"> {{col.title}} </th> </tr> </thead> <tbody> <tr class="neumorphism" v-for="row in data" :key="row.id"> <td v-for="col in columns" :key="col.key"> {{row[col.key]}} </td> </tr> </tbody> </table> </div></template><script> export default { name: 'sanorin-table', }</script><style scoped> @import "../../style/index.css"; @import "../../style/neumorphism.css"; .san-table{ padding: 0px 20px 20px 20px; position: relative; width: 700px; overflow: auto; } table { width: 100%; table-layout: fixed; empty-cells: show; border-collapse:separate; border-spacing:0px 10px; } thead { position: sticky; top: 10px; } thead:before{ position: absolute; content: ''; width: calc(100% + var(--shadow-blur) * 2); transform: translate(calc(var(--shadow-blur) * -1) , -10px); height: 20px; background-color: var(--main-color); z-index: -1; } table td, table th { color: var(--text-color); padding: 8px 16px 8px 16px; text-align: left; } table th { color: var(--text-back-color) !important; font-weight: 600; white-space: nowrap; }</style>
自定义列宽接下来加入宽度控制,希望在columns 传入的数组对象内加入宽度,示例如下:
const columnslist = [ { title: '书名', key: 'name', width: 100, }, { title: '作者', key: 'author', width: 100, }, { title: '价格', key: 'price', width: 100, }, { title: '简介', key: 'desc', minwidth: 350, }]
希望达到以下效果
1、含有width的列,宽度固定,不随浏览器宽度变化而变化
2、含有minwidth的列,在大于设定值时,自动填充 table 剩余宽度,小于设定值时,固定该宽度
3、不包含width和minwidth的列,自动填充 table 剩余宽度
根据我们的需求,我们需要单独控制每一列的宽度展示,并在浏览器宽度变化时实时的重新计算并且重新渲染列。
首先定义出一个方法,用来计算每一列在当前情况下所要的宽度,再绑定要dom上。然后,每次表格变化/浏览器宽度变化时候就能实时响应改变table的宽度了。
const initcolumns = () => { // 计算每一列在当前情况下所要的宽度 } watch(() => props.columns, () => { initcolumns() }); onmounted(() => { nexttick(() => { initcolumns(); on(window, 'resize', throttle(() => initcolumns(), 400)); }); }); onbeforeunmount(() => off(window, 'resize', () => initcolumns()));
全部代码:
<script setup> import { ref, computed, watch, onmounted, onbeforeunmount, nexttick } from 'vue' import { on, off } from '../../utils/listener' import { throttle } from "../../utils/debounce&throttle" import { useprop, useneumorphism } from '../mixin/neumorphism' const table = ref() // 与html中ref=""对应,定位dom元素 const props = defineprops({ ...useprop, ...{ data: { // datalist type: array, default: () => [], }, columns: { // columnslist type: array, default: () => [], }, height: { // height type: number, }, maxheight: { // 流体高度 type: number, }, minunsetwidth: { // 未设置宽度时最小宽度 type: number, default: 80 } } }) // 高度设置 let tableheightstyleobj = computed(() => { let styleobj = ((e) => { if (e.maxheight) return { maxheight: e.maxheight + 'px' } if (e.height) return { height: e.height + 'px' } return {} })({...props}) return styleobj }) // 列宽设置 let col = ref([]) const { columns, minunsetwidth } = props const _min_column_width = minunsetwidth // 未设置宽度时最小宽度 const initcolumns = () => { col.value = (() => { let _total_width = table.value.offsetwidth // 表格dom元素总宽度 let _needed_minwidth = columns.reduce((t, v) => { // 需要的最小宽度 t += v.width || v.minwidth || _min_column_width return t }, 0) // 需要的最小宽度比总宽度大,则取minwidth即可 if (_needed_minwidth >= _total_width) return columns.reduce((t, v) => { let n = v.width || v.minwidth || _min_column_width t = [...t, n] return t }, []) // 需要的最小宽度比总宽度大,则要把minwidth加权,权重为(未分配的宽度 / minwidth之和) let _unassigned_width = columns.reduce((t, v) => { t += v.minwidth || 0 return t }, 0) let _assigned_width = _needed_minwidth - _unassigned_width let _width_power = (_total_width - _assigned_width) / _unassigned_width return columns.reduce((t, v) => { let n = v.width || (v.minwidth ? (_width_power * v.minwidth).tofixed(2) : _min_column_width) t = [...t, n] return t }, []) })() } watch(() => props.columns, () => { initcolumns() }) const throttleinitcolumns = () => throttle(() => initcolumns(), 400) onmounted(() => { nexttick(() => { initcolumns() on(window, 'resize', throttleinitcolumns) }) }) onbeforeunmount(() => off(window, 'resize', throttleinitcolumns)) const { basestyleobject } = useneumorphism(props) let styleobject = computed(() => ({ ...tableheightstyleobj.value }))</script><template> <div class="san-table scrollbar" :> <table ref="table"> <colgroup> <col v-for="(item, index) in col" :key="index" :width="`${item}px`"> </colgroup> <thead> <tr class="neumorphism"> <th v-for="col in columns" :key="col.key"> {{col.title}} </th> </tr> </thead> <tbody> <tr class="neumorphism" v-for="row in data" :key="row.id"> <td v-for="col in columns" :key="col.key"> {{row[col.key]}} </td> </tr> </tbody> </table> </div></template><script> export default { name: 'sanorin-table', }</script><style scoped> @import "../../style/index.css"; @import "../../style/neumorphism.css"; .san-table{ padding: 0px 20px 20px 20px; position: relative; overflow: auto; } table { width: 100%; table-layout: fixed; empty-cells: show; border-collapse:separate; border-spacing:0px 10px; } thead { position: sticky; top: 10px; } thead:before{ position: absolute; content: ''; width: calc(100% + var(--shadow-blur) * 2); transform: translate(calc(var(--shadow-blur) * -1) , -10px); height: 20px; background-color: var(--main-color); z-index: -1; } table td, table th { color: var(--text-color); padding: 8px 16px 8px 16px; text-align: left; word-break:break-all; } table th { color: var(--text-back-color) !important; font-weight: 600; white-space: nowrap; }</style>
其中用到的两个js,防抖节流和注册监听这里也放下吧
/* 防抖节流函数 */let timeout = null // 创建一个标记用来存放定时器的返回值let count = 0;export function debounce(fn, wait = 1000, immediate = false) { return function () { const args = arguments; if (immediate) { if (count == 0) { fn.apply(this, arguments) count++; } else { if (timeout) { cleartimeout(timeout) // 每当用户输入的时候把前一个 settimeout clear 掉 } timeout = settimeout(() => { fn.apply(this, arguments) }, wait) } } else { if (timeout) { cleartimeout(timeout) // 每当用户输入的时候把前一个 settimeout clear 掉 } timeout = settimeout(() => { fn.apply(this, arguments) }, wait) } }()}let canrun = true;let count1 = 0;export function throttle(fn, wait = 1000, immediate = true) { return function () { if (immediate) { if (count1 == 0) { fn.apply(this, arguments); count1++; } else { if (canrun) { canrun = false settimeout(function () { fn.apply(this, arguments) canrun = true }, wait); } } } else { if (!canrun) return canrun = false settimeout(function () { fn.apply(this, arguments) canrun = true }, wait); } }()}
/** * 绑定事件 on(element, event, handler) */export const on = (element, event, handler) => { if (document.addeventlistener) { if (element && event && handler) { element.addeventlistener(event, handler, false) } }}/** * 解绑事件 off(element, event, handler) */export const off = (element, event, handler) => { if (document.removeeventlistener) { if (element && event) { element.removeeventlistener(event, handler, false) } }}
以上就是vue3 table组件怎么使用的详细内容。