11import { defineComponent , ref , computed , nextTick , watch , SetupContext , getCurrentInstance } from 'vue' ;
22import { createI18nTranslate } from '../../locale/create' ;
3+ import clickoutsideDirective from '../../shared/devui-directive/clickoutside' ;
34import removeBtnSvg from './icon-remove' ;
45import { Suggestion , TagInputProps , tagInputProps } from './tag-input-types' ;
56import './tag-input.scss' ;
@@ -14,6 +15,9 @@ const KEYS_MAP = {
1415
1516export default defineComponent ( {
1617 name : 'DTagInput' ,
18+ directives : {
19+ clickoutside : clickoutsideDirective ,
20+ } ,
1721 props : tagInputProps ,
1822 emits : [ 'update:tags' , 'update:suggestionList' , 'valueChange' ] ,
1923 setup ( props : TagInputProps , ctx : SetupContext ) {
@@ -69,8 +73,14 @@ export default defineComponent({
6973 isInputBoxFocus . value = true ;
7074 } ;
7175 const onInputBlur = ( ) => {
76+ // isInputBoxFocus.value = false;
77+ } ;
78+
79+ // 点击元素外部区域关闭Suggestion选择
80+ const closeSuggestion = ( ) => {
7281 isInputBoxFocus . value = false ;
7382 } ;
83+
7484 const handleEnter = ( ) => {
7585 let res = { [ props . displayProperty ] : tagInputVal . value } ;
7686 if ( tagInputVal . value === '' && mergedSuggestions . value . length === 0 ) {
@@ -119,20 +129,23 @@ export default defineComponent({
119129 }
120130 } ;
121131
122- const removeTag = ( $event : MouseEvent , tagIdx : number ) => {
132+ const removeTag = ( $event : Event , tagIdx : number ) => {
123133 $event . preventDefault ( ) ;
124134 ctx . emit ( 'update:suggestionList' , add ( props . suggestionList , props . tags [ tagIdx ] ) ) ;
125135 const newTags = remove ( props . tags , tagIdx ) ;
126136 ctx . emit ( 'valueChange' , props . tags , newTags ) ;
127137 ctx . emit ( 'update:tags' , newTags ) ;
138+
128139 nextTick ( ( ) => {
129140 tagInputRef . value ?. focus ( ) ;
130141 } ) ;
131142 } ;
132- const onSuggestionItemClick = ( $event : MouseEvent , itemIndex : number ) => {
143+ const onSuggestionItemClick = ( $event : Event , itemIndex : number ) => {
133144 $event . preventDefault ( ) ;
134145 const target = mergedSuggestions . value [ itemIndex ] ;
135146 const newTags = add ( props . tags , target ) ;
147+
148+
136149 const newSuggestions = remove ( props . suggestionList , target . __index ) ;
137150 ctx . emit ( 'valueChange' , props . tags , newTags ) ;
138151 ctx . emit ( 'update:tags' , newTags ) ;
@@ -144,119 +157,73 @@ export default defineComponent({
144157 return ! props . disabled && ! isTagsLimit . value && isInputBoxFocus . value ;
145158 } ) ;
146159
147- return {
148- tagInputRef,
149- tagInputVal,
150- isInputBoxFocus,
151- onInput,
152- onInputFocus,
153- onInputBlur,
154- removeTag,
155- onSuggestionItemClick,
156- onInputKeydown,
157- isShowSuggestion,
158- mergedSuggestions,
159- selectIndex,
160- isTagsLimit,
161- t,
162- } ;
163- } ,
164- render ( ) {
165- const {
166- tagInputVal,
167- isInputBoxFocus,
168- disabled,
169- disabledText,
170- isTagsLimit,
171- maxTagsText,
172- displayProperty,
173- tags,
174- onInputKeydown,
175- onInputFocus,
176- onInputBlur,
177- onInput,
178- onSuggestionItemClick,
179- removeTag,
180- placeholder,
181- spellcheck,
182- isShowSuggestion,
183- noData,
184- mergedSuggestions,
185- selectIndex,
186- maxTags,
187- t,
188- } = this ;
189-
190160 const inputBoxCls = {
191161 'devui-tags' : true ,
192162 'devui-form-control' : true ,
193163 'devui-dropdown-origin' : true ,
194164 'devui-dropdown-origin-open' : isInputBoxFocus ,
195- 'devui-disabled' : disabled ,
165+ 'devui-disabled' : props . disabled ,
196166 } ;
197167 const tagInputCls = {
198168 input : true ,
199169 'devui-input' : true ,
200170 'invalid-tag' : false ,
201171 } ;
202- const tagInputStyle = [ `display:${ disabled ? 'none' : 'block' } ;` ] ;
172+ const tagInputStyle = [ `display:${ props . disabled ? 'none' : 'block' } ;` ] ;
203173
204- const noDataTpl = < li class = "devui-suggestion-item devui-disabled" > { noData } </ li > ;
174+ const noDataTpl = < li class = "devui-suggestion-item devui-disabled" > { props . noData } </ li > ;
205175
206- return (
207- < div class = "devui-tags-host" tabindex = "-1" >
208- < div class = { inputBoxCls } style = { [ 'box-shadow: none;' ] } >
209- < ul class = "devui-tag-list" title = { disabled ? disabledText : '' } >
210- { tags . map ( ( tag , tagIdx ) => {
211- return (
212- < li class = "devui-tag-item" >
213- < span > { tag [ displayProperty ] } </ span >
214- { ! disabled && (
215- < a class = "remove-button" onMousedown = { ( $event ) => removeTag ( $event , tagIdx ) } >
216- { removeBtnSvg }
217- </ a >
218- ) }
219- </ li >
220- ) ;
221- } ) }
176+ return ( ) => ( < div class = "devui-tags-host" tabIndex = "-1" v-clickoutside = { closeSuggestion } >
177+ < div class = { inputBoxCls } style = { [ 'box-shadow: none;' ] } >
178+ < ul class = "devui-tag-list" title = { props . disabled ? props . disabledText : '' } >
179+ { props . tags . map ( ( tag , tagIdx ) => {
180+ return (
181+ < li class = "devui-tag-item" >
182+ < span > { tag [ props . displayProperty ] } </ span >
183+ { ! props . disabled && (
184+ < a class = "remove-button" onClick = { ( $event : Event ) => removeTag ( $event , tagIdx ) } >
185+ { removeBtnSvg }
186+ </ a >
187+ ) }
188+ </ li >
189+ ) ;
190+ } ) }
191+ </ ul >
192+ < input
193+ type = "text"
194+ ref = "tagInputRef"
195+ value = { tagInputVal . value }
196+ class = { tagInputCls }
197+ style = { tagInputStyle }
198+ onKeyDown = { onInputKeydown }
199+ onFocus = { onInputFocus }
200+ onBlur = { onInputBlur }
201+ onInput = { ( $event : InputEvent ) => onInput ( $event ) }
202+ placeholder = { isTagsLimit . value ? `${ props . maxTagsText || t ( 'maxTagsText' ) } ${ props . maxTags } ` : props . placeholder }
203+ spellCheck = { props . spellcheck }
204+ disabled = { isTagsLimit . value }
205+ />
206+ </ div >
207+ { isShowSuggestion . value && (
208+ < div class = "devui-tags-autocomplete devui-dropdown-menu" >
209+ < ul class = "devui-suggestion-list" >
210+ { mergedSuggestions . value . length === 0
211+ ? noDataTpl
212+ : mergedSuggestions . value . map ( ( item : Suggestion , index : number ) => {
213+ return (
214+ < li
215+ class = { { 'devui-suggestion-item' : true , selected : index === selectIndex . value } }
216+ onClick = { ( $event : Event ) => {
217+ onSuggestionItemClick ( $event , index ) ;
218+ } }
219+ >
220+ { item [ props . displayProperty ] }
221+ </ li >
222+ ) ;
223+ } ) }
222224 </ ul >
223- < input
224- type = "text"
225- ref = "tagInputRef"
226- value = { tagInputVal }
227- class = { tagInputCls }
228- style = { tagInputStyle }
229- onKeydown = { onInputKeydown }
230- onFocus = { onInputFocus }
231- onBlur = { onInputBlur }
232- onInput = { ( $event : InputEvent ) => onInput ( $event ) }
233- placeholder = { isTagsLimit ? `${ maxTagsText || t ( 'maxTagsText' ) } ${ maxTags } ` : placeholder }
234- spellcheck = { spellcheck }
235- disabled = { isTagsLimit }
236- />
237225 </ div >
238- { ! isShowSuggestion ? (
239- ''
240- ) : (
241- < div class = "devui-tags-autocomplete devui-dropdown-menu" >
242- < ul class = "devui-suggestion-list" >
243- { mergedSuggestions . length === 0
244- ? noDataTpl
245- : mergedSuggestions . map ( ( item : Suggestion , index : number ) => {
246- return (
247- < li
248- class = { { 'devui-suggestion-item' : true , selected : index === selectIndex } }
249- onMousedown = { ( $event ) => {
250- onSuggestionItemClick ( $event , index ) ;
251- } } >
252- { item [ displayProperty ] }
253- </ li >
254- ) ;
255- } ) }
256- </ ul >
257- </ div >
258- ) }
259- </ div >
260- ) ;
226+ ) }
227+ </ div > ) ;
261228 } ,
262229} ) ;
0 commit comments