我使用的element-ui的版本是1.4.13。

如上图所示,使用el-select组件,要实现可搜索、可复选、可创建条目时,展示样式是如上图所示,输入框的高度会撑开,影响页面布局,按照产品的需求,要调整为以下样式:

1、复选时,输入框中不以标签的形式展示,而是以字符串的形式展示。

2、超出部分显示省略号,并且鼠标移入显示提示框,用来展示全选的内容。

下面是源码修改部分:

(1)在select的props中添加了一个参数noTag用来控制是否以字符串形式显示输入框中的数据。添加了上面的el-popover标签,主要是文字超出时显示,这个后面再讲。底下的span标签就是在noTag参数为true时显示,data中添加currentSelLabel,用来显示处理后的多选数据,将数组转成字符串。

(2)在这里加了一个类,主要是方便后面加span标签的css样式。在select.css文件中的css样式如下面代码所示:

  1. .el-select__tags.noTags .noTagSpan{
  2. display: inline-block;
  3. font-size: 12px;
  4. width: 100%;
  5. padding:0 6px;
  6. overflow: hidden; /*自动隐藏文字*/
  7. text-overflow: ellipsis; /*文字隐藏后添加省略号*/
  8. white-space: nowrap; /*强制不换行*/
  9. }

(3)在noTag参数为true时显示class="noTagSpan"的span标签时,对应的el-tag标签就不再显示,如图所示,也需要在el-tag标签中添加noTag控制

(4)在setSelected方法中处理多选时的数据,将数组转成字符串,如下图所示:

(5)文字超出时显示提示框,效果如下:

需要在methods中添加如下方法:

  1. //当复选时文字超出输入框,出现提示框
  2. showSpanTooltip: function (event) {
  3. if(!this.showpop) return;
  4. var ev = event || window.event;
  5. var eventName = ev.target.className;
  6. if (eventName.indexOf('noTagSpan') != -1) {
  7. if (ev.target.offsetWidth < ev.target.scrollWidth) {
  8. var tooltip = this.$refs.textTooltip;
  9. tooltip.referenceElm = ev.target;
  10. tooltip.$refs.popper.style.display = 'none';
  11. tooltip.doDestroy();
  12. tooltip.showPopper = true;
  13. }
  14. }
  15. },
  16. //当复选时文字超出输入框,隐藏提示框
  17. hiddenSpanTooltip: function () {
  18. if(!this.showpop) return;
  19. const tooltip = this.$refs.textTooltip;
  20. if (tooltip) {
  21. tooltip.doClose() ;
  22. tooltip.doDestroy();
  23. }
  24. }

(6)多选时,可搜索。按照组件现在的,搜索框会在选项的下面出现,这样会撑开输入框的高度。

这里需要调整,将输入框放在下面的下拉菜单中,如图所示:



代码如下:



避免跟element原有的搜索框冲突,加了参数控制:

需要在select.css加入如下样式:

  1. .noTagInputDiv{
  2. border: 1px solid rgb(191, 193, 217);
  3. margin-left: -1px;
  4. margin-top:-30px;
  5. width: 100%;
  6. max-width: 185px;
  7. padding-right: 30px;
  8. overflow: hidden; /*自动隐藏文字*/
  9. text-overflow: ellipsis; /*文字隐藏后添加省略号*/
  10. white-space: nowrap; /*强制不换行*/
  11. }

这个时候需要在下拉出现的时候调整整个下拉菜单的位置,具体修改代码的地方如下:

在data中加入initPopperTop,用来记录初始时下拉菜单的位置:

1、在watch中的visible中



2、在watch中的query中



3、methods的resetInputHeight方法中

(7)多选时并且可搜索时,如果条目不存在时,创建条目,并且显示在下拉菜单中,这样可以通过反选删除选中的数据。

1、添加el-option标签,用来显示创建的条目。在data中添加mulOptions数组,用来记录创建的条目。

2、handleOptionSelect方法中处理数据

3、在option.vue的props中添加optcreated

ok,所有的就改完了,效果如图所示:

以下附源码:

  1. <template>
  2. <div
  3. class="el-select"
  4. v-clickoutside="handleClose">
  5. <div
  6. class="el-select__tags"
  7. :class="{'noTags':noTag}"
  8. v-if="multiple"
  9. @click.stop="toggleMenu"
  10. ref="tags"
  11. :style="{ 'max-width': inputWidth - 32 + 'px' }">
  12. <transition-group @after-leave="resetInputHeight">
  13. <el-tag
  14. v-if="!noTag"
  15. v-for="item in selected"
  16. :key="getValueKey(item)"
  17. closable
  18. :hit="item.hitState"
  19. type="primary"
  20. @close="deleteTag($event, item)"
  21. close-transition>
  22. <span class="el-select__tags-text">{{ item.currentLabel }}</span>
  23. </el-tag>
  24. </transition-group>
  25. <el-popover
  26. ref="textTooltip"
  27. placement="top-start"
  28. width="200"
  29. trigger="hover"
  30. :content="currentSelLabel">
  31. </el-popover>
  32. <span v-if="noTag" class="noTagSpan"
  33. @mouseenter="showSpanTooltip($event)" @mouseleave="hiddenSpanTooltip($event)">
  34. {{currentSelLabel}}
  35. </span>
  36. <input
  37. type="text"
  38. class="el-select__input"
  39. :class="`is-${ size }`"
  40. @focus="visible = true"
  41. :disabled="disabled"
  42. @keyup="managePlaceholder"
  43. @keydown="resetInputState"
  44. @keydown.down.prevent="navigateOptions('next')"
  45. @keydown.up.prevent="navigateOptions('prev')"
  46. @keydown.enter.prevent="selectOption"
  47. @keydown.esc.stop.prevent="visible = false"
  48. @keydown.delete="deletePrevTag"
  49. v-model="query"
  50. :debounce="remote ? 300 : 0"
  51. v-if="filterable && !noTag"
  52. :style="{ width: inputLength + 'px', 'max-width': inputWidth - 42 + 'px' }"
  53. ref="input">
  54. </div>
  55. <el-input
  56. ref="reference"
  57. v-model="selectedLabel"
  58. type="text"
  59. :placeholder="currentPlaceholder"
  60. :name="name"
  61. :size="size"
  62. :disabled="disabled"
  63. :readonly="!filterable || multiple"
  64. :validate-event="false"
  65. @focus="handleFocus"
  66. @click="handleIconClick"
  67. @mousedown.native="handleMouseDown"
  68. @keyup.native="debouncedOnInputChange"
  69. @keydown.native.down.prevent="navigateOptions('next')"
  70. @keydown.native.up.prevent="navigateOptions('prev')"
  71. @keydown.native.enter.prevent="selectOption"
  72. @keydown.native.esc.stop.prevent="visible = false"
  73. @keydown.native.tab="visible = false"
  74. @paste.native="debouncedOnInputChange"
  75. @mouseenter.native="inputHovering = true"
  76. @mouseleave.native="inputHovering = false"
  77. :icon="iconClass">
  78. </el-input>
  79. <transition
  80. name="el-zoom-in-top"
  81. @before-enter="handleMenuEnter"
  82. @after-leave="doDestroy">
  83. <el-select-menu
  84. ref="popper"
  85. v-show="visible && emptyText !== false">
  86. <!--有noTag时搜索框在下面显示-->
  87. <div v-if="filterable && noTag && multiple" :class="{'noTagInputDiv':noTag}">
  88. <input
  89. type="text"
  90. class="el-select__input"
  91. :class="`is-${ size }`"
  92. @focus="visible = true"
  93. :disabled="disabled"
  94. @keyup="managePlaceholder"
  95. @keydown="resetInputState"
  96. @keydown.down.prevent="navigateOptions('next')"
  97. @keydown.up.prevent="navigateOptions('prev')"
  98. @keydown.enter.prevent="selectOption"
  99. @keydown.esc.stop.prevent="visible = false"
  100. @keydown.delete="deletePrevTag"
  101. v-model="query"
  102. :debounce="remote ? 300 : 0"
  103. v-if="filterable && noTag && multiple"
  104. :style="{ width: inputLength + 'px', 'max-width': inputWidth - 42 + 'px' }"
  105. ref="input">
  106. </div>
  107. <el-input v-model="search" @focus="visible = true" v-if="searchable"></el-input>
  108. <el-scrollbar
  109. tag="ul"
  110. wrap-class="el-select-dropdown__wrap"
  111. view-class="el-select-dropdown__list"
  112. :class="{ 'is-empty': !allowCreate && filteredOptionsCount === 0 }"
  113. v-show="options.length > 0 && !loading">
  114. <el-option
  115. :value="query"
  116. created
  117. v-if="showNewOption">
  118. </el-option>
  119. <el-option
  120. v-if="noTag && multiple && allowCreate"
  121. v-for="item in mulOptions"
  122. :key="item.currentLabel"
  123. :optcreated="item.optcreated"
  124. :value="item.currentLabel">
  125. </el-option>
  126. <slot></slot>
  127. </el-scrollbar>
  128. <p class="el-select-dropdown__empty" v-if="emptyText && (allowCreate && options.length === 0 || !allowCreate)">{{ emptyText }}</p>
  129. </el-select-menu>
  130. </transition>
  131. </div>
  132. </template>
  133. <script type="text/babel">
  134. import Emitter from 'element-ui/src/mixins/emitter';
  135. import Locale from 'element-ui/src/mixins/locale';
  136. import ElInput from 'element-ui/packages/input';
  137. import ElSelectMenu from './select-dropdown.vue';
  138. import ElOption from './option.vue';
  139. import ElTag from 'element-ui/packages/tag';
  140. import ElScrollbar from 'element-ui/packages/scrollbar';
  141. import debounce from 'throttle-debounce/debounce';
  142. import Clickoutside from 'element-ui/src/utils/clickoutside';
  143. import { addClass, removeClass, hasClass } from 'element-ui/src/utils/dom';
  144. import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event';
  145. import { t } from 'element-ui/src/locale';
  146. import scrollIntoView from 'element-ui/src/utils/scroll-into-view';
  147. import { getValueByPath } from 'element-ui/src/utils/util';
  148. const sizeMap = {
  149. 'large': 42,
  150. 'small': 30,
  151. 'mini': 22
  152. };
  153. export default {
  154. mixins: [Emitter, Locale],
  155. name: 'ElSelect',
  156. componentName: 'ElSelect',
  157. computed: {
  158. iconClass() {
  159. let criteria = this.clearable &&
  160. !this.disabled &&
  161. this.inputHovering &&
  162. !this.multiple &&
  163. this.value !== undefined &&
  164. this.value !== '';
  165. return criteria ? 'circle-close is-show-close' : (this.remote && this.filterable ? '' : 'caret-top');
  166. },
  167. debounce() {
  168. return this.remote ? 300 : 0;
  169. },
  170. emptyText() {
  171. if (this.loading) {
  172. return this.loadingText || this.t('el.select.loading');
  173. } else {
  174. if (this.remote && this.query === '' && this.options.length === 0) return false;
  175. if (this.filterable && this.options.length > 0 && this.filteredOptionsCount === 0) {
  176. return this.noMatchText || this.t('el.select.noMatch');
  177. }
  178. if (this.options.length === 0) {
  179. return this.noDataText || this.t('el.select.noData');
  180. }
  181. }
  182. return null;
  183. },
  184. showNewOption() {
  185. let hasExistingOption = this.options.filter(option => !option.created)
  186. .some(option => option.currentLabel === this.query);
  187. return this.filterable && this.allowCreate && this.query !== '' && !hasExistingOption;
  188. }
  189. },
  190. components: {
  191. ElInput,
  192. ElSelectMenu,
  193. ElOption,
  194. ElTag,
  195. ElScrollbar
  196. },
  197. directives: { Clickoutside },
  198. props: {
  199. name: String,
  200. value: {
  201. required: true
  202. },
  203. size: String,
  204. disabled: Boolean,
  205. clearable: Boolean,
  206. filterable: Boolean,
  207. searchable: Boolean,
  208. allowCreate: Boolean,
  209. noTag:Boolean, //多选的时候是否以字符串形式展示 f
  210. showpop: { //是否在文字超出span标签的时候显示提示 f
  211. type: Boolean,
  212. default: true
  213. },
  214. loading: Boolean,
  215. popperClass: String,
  216. remote: Boolean,
  217. loadingText: String,
  218. noMatchText: String,
  219. noDataText: String,
  220. remoteMethod: Function,
  221. filterMethod: Function,
  222. multiple: Boolean,
  223. multipleLimit: {
  224. type: Number,
  225. default: 0
  226. },
  227. placeholder: {
  228. type: String,
  229. default() {
  230. return t('el.select.placeholder');
  231. }
  232. },
  233. defaultFirstOption: Boolean,
  234. valueKey: {
  235. type: String,
  236. default: 'value'
  237. }
  238. },
  239. data() {
  240. return {
  241. options: [],
  242. cachedOptions: [],
  243. createdLabel: null,
  244. createdSelected: false,
  245. selected: this.multiple ? [] : {},
  246. isSelect: true,
  247. inputLength: 20,
  248. inputWidth: 0,
  249. cachedPlaceHolder: '',
  250. optionsCount: 0,
  251. filteredOptionsCount: 0,
  252. visible: false,
  253. selectedLabel: '',
  254. hoverIndex: -1,
  255. query: '',
  256. search: '',
  257. optionsAllDisabled: false,
  258. inputHovering: false,
  259. currentPlaceholder: '',
  260. currentSelLabel:'', //多选时以字符串形式展示的标签 f
  261. initPopperTop:0, //初始时下拉框的位置 f
  262. mulOptions:[] //多选时添加的数据 f
  263. };
  264. },
  265. watch: {
  266. placeholder(val) {
  267. this.cachedPlaceHolder = this.currentPlaceholder = val;
  268. },
  269. value(val) {
  270. if (this.multiple) {
  271. this.resetInputHeight();
  272. if (val.length > 0 || (this.$refs.input && this.query !== '')) {
  273. this.currentPlaceholder = '';
  274. } else {
  275. this.currentPlaceholder = this.cachedPlaceHolder;
  276. }
  277. }
  278. this.setSelected();
  279. if (this.filterable && !this.multiple) {
  280. this.inputLength = 20;
  281. }
  282. this.$emit('change', val);
  283. this.dispatch('ElFormItem', 'el.form.change', val);
  284. },
  285. search(val) {
  286. if (this.searchable) {
  287. this.$emit('search-change', val);
  288. }
  289. },
  290. query(val) {
  291. this.$nextTick(() => {
  292. if (this.visible) {
  293. this.broadcast('ElSelectDropdown', 'updatePopper');
  294. //multiple、noTag、filterable 同时存在时,调整下拉框位置
  295. if(this.multiple && this.noTag && this.filterable){
  296. this.$nextTick(()=>{
  297. var popperTop = window.getComputedStyle? window.getComputedStyle(this.$refs.popper.$el).top : this.$refs.popper.$el.currentStyle.top;
  298. this.$refs.popper.$el.style.top = parseInt(popperTop)+ 25+'px';
  299. })
  300. }
  301. }
  302. });
  303. this.hoverIndex = -1;
  304. if (this.multiple && this.filterable) {
  305. this.inputLength = this.$refs.input.value.length * 15 + 20;
  306. this.managePlaceholder();
  307. this.resetInputHeight();
  308. }
  309. if (this.remote && typeof this.remoteMethod === 'function') {
  310. this.hoverIndex = -1;
  311. this.remoteMethod(val);
  312. this.broadcast('ElOption', 'resetIndex');
  313. } else if (typeof this.filterMethod === 'function') {
  314. this.filterMethod(val);
  315. this.broadcast('ElOptionGroup', 'queryChange');
  316. } else {
  317. this.filteredOptionsCount = this.optionsCount;
  318. this.broadcast('ElOption', 'queryChange', val);
  319. this.broadcast('ElOptionGroup', 'queryChange');
  320. }
  321. if (this.defaultFirstOption && (this.filterable || this.remote) && this.filteredOptionsCount) {
  322. this.checkDefaultFirstOption();
  323. }
  324. },
  325. visible(val) {
  326. if (!val) {
  327. this.$refs.reference.$el.querySelector('input').blur();
  328. this.handleIconHide();
  329. this.broadcast('ElSelectDropdown', 'destroyPopper');
  330. if (this.$refs.input) {
  331. this.$refs.input.blur();
  332. }
  333. this.query = '';
  334. this.selectedLabel = '';
  335. this.inputLength = 20;
  336. this.resetHoverIndex();
  337. this.$nextTick(() => {
  338. if (this.$refs.input &&
  339. this.$refs.input.value === '' &&
  340. this.selected.length === 0) {
  341. this.currentPlaceholder = this.cachedPlaceHolder;
  342. }
  343. });
  344. if (!this.multiple) {
  345. if (this.selected) {
  346. if (this.filterable && this.allowCreate &&
  347. this.createdSelected && this.createdLabel) {
  348. this.selectedLabel = this.createdLabel;
  349. } else {
  350. this.selectedLabel = this.selected.currentLabel;
  351. }
  352. if (this.filterable) this.query = this.selectedLabel;
  353. }
  354. }
  355. } else {
  356. this.handleIconShow();
  357. this.broadcast('ElSelectDropdown', 'updatePopper');
  358. //multiple、noTag、filterable 同时存在时,调整下拉框位置,并记录初始下拉框的位置
  359. if(this.multiple && this.noTag && this.filterable){
  360. this.$nextTick(()=>{
  361. this.$refs.input.focus();
  362. var popperTop = window.getComputedStyle? window.getComputedStyle(this.$refs.popper.$el).top : this.$refs.popper.$el.currentStyle.top;
  363. //记录初始下拉框的位置
  364. this.initPopperTop = popperTop;
  365. this.$refs.popper.$el.style.top = parseInt(popperTop) + 25 +'px';
  366. })
  367. }
  368. if (this.filterable) {
  369. this.query = this.selectedLabel;
  370. if (this.multiple) {
  371. this.$refs.input.focus();
  372. } else {
  373. if (!this.remote) {
  374. this.broadcast('ElOption', 'queryChange', '');
  375. this.broadcast('ElOptionGroup', 'queryChange');
  376. }
  377. this.broadcast('ElInput', 'inputSelect');
  378. }
  379. }
  380. }
  381. this.$emit('visible-change', val);
  382. },
  383. options(val) {
  384. if (this.$isServer) return;
  385. this.optionsAllDisabled = val.length === val.filter(item => item.disabled === true).length;
  386. if (this.multiple) {
  387. this.resetInputHeight();
  388. }
  389. let inputs = this.$el.querySelectorAll('input');
  390. if ([].indexOf.call(inputs, document.activeElement) === -1) {
  391. this.setSelected();
  392. }
  393. if (this.defaultFirstOption && (this.filterable || this.remote) && this.filteredOptionsCount) {
  394. this.checkDefaultFirstOption();
  395. }
  396. }
  397. },
  398. methods: {
  399. //当复选时文字超出输入框,出现提示框
  400. showSpanTooltip: function (event) {
  401. if(!this.showpop) return;
  402. var ev = event || window.event;
  403. var eventName = ev.target.className;
  404. if (eventName.indexOf('noTagSpan') != -1) {
  405. if (ev.target.offsetWidth < ev.target.scrollWidth) {
  406. var tooltip = this.$refs.textTooltip;
  407. tooltip.referenceElm = ev.target;
  408. tooltip.$refs.popper.style.display = 'none';
  409. tooltip.doDestroy();
  410. tooltip.showPopper = true;
  411. }
  412. }
  413. },
  414. //当复选时文字超出输入框,隐藏提示框
  415. hiddenSpanTooltip: function () {
  416. if(!this.showpop) return;
  417. const tooltip = this.$refs.textTooltip;
  418. if (tooltip) {
  419. tooltip.doClose() ;
  420. tooltip.doDestroy();
  421. }
  422. },
  423. handleIconHide() {
  424. let icon = this.$el.querySelector('.el-input__icon');
  425. if (icon) {
  426. removeClass(icon, 'is-reverse');
  427. }
  428. },
  429. handleIconShow() {
  430. let icon = this.$el.querySelector('.el-input__icon');
  431. if (icon && !hasClass(icon, 'el-icon-circle-close')) {
  432. addClass(icon, 'is-reverse');
  433. }
  434. },
  435. scrollToOption(className = 'selected') {
  436. const menu = this.$refs.popper.$el.querySelector('.el-select-dropdown__wrap');
  437. scrollIntoView(menu, menu.getElementsByClassName(className)[0]);
  438. },
  439. handleMenuEnter() {
  440. this.$nextTick(() => this.scrollToOption());
  441. },
  442. getOption(value) {
  443. let option;
  444. const type = typeof value;
  445. const isObject = type !== 'string' && type !== 'number' && type !== 'boolean';
  446. for (let i = this.cachedOptions.length - 1; i >= 0; i--) {
  447. const cachedOption = this.cachedOptions[i];
  448. const isEqual = isObject
  449. ? this.getValueByPath(cachedOption.value, this.valueKey) === this.getValueByPath(value, this.valueKey)
  450. : cachedOption.value === value;
  451. if (isEqual) {
  452. option = cachedOption;
  453. break;
  454. }
  455. }
  456. if (option) return option;
  457. const label = !isObject
  458. ? value : '';
  459. let newOption = {
  460. value: value,
  461. currentLabel: label
  462. };
  463. if (this.multiple) {
  464. newOption.hitState = false;
  465. }
  466. return newOption;
  467. },
  468. getValueByPath(object, prop) {
  469. prop = prop || '';
  470. const paths = prop.split('.');
  471. let current = object;
  472. let result = null;
  473. for (let i = 0, j = paths.length; i < j; i++) {
  474. const path = paths[i];
  475. if (current !== 0 && !current) break;
  476. if (i === j - 1) {
  477. result = current[path];
  478. break;
  479. }
  480. current = current[path];
  481. }
  482. return result;
  483. },
  484. setSelected() {
  485. if (!this.multiple) {
  486. let option = this.getOption(this.value);
  487. if (option.created) {
  488. this.createdLabel = option.currentLabel;
  489. this.createdSelected = true;
  490. } else {
  491. this.createdSelected = false;
  492. }
  493. this.selectedLabel = option.currentLabel;
  494. this.selected = option;
  495. if (this.filterable) this.query = this.selectedLabel;
  496. return;
  497. }
  498. let result = [];
  499. if (Array.isArray(this.value)) {
  500. this.value.forEach(value => {
  501. result.push(this.getOption(value));
  502. });
  503. }
  504. this.selected = result;
  505. //复选时,选项以字符串的形式显示,此处处理显示数据,数组转成字符串
  506. if(this.noTag && this.multiple){
  507. var arr = [];
  508. if(this.selected && this.selected.length){
  509. this.selected.forEach(function(item){
  510. arr.push(item.currentLabel);
  511. })
  512. }
  513. this.currentSelLabel = arr.join(',');
  514. }
  515. this.$nextTick(() => {
  516. this.resetInputHeight();
  517. });
  518. },
  519. handleFocus() {
  520. this.visible = true;
  521. },
  522. handleIconClick(event) {
  523. if (this.iconClass.indexOf('circle-close') > -1) {
  524. this.deleteSelected(event);
  525. } else {
  526. this.toggleMenu();
  527. }
  528. },
  529. handleMouseDown(event) {
  530. if (event.target.tagName !== 'INPUT') return;
  531. if (this.visible) {
  532. this.handleClose();
  533. event.preventDefault();
  534. }
  535. },
  536. doDestroy() {
  537. this.$refs.popper && this.$refs.popper.doDestroy();
  538. this.dropdownUl = null;
  539. },
  540. handleClose() {
  541. this.visible = false;
  542. },
  543. toggleLastOptionHitState(hit) {
  544. if (!Array.isArray(this.selected)) return;
  545. const option = this.selected[this.selected.length - 1];
  546. if (!option) return;
  547. if (hit === true || hit === false) {
  548. option.hitState = hit;
  549. return hit;
  550. }
  551. option.hitState = !option.hitState;
  552. return option.hitState;
  553. },
  554. deletePrevTag(e) {
  555. if (e.target.value.length <= 0 && !this.toggleLastOptionHitState()) {
  556. const value = this.value.slice();
  557. value.pop();
  558. this.$emit('input', value);
  559. }
  560. },
  561. managePlaceholder() {
  562. if (this.currentPlaceholder !== '') {
  563. this.currentPlaceholder = this.$refs.input.value ? '' : this.cachedPlaceHolder;
  564. }
  565. },
  566. resetInputState(e) {
  567. if (e.keyCode !== 8) this.toggleLastOptionHitState(false);
  568. this.inputLength = this.$refs.input.value.length * 15 + 20;
  569. this.resetInputHeight();
  570. },
  571. resetInputHeight() {
  572. this.$nextTick(() => {
  573. if (!this.$refs.reference) return;
  574. let inputChildNodes = this.$refs.reference.$el.childNodes;
  575. let input = [].filter.call(inputChildNodes, item => item.tagName === 'INPUT')[0];
  576. input.style.height = Math.max(this.$refs.tags.clientHeight + 6, sizeMap[this.size] || 36) + 'px';
  577. if (this.visible && this.emptyText !== false) {
  578. this.broadcast('ElSelectDropdown', 'updatePopper');
  579. //multiple、noTag、filterable 同时存在时,判断当前下拉框是否在初始位置,不在则调整下拉框位置
  580. if(this.multiple && this.noTag && this.filterable){
  581. this.$nextTick(()=>{
  582. var popperTop = window.getComputedStyle? window.getComputedStyle(this.$refs.popper.$el).top : this.$refs.popper.$el.currentStyle.top;
  583. if(popperTop <= this.initPopperTop){
  584. this.$refs.popper.$el.style.top = parseInt(popperTop)+ 25+'px';
  585. }
  586. })
  587. }
  588. }
  589. });
  590. },
  591. resetHoverIndex() {
  592. setTimeout(() => {
  593. if (!this.multiple) {
  594. this.hoverIndex = this.options.indexOf(this.selected);
  595. } else {
  596. if (this.selected.length > 0) {
  597. this.hoverIndex = Math.min.apply(null, this.selected.map(item => this.options.indexOf(item)));
  598. } else {
  599. this.hoverIndex = -1;
  600. }
  601. }
  602. }, 300);
  603. },
  604. handleOptionSelect(option) {
  605. if (this.multiple) {
  606. const value = this.value.slice();
  607. const optionIndex = this.getValueIndex(value, option.value);
  608. if (optionIndex > -1) {
  609. //multiple、allowCreate存在,复选时可以向下拉列表中删除数据
  610. if(this.allowCreate && option.optcreated && this.noTag){
  611. if(this.mulOptions && this.mulOptions.length){
  612. this.mulOptions.forEach((item,index)=>{
  613. if(item.currentValue == option.currentValue){
  614. this.mulOptions.splice(index, 1);
  615. }
  616. })
  617. }
  618. }
  619. value.splice(optionIndex, 1);
  620. } else if (this.multipleLimit <= 0 || value.length < this.multipleLimit) {
  621. value.push(option.value);
  622. }
  623. this.$emit('input', value);
  624. if (option.created) {
  625. //multiple、allowCreate存在,复选时可以像下拉列表中添加数据
  626. if(this.allowCreate && this.noTag && !option.optcreated){
  627. var obj = {
  628. optcreated:true,
  629. created:option.created,
  630. currentLabel:option.currentLabel,
  631. currentValue:option.currentValue
  632. }
  633. this.mulOptions.push(obj);
  634. }
  635. this.query = '';
  636. this.inputLength = 20;
  637. }
  638. if (this.filterable) this.$refs.input.focus();
  639. } else {
  640. this.$emit('input', option.value);
  641. this.visible = false;
  642. }
  643. this.$nextTick(() => this.scrollToOption());
  644. },
  645. getValueIndex(arr = [], value) {
  646. const type = typeof value;
  647. const isObject = type !== 'string' && type !== 'number' && type !== 'boolean';
  648. if (!isObject) {
  649. return arr.indexOf(value);
  650. } else {
  651. const valueKey = this.valueKey;
  652. let index = -1;
  653. arr.some((item, i) => {
  654. if (getValueByPath(item, valueKey) === getValueByPath(value, valueKey)) {
  655. index = i;
  656. return true;
  657. }
  658. return false;
  659. });
  660. return index;
  661. }
  662. },
  663. toggleMenu() {
  664. if (this.filterable && this.query === '' && this.visible) {
  665. return;
  666. }
  667. if (!this.disabled) {
  668. this.visible = !this.visible;
  669. }
  670. },
  671. navigateOptions(direction) {
  672. if (!this.visible) {
  673. this.visible = true;
  674. return;
  675. }
  676. if (this.options.length === 0 || this.filteredOptionsCount === 0) return;
  677. this.optionsAllDisabled = this.options.length === this.options.filter(item => item.disabled === true).length;
  678. if (!this.optionsAllDisabled) {
  679. if (direction === 'next') {
  680. this.hoverIndex++;
  681. if (this.hoverIndex === this.options.length) {
  682. this.hoverIndex = 0;
  683. }
  684. if (this.options[this.hoverIndex].disabled === true ||
  685. this.options[this.hoverIndex].groupDisabled === true ||
  686. !this.options[this.hoverIndex].visible) {
  687. this.navigateOptions('next');
  688. }
  689. }
  690. if (direction === 'prev') {
  691. this.hoverIndex--;
  692. if (this.hoverIndex < 0) {
  693. this.hoverIndex = this.options.length - 1;
  694. }
  695. if (this.options[this.hoverIndex].disabled === true ||
  696. this.options[this.hoverIndex].groupDisabled === true ||
  697. !this.options[this.hoverIndex].visible) {
  698. this.navigateOptions('prev');
  699. }
  700. }
  701. }
  702. this.$nextTick(() => this.scrollToOption('hover'));
  703. },
  704. selectOption() {
  705. if (this.options[this.hoverIndex]) {
  706. this.handleOptionSelect(this.options[this.hoverIndex]);
  707. }
  708. },
  709. deleteSelected(event) {
  710. event.stopPropagation();
  711. this.$emit('input', '');
  712. this.visible = false;
  713. this.$emit('clear');
  714. },
  715. deleteTag(event, tag) {
  716. let index = this.selected.indexOf(tag);
  717. if (index > -1 && !this.disabled) {
  718. const value = this.value.slice();
  719. value.splice(index, 1);
  720. this.$emit('input', value);
  721. this.$emit('remove-tag', tag);
  722. }
  723. event.stopPropagation();
  724. },
  725. onInputChange() {
  726. if (this.filterable) {
  727. this.query = this.selectedLabel;
  728. }
  729. },
  730. onOptionDestroy(option) {
  731. this.optionsCount--;
  732. this.filteredOptionsCount--;
  733. let index = this.options.indexOf(option);
  734. if (index > -1) {
  735. this.options.splice(index, 1);
  736. }
  737. this.broadcast('ElOption', 'resetIndex');
  738. },
  739. resetInputWidth() {
  740. this.inputWidth = this.$refs.reference.$el.getBoundingClientRect().width;
  741. },
  742. handleResize() {
  743. this.resetInputWidth();
  744. if (this.multiple) this.resetInputHeight();
  745. },
  746. checkDefaultFirstOption() {
  747. this.hoverIndex = -1;
  748. for (let i = 0; i !== this.options.length; ++i) {
  749. const option = this.options[i];
  750. if (this.query) {
  751. // pick first options that passes the filter
  752. if (!option.disabled && !option.groupDisabled && option.visible) {
  753. this.hoverIndex = i;
  754. break;
  755. }
  756. } else {
  757. // pick currently selected option
  758. if (option.itemSelected) {
  759. this.hoverIndex = i;
  760. break;
  761. }
  762. }
  763. }
  764. },
  765. getValueKey(item) {
  766. const type = typeof item.value;
  767. if (type === 'number' || type === 'string') {
  768. return item.value;
  769. } else {
  770. return getValueByPath(item.value, this.valueKey);
  771. }
  772. }
  773. },
  774. created() {
  775. this.cachedPlaceHolder = this.currentPlaceholder = this.placeholder;
  776. if (this.multiple && !Array.isArray(this.value)) {
  777. this.$emit('input', []);
  778. }
  779. if (!this.multiple && Array.isArray(this.value)) {
  780. this.$emit('input', '');
  781. }
  782. this.setSelected();
  783. this.debouncedOnInputChange = debounce(this.debounce, () => {
  784. this.onInputChange();
  785. });
  786. this.$on('handleOptionClick', this.handleOptionSelect);
  787. this.$on('onOptionDestroy', this.onOptionDestroy);
  788. this.$on('setSelected', this.setSelected);
  789. },
  790. mounted() {
  791. if (this.multiple && Array.isArray(this.value) && this.value.length > 0) {
  792. this.currentPlaceholder = '';
  793. }
  794. addResizeListener(this.$el, this.handleResize);
  795. if (this.remote && this.multiple) {
  796. this.resetInputHeight();
  797. }
  798. this.$nextTick(() => {
  799. if (this.$refs.reference && this.$refs.reference.$el) {
  800. this.inputWidth = this.$refs.reference.$el.getBoundingClientRect().width;
  801. }
  802. });
  803. },
  804. beforeDestroy() {
  805. if (this.$el && this.handleResize) removeResizeListener(this.$el, this.handleResize);
  806. }
  807. };
  808. // dialog_ref
  809. </script>

element-ui select组件中复选时以字符串形式显示的更多相关文章

  1. 使用 Element UI Select 组件的 value-key 属性,让绑定值可以为一个对象

    EsunR 2019-11-07 12:14:42  12264  收藏 6 分类专栏: Vue 文章标签: element-ui 版权 当我们使用 Elemet UI 的选择组件进行多选时,Sele ...

  2. element ui step组件在另一侧加时间轴显示

    这是我开发的时候遇到的一个问题:项目需要在步骤条(竖直方向)的另一侧加时间显示,但是我在element ui 的step组件中一直没找着设置方法,所以就自己想了个办法加进来,效果如下: 代码如下,先上 ...

  3. element ui select组件和table做分页完整功能和二级联动效果

    <template> <div class="index_box"> <div class="search_box"> &l ...

  4. [转]vue Element UI走马灯组件重写

    https://blog.csdn.net/u013750989/article/details/82885482 1.element ui走马灯组件 -- carousel分析一波源代码:carou ...

  5. Element UI表格组件技巧:如何简洁实现跨页勾选、跨页统计功能

    业务场景 在使用Element UI的Table组件时,常常面对这样的业务需求: 表格数据的每一项都要提供勾选框,当切换分页时,能够记忆所有页面勾选的数据,以实现批量提交不同页面勾选数据的功能.并且, ...

  6. 封装一个优雅的element ui表格组件

    现在做后台系统用vue + elementUI 的越来越多,那element ui的 el-table 组件肯定也离不开.虽然element ui的table组件很好.但是表格和分页是分离的.每次写表 ...

  7. Element UI table组件源码分析

    本文章从如下图所示的最基本的table入手,分析table组件源代码.本人已经对table组件原来的源码进行削减,源码点击这里下载.本文只对重要的代码片段进行讲解,推荐下载代码把项目运行起来,跟着文章 ...

  8. 普通element ui table组件的使用

    1.使用基础的element ui 的table的基础使用 首先,使用前要先引用element库到项目中,可以直接引入element的js和css或者在vue项目下按需加载不同的组件 废话不多说,直接 ...

  9. Element UI 中组件this.$message报错

    最近在做毕设的时候,用Element UI中的消息提示message一直报以下的错误: 展示的效果也不好看,没有图标什么的: 但我明明有在main.js引入了element-ui 呀,因为毕设时间很赶 ...

随机推荐

  1. Centos系统安装InfluxDB

    概述安装influxDB时需要root用户或者管理员权限. 端口默认情况下,InfluxDB会使用如下的端口: * TCP8086端口是服务器监听端口,对HTTP API响应 * TCP8088端口是 ...

  2. Android框架式编程之MVP架构

    MVP(Model-View-Presenter)模式.是将APP的结构分为三层:View - Presenter - Model. View 1. 提供UI交互 2. 在presenter的控制下修 ...

  3. 如何在cygwin中运行crontab定时脚本[利刃篇]

    用到cygwin,自然是希望能多处理一些类似linux的任务了,那就自然少不了定时任务crontab,看到网上教程不少,自己运行一个测试却也不那么容易,下面就记录我的安装过程,以供参考吧! 1.首先, ...

  4. maven 下载镜像文件卡,下载pom文件慢的问题

    问题原因: maven默认的镜像库URL为 http://maven.net.cn/content/groups/public/ 由于网络原因,可能导致响应速度超级慢,或者无法效应: 解决方法: 配置 ...

  5. spring boot log4j2配置

    [传送门]:log4j官网配置文件详解 1. 排除 spring boot 自带的  spring-boot-starter-logging 依赖 <dependency> <gro ...

  6. MessageBeep - Play a System sound

    There is a interesting function which can play a System sound. First let's see the WinAPI. //声明: Mes ...

  7. 凉凉了,Eureka 宣布闭源,Spring Cloud 何去何从?

    今年 Dubbo 活了,并且被 Apache 收了.同时很不幸,Spring Cloud 下的 Netflix Eureka 组件项目居然宣布闭源了.. 已经从 Dubbo 迁移至 Spring Cl ...

  8. js中break、continue和return的一般用法总结

    break break :终止break的整个循环体,包括内部所有循环.但对循环体外部的循环不影响. for(let i = 0;i<2;i++){ for(let j = 0;j<2;j ...

  9. hdu 6086 -- Rikka with String(AC自动机 + 状压DP)

    题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...

  10. 从 Secure Element 到 Android KeyStore

    忽如一夜春风来,智能手机来到每个人的手上,我们用它支付.理财.娱乐.工作.记录生活.存储私密信息.乘坐公共交通.开启家门.控制汽车....智能手机是如此的重要,不知天天把它拿在手上的你,是否关心过它是 ...