티스토리 뷰
** 2021-04-16
1.0.6 버전 부터 ag grid 를 지원하도록 기능을 추가하였습니다.
---------------------------------------------------------------------------------------------------------------------------------
안녕하세요. 오늘은 npm package 하나를 소개해 드리겠습니다.
우선 다음의 예제를 vuetify 로 구현해 보겠습니다.
* Vuetify 코드
<template> <v-form ref="form" v-model="valid" lazy-validation> <v-text-field v-model="name" :counter="10" :rules="nameRules" label="Name" required/> <v-text-field v-model="email" :rules="emailRules" label="E-mail" required/> <v-select v-model="select" :items="items" :rules="[v => !!v || 'Item is required']" label="Item" required/> <v-checkbox v-model="checkbox" :rules="[v => !!v || 'You must agree to continue!']" label="Do you agree?" required/> <v-btn :disabled="!valid" color="success" class="mr-4" @click="validate"> Validate </v-btn> <v-btn color="error" class="mr-4" @click="reset"> Reset Form </v-btn> <v-btn color="warning" @click="resetValidation"> Reset Validation </v-btn> </v-form> </template> <script> export default { data: () => ({ valid: true, name: '', nameRules: [ v => !!v || 'Name is required', v => (v && v.length <= 10) || 'Name must be less than 10 characters', ], email: '', emailRules: [ v => !!v || 'E-mail is required', v => /.+@.+\..+/.test(v) || 'E-mail must be valid', ], select: null, items: [ 'Item 1', 'Item 2', 'Item 3', 'Item 4', ], checkbox: false, }), methods: { validate () { this.$refs.form.validate() }, reset () { this.$refs.form.reset() }, resetValidation () { this.$refs.form.resetValidation() }, }, } </script>
다음은 제가 만든 v-iterator 를 사용한 코드입니다.
<template> <v-iterator :dynamicArg="screen" :data="$data" @validate="validate" @reset="reset" @resetValidation="resetValidation"/> </template> export default { computed: { screen () { return { items: [ { component: 'form', ref: 'form', model: 'valid', lazyValidation: true, items: [ { component: 'txtfld', model: 'name', couter: '10', rules: ['requiredRule', 'nameRule'], label: 'Name', required: true }, { component: 'txtfld', model: 'email', rules: ['requiredRule', 'emailRule'], label: 'E-mail', required: true }, { component: 'select', model: 'select', items: 'items', rules: ['requiredRule'], label: 'Item', required: true }, { component: 'chk', model: 'checkbox', rules: ['requiredRule'], label: 'Do you agree?', required: true }, { component: 'btn', disabled: 'isNotValid', color: 'success', class: 'mr-4', itemtext: 'Validate', evnts: [{event: 'click', method: 'validate'}] }, { component: 'btn', color: 'error', class: 'mr-4', itemtext: 'Reset Form', evnts: [{event: 'click', method: 'reset'}] }, { component: 'btn', color: 'warning', class: 'mr-4', itemtext: 'Reset Validation', evnts: [{event: 'click', method: 'resetValidation'}] } ]} ] } } }, data: () => ({ valid: true, isNotValid: false, name: '', requiredRule: v => !!v || 'Required', nameRule: v => (v && v.length <= 10) || 'Name must be less than 10 characters', email: '', emailRule: v => /.+@.+\..+/.test(v) || 'E-mail must be valid', select: null, items: [ 'Item 1', 'Item 2', 'Item 3', 'Item 4', ], checkbox: false, }), watch: { valid (value) { this.isNotValid = !value } }, methods: { validate() { this.$refs.code.getRef('form').validate() }, reset() { this.$refs.code.getRef('form').reset() }, resetValidation() { this.$refs.code.getRef('form').resetValidation() }, }, }
보시다시피 가장 큰 차이는 <template> 코드는 줄고, screen 구성을 <script> 영역에서 구현할 수 있다는 점입니다.
<template> 에서 화면 구성에 변화를 줄 경우 가능한 방법은 v-if, v-show 정도이지만, v-iterator 를 사용할 경우 <template>은 변화없이 <script> 내의 data, computed, method 또는 별도의 function , js 등 다양한 방법으로 구현 할 수 있습니다.
그럼 위 코드를 다시 변형시켜보겠습니다.
* screen.js
export default { items: [ { component: 'form', ref: 'form', model: 'valid', lazyValidation: true, items: [ { component: 'txtfld', model: 'name', couter: '10', rules: ['requiredRule', 'nameRule'], label: 'Name', required: true }, { component: 'txtfld', model: 'email', rules: ['requiredRule', 'emailRule'], label: 'E-mail', required: true }, { component: 'select', model: 'select', items: 'items', rules: ['requiredRule'], label: 'Item', required: true }, { component: 'chk', model: 'checkbox', rules: ['requiredRule'], label: 'Do you agree?', required: true }, { component: 'btn', disabled: 'isNotValid', color: 'success', class: 'mr-4', itemtext: 'Validate', evnts: [{event: 'click', method: 'validate'}] }, { component: 'btn', color: 'error', class: 'mr-4', itemtext: 'Reset Form', evnts: [{event: 'click', method: 'reset'}] }, { component: 'btn', color: 'warning', class: 'mr-4', itemtext: 'Reset Validation', evnts: [{event: 'click', method: 'resetValidation'}] } ]} ] }
* form.vue
<template> <v-iterator :dynamicArg="screen" :data="$data" @validate="validate" @reset="reset" @resetValidation="resetValidation"/> </template> const screen = require(./screen.js) export default { data: () => ({ valid: true, isNotValid: false, name: '', requiredRule: v => !!v || 'Required', nameRule: v => (v && v.length <= 10) || 'Name must be less than 10 characters', email: '', emailRule: v => /.+@.+\..+/.test(v) || 'E-mail must be valid', select: null, items: [ 'Item 1', 'Item 2', 'Item 3', 'Item 4', ], checkbox: false, }), watch: { valid (value) { this.isNotValid = !value } }, methods: { validate() { this.$refs.code.getRef('form').validate() }, reset() { this.$refs.code.getRef('form').reset() }, resetValidation() { this.$refs.code.getRef('form').resetValidation() }, }, }
위와 같이 screen 구성을 별도의 js 로 만들어서 사용도 가능하며, json 으로 저장 후 변환하여 사용하는 것도 가능합니다.
◆ 이렇게 할 경우 몇가지 장점이 있습니다.
1. 화면 구성을 DB나 별도 파일로 저장이 가능합니다.
- <template> 에 화면 구성을 코딩한 경우 변경되면 다시 빌드해야 하지만, 별도의 DB나 파일로 저장하게 되면 빌드 없이 화면을 변경 할 수 있습니다.
2. 가독성 증가
- data object 구조로 구성되므로 template 문법에 익숙하지 않아도 좀 더 쉽게 접근 가능합니다.
3. 유지보수성 증가
- vuetify를 그대로 사용하는 경우 vuetify가 업데이트 되는 경우 전체 template 코드에서 변경 부분을 확인해야 하지만, v-iterator를 사용하는 경우 vuetify 변경사항을 대신 적용하므로 v-iterator update로 변경 영향도를 최소화하면서 변경이 가능합니다.
◆ v-iterator에서는 몇가지 편의기능도 지원합니다.
1. v-currency
- 금액 입력만을 위한 v-currency를 내장하고 있습니다. (v-text-field 기반)
2. component 단축어 지원
- v-autocomplete > aut, v-bottom-navigation > bnavi 등 단축어를 지원합니다.
3. i18n
- i18n을 사용하여 다국어 지원을 하는 경우 일반적으로 다음과 같이 사용합니다.
$t('common.confirm')
v-iterator에서는 $t 없이 'common.confirm' 으로 입력하여 사용합니다.
◆ 설치방법
v-iterator에서는 vue, vuetify, lodash 가 필수로 필요하며 우선 아래의 링크를 참고하여 설치환경을 구성합니다.
vuetifyjs.com/en/getting-started/installation/
lodash까지 설치가 되었으면, v-iterator를 설치합니다.
npm i v-iterator --save
v-iterator를 전역으로 사용하는 경우 main.js 에서 import 구문을 추가합니다.
import Vue from 'vue' import App from './App.vue' import vuetify from './plugins/vuetify' // import and set v-iterator import {VIterator} from 'v-iterator' Vue.component(VIterator.name, VIterator) new Vue({ vuetify, render: h => h(App) }).$mount('#app')
그 다음 vue.config.js 에서 runtimeCompiler를 true 로 설정합니다.
module.exports = { runtimeCompiler: true }
◆ 사용 방법
props 나 event, class 는 vuetify에서 제공하는 것과 동일하게 입력 가능합니다. 단, event의 경우 <template> 에는 component event 가 호출하는 method를 v-on:method명="method명" 과 같이 입력합니다.
<template> <v-iterator :dynamicArg="screen" :data="$data" @btnClick="btnClick"> </template> <script> export default { data: () => ({ screen: { items: [ { component: 'container', fluid: true, items: [ { component: 'btn', color: 'grey lighten-3', itemtext: 'Block Button', style: 'width: 100%;', evnts: [{ event: 'click', method: 'btnClick'}] }, { component: 'card', flat: true, items: [ { component: 'card-text', itemtext: 'textData' } ]} ]} ] }, textData: 'Button clicked!', clickedCount: 0 }), methods: { btnClick () { this.clickedCount++ this.textData = String(this.textData).concat(': ', this.clickedCount) } } } </script>
* 지원 component 명 (축약어 포함)
agGrid: 'AG Grid', agd: 'AG Grid', alert: 'Alert', alt: 'Alert', appBar: 'AppBar', appbar: 'AppBar', apb: 'AppBar', autocomplete: 'Autocomplete', aut: 'Autocomplete', avatar: 'Avatar', ava: 'Avatar', badge: 'Badge', bge: 'Badge', banner: 'Banner', bnr: 'Banner', bottomNavigation: 'BottomNavigation', bnavi: 'BottomNavigation', btmnav: 'BottomNavigation', bottomSheet: 'BottomSheet', bsheet: 'BottomSheet', btmsht: 'BottomSheet', breadcrumbs: 'Breadcrumbs', bread: 'Breadcrumbs', brd: 'Breadcrumbs', breadcrumbsItem: 'BreadcrumbsItem', breadItem: 'BreadcrumbsItem', breaditm: 'BreadcrumbsItem', brditm: 'BreadcrumbsItem', button: 'Button', btn: 'Button', buttonToggle: 'ButtonToggle', btnToggle: 'ButtonToggle', btntog: 'ButtonToggle', card: 'Card', crd: 'Card', cardTitle: 'CardTitle', crdtle: 'CardTitle', cardSubtitle: 'CardSubtitle', crdsut: 'CardSubitle', cardText: 'CardText', crdtxt: 'CardText', cardActions: 'CardActions', crdact: 'CardActions', calendar: 'Calendar', caledr: 'Calendar', cal: 'Calendar', carousel: 'Carousel', car: 'Carousel', carouselItem: 'CarouselItem', caritm: 'CarouselItem', carouselTranstion: 'CarouselTranstion', cartrn: 'CarouselTranstion', carouselReverseTranstion: 'CarouselReverseTranstion', carrevtrn: 'CarouselReverseTranstion', chip: 'Chip', chp: 'Chip', chipGroup: 'ChipGroup', chpgrp: 'ChipGroup', checkbox: 'Checkbox', chk: 'Checkbox', col: 'Col', combobox: 'Combobox', com: 'Combobox', container: 'Container', contai: 'Container', currency: 'Currency', cur: 'Currency', dataIterator: 'DataIterator', dtaIte: 'DataIterator', dataFooter: 'DataFooter', dtafoo: 'DataFooter', datePicker: 'DatePicker', date: 'DatePicker', dte: 'DatePicker', dtepik: 'DatePicker', dialog: 'Dialog', dia: 'Dialog', dialogTranstion: 'DialogTranstion', diatrn: 'DialogTranstion', dialogTopTranstion: 'DialogTopTranstion', diatoptrn: 'DialogTopTranstion', dialogBottomTranstion: 'DialogBottomTranstion', diabottrn: 'DialogBottomTranstion', divider: 'Divider', dvd: 'Divider', div: 'Div', expansionPanels: 'ExpansionPanels', expanels: 'ExpansionPanels', exppans: 'ExpansionPanels', expansionPanel: 'ExpansionPanel', expanel: 'ExpansionPanel', exppan: 'ExpansionPanel', expansionPanelHeader: 'ExpansionPanelHeader', expanelh: 'ExpansionPanelHeader', exppanhdr: 'ExpansionPanelHeader', expansionPanelContent: 'ExpansionPanelContent', expanelc: 'ExpansionPanelContent', exppancon: 'ExpansionPanelContent', expandTransition: 'ExpandTransition', exptrn: 'ExpandTransition', fadeTransition: 'FadeTransition', fadtrn: 'FadeTransition', fileInput: 'FileInput', file: 'FileInput', fle: 'FileInput', form: 'Form', frm: 'Form', footer: 'Footer', fter: 'Footer', ftr: 'Footer', hover: 'Hover', hovr: 'Hover', hvr: 'Hover', icon: 'Icon', icn: 'Icon', image: 'Image', img: 'Image', input: 'Input', in: 'Input', inp: 'Input', item: 'Item', itm: 'Item', itemGroup: 'ItemGroup', itmgrp: 'ItemGroup', lazy: 'Lazy', laz: 'Lazy', list: 'List', lst: 'List', listGroup: 'ListGroup', lstgrp: 'ListGroup', listItem: 'ListItem', lstitm: 'ListItem', listItemTitle: 'ListItemTitle', lstitmtle: 'ListItemTitle', listItemSubtitle: 'ListItemSubtitle', lstitmsut: 'ListItemSubtitle', listItemAction: 'ListItemAction', lstitmact: 'ListItemAction', listItemActionText: 'ListItemActionText', lstitmacttxt: 'ListItemActionText', listItemAvatar: 'ListItemAvatar', lstitmava: 'ListItemAvatar', listItemContent: 'ListItemContent', lstitmcon: 'ListItemContent', listItemIcon: 'ListItemIcon', lstitmicn: 'ListItemIcon', listItemGroup: 'ListItemGroup', lstitmgrp: 'ListItemGroup', menu: 'Menu', meu: 'Menu', navigationDrawer: 'NavigationDrawer', navdrw: 'NavigationDrawer', navidrw: 'NavigationDrawer', overflow: 'OverflowButton', overbtn: 'OverflowButton', overlay: 'Overlay', ovl: 'Overlay', pagination: 'Pagination', page: 'Pagination', pag: 'Pagination', parallax: 'Parallax', par: 'Parallax', pax: 'Parallax', progressLinear: 'ProgressLinear', progressL: 'ProgressLinear', prglin: 'ProgressLinear', progressCircular: 'ProgressCircular', progressC: 'ProgressCircular', prgcir: 'ProgressCircular', radio: 'Radio', rdo: 'Radio', radioGroup: 'RadioGroup', radiogrp: 'RadioGroup', rdogrp: 'RadioGroup', rating: 'Rating', rate: 'Rating', rat: 'Rating', range: 'RangeSlider', rangeSlider: 'RangeSlider', rng: 'RangeSlider', rngsld: 'RangeSlider', responsive: 'Responsive', res: 'Responsive', row: 'Row', scrollXTransition: 'ScrollXTransition', scrxtrn: 'ScrollXTransition', scrollYTransition: 'ScrollYTransition', scrytrn: 'ScrollYTransition', select: 'Select', slt: 'Select', sheet: 'Sheet', sht: 'Sheet', simpleTable: 'SimpleTable', simtbl: 'SimpleTable', skeletonLoader: 'SkeletonLoader', skeleton: 'SkeletonLoader', skelod: 'SkeletonLoader', slideItem: 'SlideItem', sliitm: 'SlideItem', slideGroup: 'SlideGroup', sligrp: 'SlideGroup', slider: 'Slider', sld: 'Slider', snackbar: 'Snackbar', sba: 'Snackbar', spacer: 'Spacer', spc: 'Spacer', speedDial: 'SpeedDial', spddil: 'SpeedDial', stepper: 'Stepper', stp: 'Stepper', stepperContent: 'StepperContent', stpcon: 'StepperContent', stepperHeader: 'StepperHeader', stphdr: 'StepperHeader', stepperItems: 'StepperItems', stpitm: 'StepperItems', stepperStep: 'StepperStep', stpstp: 'StepperStep', subheader: 'Subheader', subhdr: 'Subheader', switch: 'Switch', swc: 'Switch', tabItem: 'TabItem', tabitm: 'TabItem', tabReverseTransition: 'TabReverseTransition', tabrevtrn: 'TabReverseTransition', tabTransition: 'TabTransition', tabtrn: 'TabTransition', tabs: 'Tabs', tab: 'Tab', tabsItems: 'TabsItems', tabsitms: 'TabsItems', text: 'Text', txt: 'Text', textarea: 'Textarea', texta: 'Textarea', txta: 'Textarea', textField: 'Textfield', textfield: 'Textfield', txtfld: 'Textfield', toolbar: 'Toolbar', tlb: 'Toolbar', toolbarItems: 'ToolbarItems', tlbitms: 'ToolbarItems', timePicker: 'TimePicker', time: 'TimePicker', tim: 'TimePicker', treeview: 'Treeview', tre: 'Treeview', tree: 'Treeview', window: 'Window', win: 'Window', windowItem: 'WindowItem', winitm: 'WindowItem'
* event 처리
아래의 예제를 참고하세요. 화면 정의에서는 evnts array를 사용하여 발생 event와 연결되는 method, 지정 value 를 지정하고, <template> 에서 method명을 v-on으로 지정해 줍니다.
<template> <v-iterator :dynamicArg="screen" :data="$data" @btnClick="btnClick"> </tempalte> <script> export default { data: () => ({ screen: { items: [ { component: 'container', fluid: true, items: [ { component: 'btn', color: 'grey lighten-3', itemtext: 'Block Button', style: 'width: 100%;', evnts: [{ event: 'click', method: 'btnClick', value: '10' }] }, { component: 'card', flat: true, items: [ { component: 'card-text', itemtext: 'textData' } ]} ]} ] }, textData: 'Button clicked!', clickedCount: 0 }), methods: { btnClick (param) { this.addCount(param) }, addCount (param) { if (param) this.clickedCount =+ param else this.clickedCount++ this.textData = String('Button clicked!').concat(': ', this.clickedCount) } } } </script>
추가적인 사용법인 다음을 참고해주세요.
www.npmjs.com/package/v-iterator
감사합니다.
'dev > vue' 카테고리의 다른 글
Nativescript-vue 사용 (1) (0) | 2021.05.21 |
---|---|
Vue 새로고침 시 router 가 초기화 될 때 (0) | 2021.05.11 |
vue.js dynamic component를 이용한 팝업 띄우기 (0) | 2021.04.08 |
Vue 새창 띄우기에서 Session storage 그대로 유지하기 (0) | 2021.04.07 |
Vue 라이브러리 NPM 배포 및 사이즈 줄이기 (0) | 2021.03.05 |
- Total
- Today
- Yesterday
- vuex-persistedstate
- v-iterator
- ec2
- vs code fultter debug
- Android Studio Emulator
- nativescript-vue
- 긴급재난지원금
- ag-grid
- MariaDB
- Vue 다국어
- Galaxy Emulator
- vs code flutter
- dynamic component
- vue ios
- Add AVD
- 다국어
- 에뮬레이터
- 한글 like
- vue
- ag grid
- 갤럭시 에뮬레이터
- 경로 초기화
- AVD
- 플러터 디버그
- vue android
- aws
- 로그
- i18n
- vue mobile
- session stroage
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |