selector.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. <template>
  2. <div
  3. class="el-selector"
  4. @click="handleFocus"
  5. >
  6. <div
  7. v-if="selected && selected.length >0"
  8. ref="tags"
  9. :style="{ 'max-width': inputWidth + 'px', width: '100%',overflow: 'hidden','white-space': 'ellipsis', 'word-break': 'break-all','text-overflow': 'ellipsis'}"
  10. class="el-selector__tags"
  11. >
  12. <transition-group @after-leave="resetInputHeight">
  13. <template v-for="(item,index) in selected">
  14. <el-tag
  15. type='primary'
  16. v-if="$utils.isNotEmpty(item) "
  17. :key="item+index"
  18. :closable="!selectDisabled"
  19. :size="collapseTagSize"
  20. disable-transitions
  21. @close="deleteTag(index)"
  22. >
  23. <span class="el-selector__tags-text">{{ item }}</span>
  24. </el-tag>
  25. </template>
  26. </transition-group>
  27. </div>
  28. <el-input
  29. ref="reference"
  30. v-model="selectedLabel"
  31. :disabled="selectDisabled"
  32. :validate-event="false"
  33. :size="selectSize"
  34. :placeholder="currentPlaceholder"
  35. type="text"
  36. :class="inputClass"
  37. @focus="handleFocus"
  38. @mouseenter.native="inputHovering = true"
  39. @mouseleave.native="inputHovering = false"
  40. >
  41. <i v-if="prefixIconClass" slot="prefix" :class="prefixIconClass" />
  42. </el-input>
  43. </div>
  44. </template>
  45. <script>
  46. import { addResizeListener, removeResizeListener } from '@/plugins/element-ui/src/utils/resize-event'
  47. import emitter from '@/plugins/element-ui/src/mixins/emitter'
  48. const sizeMap = {
  49. 'medium': 36,
  50. 'small': 32,
  51. 'mini': 28
  52. }
  53. export default {
  54. name: 'ibps-selector',
  55. mixins: [emitter],
  56. props: {
  57. items: {
  58. type: Array
  59. },
  60. placeholder: {
  61. type: String,
  62. default: '请选择'
  63. },
  64. multiple: { // 是否多选
  65. type: Boolean,
  66. default: false
  67. },
  68. icon: {
  69. type: String,
  70. default: 'el-icon-plus'
  71. },
  72. disabledIcon: {
  73. type: Boolean,
  74. default: false
  75. },
  76. disabled: {
  77. type: Boolean,
  78. default: false
  79. },
  80. readonly: {
  81. type: Boolean,
  82. default: false
  83. },
  84. showPlaceholder: { // 是否显示占位符
  85. type: Boolean,
  86. default: false
  87. },
  88. /**
  89. * 只读样式 【text original】
  90. */
  91. readonlyText: {
  92. type: String,
  93. default: 'original'
  94. },
  95. inputBorderStyle: {
  96. type: String
  97. },
  98. size: {
  99. type: String,
  100. default: 'mini'
  101. }
  102. },
  103. data() {
  104. return {
  105. query: '',
  106. inputLength: 20,
  107. inputWidth: 0,
  108. inputHovering: false,
  109. selected: []
  110. }
  111. },
  112. computed: {
  113. hasValue() {
  114. return this.items && this.items.length > 0
  115. },
  116. selectedLabel() {
  117. return this.hasValue ? ' ' : ''
  118. },
  119. prefixIconClass() {
  120. let classes = ['el-selector__caret', 'el-input__icon']
  121. if ((this.disabled || this.readonly) && !this.disabledIcon) {
  122. return
  123. }
  124. if (this.hasValue) {
  125. classes = [...classes, this.icon, 'is-show-close']
  126. } else {
  127. classes.push(this.icon)
  128. }
  129. return classes
  130. },
  131. inputClass() {
  132. let classes = []
  133. if (this.readonlyText === 'text') {
  134. classes = ['el-selector__readonly-text']
  135. }
  136. if (this.inputBorderStyle) {
  137. classes = [...classes, 'el-selector__' + this.inputBorderStyle]
  138. }
  139. return classes
  140. },
  141. selectDisabled() {
  142. return this.disabled || (this.elForm || {}).disabled
  143. },
  144. selectSize() {
  145. return this.size || (this.elFormItem || {}).elFormItemSize || (this.$ELEMENT || {}).size
  146. },
  147. collapseTagSize() {
  148. return ['small', 'mini'].indexOf(this.selectSize) > -1
  149. ? 'mini'
  150. : 'small'
  151. },
  152. currentPlaceholder() {
  153. if (!this.showPlaceholder && (this.readonly || this.selectDisabled)) {
  154. return ''
  155. }
  156. if (!this.items || (Array.isArray(this.items) && this.items.length === 0)) {
  157. return this.placeholder
  158. } else {
  159. return ''
  160. }
  161. }
  162. },
  163. watch: {
  164. items(val) {
  165. if(val){
  166. this.setSelected()
  167. }
  168. }
  169. },
  170. mounted() {
  171. addResizeListener(this.$el, this.handleResize)
  172. const reference = this.$refs.reference
  173. this.$nextTick(() => {
  174. if (reference && reference.$el) {
  175. this.inputWidth = reference.$el.getBoundingClientRect().width
  176. }
  177. })
  178. this.setSelected()
  179. },
  180. beforeDestroy() {
  181. removeResizeListener(this.$el, this.handleResize)
  182. },
  183. methods: {
  184. setSelected() {
  185. const result = []
  186. if (Array.isArray(this.items)) {
  187. this.items.forEach(item => {
  188. result.push(item)
  189. })
  190. }
  191. this.selected = result
  192. if (this.multiple) {
  193. this.$nextTick(this.resetInputHeight)
  194. }
  195. },
  196. resetInputWidth() {
  197. if (!this.$refs.reference) return
  198. this.inputWidth = this.$refs.reference.$el.getBoundingClientRect().width
  199. },
  200. resetInputHeight() {
  201. this.$nextTick(() => {
  202. if (!this.$refs.reference) return
  203. const inputEl = this.$refs.reference.$refs.input
  204. const tags = this.$refs.tags
  205. let height = sizeMap[this.selectSize] || 40
  206. if (this.selected.length !== 0) {
  207. height = Math.max((tags.clientHeight + (tags.clientHeight > height ? 6 : 0)), height)
  208. }
  209. inputEl.style.height = `${height}px`
  210. })
  211. },
  212. handleResize() {
  213. this.resetInputWidth()
  214. if (this.multiple) this.resetInputHeight()
  215. },
  216. handleFocus() {
  217. if (this.disabled) return
  218. this.$refs.reference.blur()
  219. this.$emit('click')
  220. },
  221. deleteTag(index) {
  222. this.$emit('remove', index)
  223. }
  224. }
  225. }
  226. </script>