Die einfachste Tabellenkapselung ermöglicht es Benutzern, sich nur auf Zeilen- und Spaltendaten zu konzentrieren, ohne auf die DOM
-Struktur zu achten. Wir können auf verweisen AntDesign
, columns
dataSource
Diese beiden Attribute sind wichtig. Der Code lautet wie folgt: DOM
结构是怎样的,我们可以参考 AntDesign
,columns
dataSource
这两个属性是必不可少的,代码如下:
import { defineComponent } from 'vue' import type { PropType } from 'vue' interface Column { title: string; dataIndex: string; slotName?: string; } type TableRecord = Record<string, unknown>; export const Table = defineComponent({ props: { columns: { type: Array as PropType<Column[]>, required: true, }, dataSource: { type: Array as PropType<TableRecord[]>, default: () => [], }, rowKey: { type: Function as PropType<(record: TableRecord) => string>, } }, setup(props, { slots }) { const getRowKey = (record: TableRecord, index: number) => { if (props.rowKey) { return props.rowKey(record) } return record.id ? String(record.id) : String(index) } const getTdContent = ( text: any, record: TableRecord, index: number, slotName?: string ) => { if (slotName) { return slots[slotName]?.(text, record, index) } return text } return () => { return ( <table> <tr> {props.columns.map(column => { const { title, dataIndex } = column return <th key={dataIndex}>{title}</th> })} </tr> {props.dataSource.map((record, index) => { return ( <tr key={getRowKey(record, index)}> {props.columns.map((column, i) => { const { dataIndex, slotName } = column const text = record[dataIndex] return ( <td key={dataIndex}> {getTdContent(text, record, i, slotName)} </td> ) })} </tr> ) })} </table> ) } } })
需要关注一下的是 Column
中有一个 slotName
属性,这是为了能够自定义该列的所需要渲染的内容(在 AntDesign
中是通过 TableColumn
组件实现的,这里为了方便直接使用 slotName
)。
首先我们可以手动选中表格复制尝试一下,发现表格是支持选中复制的,那么实现思路也就很简单了,通过代码选中表格再执行复制命令就可以了,代码如下:
export const Table = defineComponent({ props: { // ... }, setup(props, { slots, expose }) { // 新增,存储table节点 const tableRef = ref<HTMLTableElement | null>(null) // ... // 复制的核心方法 const copy = () => { if (!tableRef.value) return const range = document.createRange() range.selectNode(tableRef.value) const selection = window.getSelection() if (!selection) return if (selection.rangeCount > 0) { selection.removeAllRanges() } selection.addRange(range) document.execCommand('copy') } // 将复制方法暴露出去以供父组件可以直接调用 expose({ copy }) return (() => { return ( // ... ) }) as unknown as { copy: typeof copy } // 这里是为了让ts能够通过类型校验,否则调用`copy`方法ts会报错 } })
这样复制功能就完成了,外部是完全不需要关注如何复制的,只需要调用组件暴露出去的 copy
export const Table = defineComponent({ props: { // ... }, setup(props, { slots, expose }) { const tableRef = ref<HTMLTableElement | null>(null) // 新增,定义复制状态 const copying = ref(false) // ... const getTdContent = ( text: any, record: TableRecord, index: number, slotName?: string, slotNameOnCopy?: string ) => { // 如果处于复制状态,则渲染复制状态下的内容 if (copying.value && slotNameOnCopy) { return slots[slotNameOnCopy]?.(text, record, index) } if (slotName) { return slots[slotName]?.(text, record, index) } return text } const copy = () => { copying.value = true // 将复制行为放到 nextTick 保证复制到正确的内容 nextTick(() => { if (!tableRef.value) return const range = document.createRange() range.selectNode(tableRef.value) const selection = window.getSelection() if (!selection) return if (selection.rangeCount > 0) { selection.removeAllRanges() } selection.addRange(range) document.execCommand('copy') // 别忘了把状态重置回来 copying.value = false }) } expose({ copy }) return (() => { return ( // ... ) }) as unknown as { copy: typeof copy } } })
Column< Es gibt ein < code>slotName
-Attribut in /code>, mit dem der Inhalt der Spalte angepasst werden kann, die gerendert werden muss (in AntDesign
erfolgt dies über TableColumn</ code > Von der Komponente implementiert, hier wird <code>slotName
der Einfachheit halber direkt verwendet. Implementieren Sie die KopierfunktionZunächst können wir die zu kopierende Tabelle manuell auswählen und ausprobieren. Wir haben festgestellt, dass die Tabelle das Auswählen und Kopieren unterstützt, sodass die Implementierungsidee sehr einfach ist und führen Sie dann den Kopierbefehl aus:
<template> <button @click="handleCopy">点击按钮复制表格</button> <c-table :columns="columns" :data-source="dataSource" border="1" ref="table" > <template #status> <img class="status-icon" :src="arrowUpIcon" /> </template> <template #statusOnCopy> → </template> </c-table> </template> <script setup lang="ts"> import { ref } from 'vue' import { Table as CTable } from '../components' import arrowUpIcon from '../assets/arrow-up.svg' const columns = [ { title: '序号', dataIndex: 'serial' }, { title: '班级', dataIndex: 'class' }, { title: '姓名', dataIndex: 'name' }, { title: '状态', dataIndex: 'status', slotName: 'status', slotNameOnCopy: 'statusOnCopy' } ] const dataSource = [ { serial: 1, class: '三年级1班', name: '张三' }, { serial: 2, class: '三年级2班', name: '李四' }, { serial: 3, class: '三年级3班', name: '王五' }, { serial: 4, class: '三年级4班', name: '赵六' }, { serial: 5, class: '三年级5班', name: '宋江' }, { serial: 6, class: '三年级6班', name: '卢俊义' }, { serial: 7, class: '三年级7班', name: '吴用' }, { serial: 8, class: '三年级8班', name: '公孙胜' }, ] const table = ref<InstanceType<typeof CTable> | null>(null) const handleCopy = () => { table.value?.copy() } </script> <style scoped> .status-icon { width: 20px; height: 20px; } </style>
Kopieren< aufrufen /code>-Methode, die von der Komponente bereitgestellt wird. Umgang mit nicht kopierbaren Elementen in der TabelleObwohl die Kopierfunktion sehr einfach ist, kopiert sie nur Text. Wenn die Tabelle einige nicht kopierbare Elemente (z. B. Bilder) enthält, müssen diese durch entsprechende ersetzt werden Textsymbole beim Kopieren, wie erreicht man das? Die Lösung besteht darin, einen Kopierstatus innerhalb der Komponente zu definieren, den Status beim Aufrufen der Kopiermethode auf „Kopieren“ festzulegen und entsprechend diesem Status unterschiedliche Inhalte zu rendern (Bilder im Nicht-Kopierstatus zu rendern und entsprechende Textsymbole im zu rendern). Zustand kopieren), Code wie folgt: 🎜import { defineComponent, ref, nextTick } from 'vue'
import type { PropType } from 'vue'
interface Column {
title: string;
dataIndex: string;
slotName?: string;
slotNameOnCopy?: string;
}
type TableRecord = Record<string, unknown>;
export const Table = defineComponent({
props: {
columns: {
type: Array as PropType<Column[]>,
required: true,
},
dataSource: {
type: Array as PropType<TableRecord[]>,
default: () => [],
},
rowKey: {
type: Function as PropType<(record: TableRecord) => string>,
}
},
setup(props, { slots, expose }) {
const tableRef = ref<HTMLTableElement | null>(null)
const copying = ref(false)
const getRowKey = (record: TableRecord, index: number) => {
if (props.rowKey) {
return props.rowKey(record)
}
return record.id ? String(record.id) : String(index)
}
const getTdContent = (
text: any,
record: TableRecord,
index: number,
slotName?: string,
slotNameOnCopy?: string
) => {
if (copying.value && slotNameOnCopy) {
return slots[slotNameOnCopy]?.(text, record, index)
}
if (slotName) {
return slots[slotName]?.(text, record, index)
}
return text
}
const copy = () => {
copying.value = true
nextTick(() => {
if (!tableRef.value) return
const range = document.createRange()
range.selectNode(tableRef.value)
const selection = window.getSelection()
if (!selection) return
if (selection.rangeCount > 0) {
selection.removeAllRanges()
}
selection.addRange(range)
document.execCommand('copy')
copying.value = false
})
}
expose({ copy })
return (() => {
return (
<table ref={tableRef}>
<tr>
{props.columns.map(column => {
const { title, dataIndex } = column
return <th key={dataIndex}>{title}</th>
})}
</tr>
{props.dataSource.map((record, index) => {
return (
<tr key={getRowKey(record, index)}>
{props.columns.map((column, i) => {
const { dataIndex, slotName, slotNameOnCopy } = column
const text = record[dataIndex]
return (
<td key={dataIndex}>
{getTdContent(text, record, i, slotName, slotNameOnCopy)}
</td>
)
})}
</tr>
)
})}
</table>
)
}) as unknown as { copy: typeof copy }
}
})
Nach dem Login kopieren🎜Test🎜🎜Endlich können wir eine Demo schreiben, um zu testen, ob die Funktion normal ist. Der Code lautet wie folgt: 🎜rrreee🎜Angehängt ist der vollständige Code: 🎜rrreeeDas obige ist der detaillierte Inhalt vonSo implementieren Sie kopierbare Tabellen mit Vue3. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!