VueJS/Nuxt

[VueJS] NuxtJS에 jQuery slick.grid.js 적용해보기

SongMinu 2021. 6. 2. 12:17
728x90

피치 못할 사정으로 NuxtJS에서 jQuery 기반의 슬릭그리드를 대체할 플러그인을 찾지 못해서 jQuery를 적용시킨 후

슬릭그리드를 적용해보려고 했었다.


먼저 jQuery 적용은 https://minu0807.tistory.com/90 여기처럼 적용했고,

슬릭그리드 적용은 해당 vue파일에 할까 하다가 그냥 nuxt.config.js에다 적용했다.

  head: {
    title: 'AF_Manager',
    htmlAttrs: {
      lang: 'en'
    },
    meta: [{ charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: '' }],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },{ rel: 'stylesheet', href: '/lib/slick/slick.css' }],
    script: [
      { type: 'text/javascript', src: '/lib/jquery.js' },
      { type: 'text/javascript', src: '/lib/slick/slick.core.js' },
      { type: 'text/javascript', src: '/lib/slick/slick.grid.js' },
      { type: 'text/javascript', src: '/lib/slick/plugins/slick.checkboxselectcolumn.js' },
    ]
  },

nuxt.config.js에서 head에 추가한 스크립트 파일 읽는 순서와 렌더링 순서의 문제도 있어서 다양한 방법을 써봤지만 일단 내가 한 방법은 이거다.

<template>
   <v-card>
    <v-card-title>
      <v-row>
        <v-col cols="12" lg="2">
          <v-menu
            ref="menu1"
            v-model="menu1"
            :close-on-content-click="false"
            :return-value.sync="s_date"
            transition="scale-transition"
            offset-y
            min-width="290px"
          >
            <template v-slot:activator="{ on, attrs }">
              <v-text-field
                v-model="s_date"
                prepend-icon="mdi-calendar"
                readonly
                v-bind="attrs"
                v-on="on"
                id="test"
              ></v-text-field>
            </template>
            <v-date-picker v-model="s_date" no-title scrollable :max="e_date">
              <v-spacer></v-spacer>
              <v-btn text color="primary" @click="menu1 = false">Cancel</v-btn>
              <v-btn text color="primary" @click="s_date_search(s_date)">OK</v-btn>
            </v-date-picker>
          </v-menu>
        </v-col>      
      </v-row>
    </v-card-title>
    <v-card-text>
      <div id="slickgrid" style="height: 650px"></div>
    </v-card-text>
    
  </v-card>
</template>

<script>
export default {
  data() {
    return {
      totCount: 0,
      searchSize: 0,
      grid: null,
      rows: [],
      columns: [],
      selectRows: [],
      sort: `{"test_mk_dt": "desc"}`,
      checkboxSelector: null,
      options: {
        editable: true,
        enableCellNavigation: true,
        asyncEditorLoading: false,
        enableAsyncPostRender: true,
        autoEdit: false,
        threat_pressing: true,
        enableTextSelectionOnCells: true,
        enableColumnReorder: false
      },

      date: new Date().toISOString().substr(0, 10),
      s_date: new Date().toISOString().substr(0, 10),
      e_date: new Date().toISOString().substr(0, 10),
      menu1: false,
      menu2: false
    }
  },
  mounted() {
    this.totCount = 0;
    this.searchSize = 200;

    this.setColumns();

    this.grid = new Slick.Grid("#slickgrid", this.rows, this.columns, this.options);
    this.grid.setSelectionModel(new Slick.RowSelectionModel({selectActiveRow: false}));
		this.grid.registerPlugin(this.checkboxSelector);

    this.getData();

    //checkbox
    this.grid.onSelectedRowsChanged.subscribe((e, args) => {
      this.selectRows = [];
      for (var i in args.rows) {
        this.selectRows.push(args.rows[i]);
      }
    });
    //contextMenu
    this.grid.onContextMenu.subscribe((e) => {
      e.preventDefault();
			const cell = this.grid.getCellFromEvent(e);
			const obj = this.grid.getColumns()[cell.cell];
			const data = this.grid.getDataItem(cell.row);
			const val = data[obj.id];
      console.log(cell, obj, data, val);
    });
    //sort 기능
    this.grid.onSort.subscribe((e, args) => {
      if (args.sortAsc) {
        this.sort = `{"${args.sortCol.id}":"asc"}`;
      } else {
        this.sort = `{"${args.sortCol.id}":"desc"}`;
      }
      this.searchSize = 200;
      this.getData();
		});
    //scroll 기능
    this.grid.onScroll.subscribe((e, o) => {
      if (o.scrollTop >= $("#slickgrid .grid-canvas").height() - $("#slickgrid .slick-viewport").height()) {
        if (this.totCount !== 0) {
          if (this.totCount >= this.searchSize) {
            this.searchSize += 100;
            this.getData()
          }
        }
			}
		});
  },
  methods: {
    setColumns() {
      this.checkboxSelector = new Slick.CheckboxSelectColumn({
        cssClass: "slick-cell-checkboxsel"
      });
      this.columns.push(this.checkboxSelector.getColumnDefinition());
      this.columns.push(
        { name: "생성일", field: "test_mk_dt", id: "test_mk_dt", cssClass:'text-center', width:150, sortable: true }, 
        { name: "이름", field: "name", id: "name", cssClass:'text-center',sortable: true }, 
        { name: "나이", field: "age", id: "age", cssClass:'text-center',sortable: true }, 
        { name: "아이피", field: "test_ip", id: "test_ip", cssClass:'text-center',sortable: true }, 
        { name: "포트", field: "test_port", id: "test_port", cssClass:'text-center',sortable: true }, 
        { name: "사용여부", field: "is_use", id: "is_use", cssClass:'text-center',sortable: false, formatter: this.fmt_is_use }, 
      )
    },
    async getData() {
      try {
        const params = {
          size: this.searchSize,
          s_date: this.s_date,
          e_date: this.e_date,
          sort: this.sort
        }
        const rs = await this.$store.dispatch('initList', params);
        this.rows = rs.data.data;
        this.totCount = rs.data.data.length;
        this.grid.setData(this.rows);
        this.grid.render();
      } catch (err) {
        console.error('monitoring getData err : ', err);
      }
    },
    s_date_search(v) {
      this.s_date = v;
      this.menu1 = false;
      this.$refs.menu1.save(v);
    },
    e_date_search(v) {
      this.e_date = v;
      this.menu2 = false;
      this.$refs.menu2.save(v);
    },

    //slick.grid formatter
    fmt_is_use(row, cell, value, def, data) {
      if (data.is_use) {
        return '사용';
      } else {
        return '사용안함'
      }
    }
  }
}
</script>

<style>
.slick-cell {
  color: black;
}
</style>

적용 시킨 vue파일 소스이다.

 

순서 때문에 우선 mounted() 훅에서 슬릭그리드를 적용시켜야 하고,

슬릭그리드의 내장 함수도 사용하려면 위 소스 처럼 mounted 훅에 작성해줘야 한다.

그 외에는 다른 부분에 작성해도 사용가능하다.

슬릭그리드가 그려진 화면


이걸 만들면서 생각보다 오래걸린 부분이 있다.

scope 개념을 생각못하고 문제를 해결 못해서 오래걸렸었다.

mounted 훅에 작성된 슬릭그리드 내장 함수 안에서 data() 안에 만들어 둔 값들을 가져오거나

methods 훅에 만든 함수를 실행을 시켜야하는데

this.grid.onSort.subscribe(function(e, args) {
      if (args.sortAsc) {
        this.sort = `{"${args.sortCol.id}":"asc"}`;
      } else {
        this.sort = `{"${args.sortCol.id}":"desc"}`;
      }
      this.searchSize = 200;
      this.getData();
});

처음에 이렇게 작성을 해서 왜 methods에 선언된 함수랑 data에 선언된 값을 못가져오는 건지 빨리 파악을 못해서 삽질을 엄청 했다.

애로우펑션을 쓰면 된다.

this.grid.onSort.subscribe((e, args) => {
      if (args.sortAsc) {
        this.sort = `{"${args.sortCol.id}":"asc"}`;
      } else {
        this.sort = `{"${args.sortCol.id}":"desc"}`;
      }
      this.searchSize = 200;
      this.getData();
});

이 부분에 대한 이해가 안된다면 Arrow function에 대해 찾아보길 바란다.

 

 

 

 

 

 

 

반응형