91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何用Vue3實現可復制表格

發布時間:2022-12-13 09:20:18 來源:億速云 閱讀:127 作者:iii 欄目:開發技術

這篇“如何用Vue3實現可復制表格”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“如何用Vue3實現可復制表格”文章吧。

最基礎的表格封裝

最基礎基礎的表格封裝所要做的事情就是讓用戶只關注行和列的數據,而不需要關注 DOM 結構是怎樣的,我們可以參考 AntDesigncolumns 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 }
  }
})

測試

最后我們可以寫一個demo測一下功能是否正常,代碼如下:

<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>

附上完整代碼:

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 }
  }
})

以上就是關于“如何用Vue3實現可復制表格”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

维西| 涞水县| 读书| 万载县| 靖远县| 临城县| 互助| 滦南县| 乐东| 西昌市| 通榆县| 霞浦县| 平罗县| 丹阳市| 荥经县| 温泉县| 舒城县| 仪陇县| 宕昌县| 班玛县| 积石山| 公安县| 龙山县| 上蔡县| 宣恩县| 新津县| 邹平县| 镇江市| 怀来县| 盐津县| 长垣县| 克什克腾旗| 台南县| 永川市| 东至县| 阿克苏市| 河源市| 龙南县| 玛多县| 金沙县| 东宁县|