Sky Archive

SPA/Vue.js

[Vue.js] 엑셀 다운로드(Excel Download)

서울시장 2021. 8. 11. 15:21

서버단에서 poi 메이븐으로 사용하여 다운로드하는 방법이 있지만 vue.js를 사용하고 있다면 화면단에서 불러온 목록 데이터를 엑셀로 만들어서 다운로드 할 수 있다.

 

npm install --save xlsx

xlsx를 설치해준다.

 

"xlsx": "^0.16.7" 버전으로 진행했다.

 

스크립트에서 import xlsx from 'xlsx'를 추가해준다.

 

data 변수는 아래와 같이 선언해주며 excelList는 조회해온 데이터로 설정하면 된다. 현재는 테스트 데이터를 넣어두었다.

header에서 key값은 목록데이터에서 키값이랑 매핑이 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  data() {
    return {
      visibleHeadProps: [],
      instance: undefined,
      
      excelList: [
        {no: 1, name: 'Anchovy', point: 70},
        {no: 2, name: 'ZeroLine', point: 95},
        {no: 3, name: '서울시장', point: 100},
        {no: 4, name: 'KingPork', point: 80},
        {no: 5, name: 'LeeMass', point: 60}
      ],
      header: [
        {
          key: 'no',
          name: 'No'
        },
        {
          key: 'name',
          name: '성명'
        },
        {
          key: 'point',
          name: '점수'
        }
      ]
    }
cs

 

엑셀 다운로드 버튼에 클릭 시 excelDownload() 함수를 걸어두고 데이터 정보를 세팅하여 excelExport()가 호출하게 되면 엑셀 다운로드가 실행된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  methods: {
    excelDownload() {
      let options = {
        header: this.header,
        headProps: 'header'
      }
      
      this.excelExport(this.excelList, options)
    },
    excelExport(data, options) {
      // data row별 header에 바인딩 될 매핑값 설정
      let headProps = []
      if (Array.isArray(options.headProps)) {
        headProps = options.headProps
      } else if (options.headProps === 'header') {
        for (let h of this.header) {
          headProps.push(h.key)
        }
      } else {
        headProps = Object.keys(data[0])
      }
      this.visibleHeadProps = headProps
      
      this.instance = document.createElement('table')
      
      // Header 세팅
      let header = []
      if (!Array.isArray(this.header[0])) {
        header.push(this.header)
      } else {
        header = this.header
      }

      let thead = document.createElement('thead')
      for (let row of header) {
        let tr = document.createElement('tr')
        for (let h of row) {
          let rowspan = h.rowspan || '1'
          let colspan = h.colspan || '1'
          let th = document.createElement('th')
          th.setAttribute('rowspan', rowspan)
          th.setAttribute('colspan', colspan)
          th.innerText = h.name
          tr.appendChild(th)
        }
        thead.appendChild(tr)
      }
      this.instance.appendChild(thead)
      
      // Body 세팅
      let tbody = document.createElement('tbody')

      for (let row of data) {
        let tr = document.createElement('tr')
        for (let cellkey of this.visibleHeadProps) {
          let td = document.createElement('td')
          td.innerText = row[cellkey]
          tr.appendChild(td)
        }
        tbody.appendChild(tr)
      }
      this.instance.appendChild(tbody)
      
      // instance에 만들어진 table을 엑셀파일로 저장
      let config = { raw: true, type: 'string' }
      let ws = xlsx.utils.table_to_sheet(this.instance, config)
      let wb = xlsx.utils.book_new()

      xlsx.utils.book_append_sheet(wb, ws, 'Sheet1')
      xlsx.writeFile(wb, '성적표.xlsx')
    }
  }
cs

 

아래와 같이 출력된 목록을 엑셀 다운로드 실행한다.

 

원하는 목록 데이터에 맞게 엑셀 파일이 vue화면단에서 생성할 수가 있다.

 

엑셀 목록에서 아래와 같이 헤더가 두줄로 rowspan 또는 colspan으로 출력해야될 경우

 

header변수에 로우별로 push하여 세팅해주고 목록 데이터가 바인딩될 headProps 변수에 키값으로 세팅해준다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
      header:[],      
      headProps: [
        'no',
        'name',
        'math',
        'english'
      ],
      headRow1: [
        {
          key: 'no',
          name: 'No',
          rowspan: 2
        },
        {
          key: 'name',
          name: '성명',
          rowspan: 2
        },
        {
          name: '점수',
          colspan: 2,
          rowspan: 1
        }
      ],
      headRow2: [
        {
          key: 'math',
          name: '수학',
          colspan: 1,
          rowspan: 1
        },
        {
          key: 'english',
          name: '영어',
          colspan: 1,
          rowspan: 1
        }
      ]
cs

 

엑셀 다운로드 클릭 시 호출되는 excelDownload() 함수 또한 header에 맞게 변경한다.

 

1
2
3
4
5
6
7
8
9
10
11
  excelDownload() {
      this.header = []
      this.header.push(this.headRow1)
      this.header.push(this.headRow2)

      let options = {
        header: this.header,
        headProps: this.headProps
      }
      this.excelExport(this.excelList, options)
    }
cs

 

셀이 합쳐진 엑셀 형식으로도 다운로드 가능하다.