Commit 3e855e34df94d586c7d3ebbd7c59cb12f5a0f49d

Authored by 梁灏
1 parent f94309af

fixed #46

fixed #46
src/components/select/select.vue
@@ -26,7 +26,7 @@ @@ -26,7 +26,7 @@
26 </div> 26 </div>
27 <Dropdown v-show="visible" transition="slide-up" v-ref:dropdown> 27 <Dropdown v-show="visible" transition="slide-up" v-ref:dropdown>
28 <ul v-show="notFound" :class="[prefixCls + '-not-found']"><li>{{ notFoundText }}</li></ul> 28 <ul v-show="notFound" :class="[prefixCls + '-not-found']"><li>{{ notFoundText }}</li></ul>
29 - <ul v-else :class="[prefixCls + '-dropdown-list']"><slot></slot></ul> 29 + <ul v-else :class="[prefixCls + '-dropdown-list']" v-el:options><slot></slot></ul>
30 </Dropdown> 30 </Dropdown>
31 </div> 31 </div>
32 </template> 32 </template>
@@ -34,7 +34,7 @@ @@ -34,7 +34,7 @@
34 import Icon from '../icon'; 34 import Icon from '../icon';
35 import Dropdown from './dropdown.vue'; 35 import Dropdown from './dropdown.vue';
36 import clickoutside from '../../directives/clickoutside'; 36 import clickoutside from '../../directives/clickoutside';
37 - import { oneOf } from '../../utils/assist'; 37 + import { oneOf, MutationObserver } from '../../utils/assist';
38 38
39 const prefixCls = 'ivu-select'; 39 const prefixCls = 'ivu-select';
40 40
@@ -94,7 +94,8 @@ @@ -94,7 +94,8 @@
94 focusIndex: 0, 94 focusIndex: 0,
95 query: '', 95 query: '',
96 inputLength: 20, 96 inputLength: 20,
97 - notFound: false 97 + notFound: false,
  98 + slotChangeDuration: false // if slot change duration and in multiple, set true and after slot change, set false
98 } 99 }
99 }, 100 },
100 computed: { 101 computed: {
@@ -180,7 +181,7 @@ @@ -180,7 +181,7 @@
180 }); 181 });
181 } 182 }
182 }, 183 },
183 - updateOptions (init) { 184 + updateOptions (init, slot = false) {
184 let options = []; 185 let options = [];
185 let index = 1; 186 let index = 1;
186 187
@@ -199,20 +200,28 @@ @@ -199,20 +200,28 @@
199 this.options = options; 200 this.options = options;
200 201
201 if (init) { 202 if (init) {
202 - this.updateSingleSelected(true);  
203 - this.updateMultipleSelected(true); 203 + this.updateSingleSelected(true, slot);
  204 + this.updateMultipleSelected(true, slot);
204 } 205 }
205 }, 206 },
206 - updateSingleSelected (init = false) { 207 + updateSingleSelected (init = false, slot = false) {
207 const type = typeof this.model; 208 const type = typeof this.model;
208 209
209 if (type === 'string' || type === 'number') { 210 if (type === 'string' || type === 'number') {
  211 + let findModel = false;
  212 +
210 for (let i = 0; i < this.options.length; i++) { 213 for (let i = 0; i < this.options.length; i++) {
211 if (this.model === this.options[i].value) { 214 if (this.model === this.options[i].value) {
212 this.selectedSingle = this.options[i].label; 215 this.selectedSingle = this.options[i].label;
  216 + findModel = true;
213 break; 217 break;
214 } 218 }
215 } 219 }
  220 +
  221 + if (slot && !findModel) {
  222 + this.model = '';
  223 + this.query = '';
  224 + }
216 } 225 }
217 226
218 this.toggleSingleSelected(this.model, init); 227 this.toggleSingleSelected(this.model, init);
@@ -229,7 +238,7 @@ @@ -229,7 +238,7 @@
229 } 238 }
230 } 239 }
231 }, 240 },
232 - updateMultipleSelected (init = false) { 241 + updateMultipleSelected (init = false, slot = false) {
233 if (this.multiple && Array.isArray(this.model)) { 242 if (this.multiple && Array.isArray(this.model)) {
234 let selected = []; 243 let selected = [];
235 244
@@ -249,8 +258,22 @@ @@ -249,8 +258,22 @@
249 } 258 }
250 259
251 this.selectedMultiple = selected; 260 this.selectedMultiple = selected;
252 - }  
253 261
  262 + if (slot) {
  263 + let selectedModel = [];
  264 +
  265 + for (let i = 0; i < selected.length; i++) {
  266 + selectedModel.push(selected[i].value);
  267 + }
  268 +
  269 + // if slot change and remove a selected option, emit user
  270 + if (this.model.length === selectedModel.length) {
  271 + this.slotChangeDuration = true;
  272 + }
  273 +
  274 + this.model = selectedModel;
  275 + }
  276 + }
254 this.toggleMultipleSelected(this.model, init); 277 this.toggleMultipleSelected(this.model, init);
255 }, 278 },
256 removeTag (index) { 279 removeTag (index) {
@@ -431,19 +454,46 @@ @@ -431,19 +454,46 @@
431 if (this.multiple && this.model.length && this.query === '') { 454 if (this.multiple && this.model.length && this.query === '') {
432 this.removeTag(this.model.length - 1); 455 this.removeTag(this.model.length - 1);
433 } 456 }
  457 + },
  458 + // use when slot changed
  459 + slotChange () {
  460 + this.options = [];
  461 + this.optionInstances = [];
434 } 462 }
435 }, 463 },
436 ready () { 464 ready () {
437 this.updateOptions(true); 465 this.updateOptions(true);
438 document.addEventListener('keydown', this.handleKeydown); 466 document.addEventListener('keydown', this.handleKeydown);
  467 +
  468 + // watch slot changed
  469 + if (MutationObserver) {
  470 + this.observer = new MutationObserver(() => {
  471 + this.slotChange();
  472 + this.updateOptions(true, true);
  473 + });
  474 +
  475 + this.observer.observe(this.$els.options, {
  476 +// attributes: true,
  477 + childList: true,
  478 + characterData: true,
  479 + subtree: true
  480 + });
  481 + }
439 }, 482 },
440 beforeDestroy () { 483 beforeDestroy () {
441 document.removeEventListener('keydown', this.handleKeydown); 484 document.removeEventListener('keydown', this.handleKeydown);
  485 + if (this.observer) {
  486 + this.observer.disconnect();
  487 + }
442 }, 488 },
443 watch: { 489 watch: {
444 model () { 490 model () {
445 if (this.multiple) { 491 if (this.multiple) {
446 - this.updateMultipleSelected(); 492 + if (this.slotChangeDuration) {
  493 + this.slotChangeDuration = false;
  494 + } else {
  495 + this.updateMultipleSelected();
  496 + }
447 } else { 497 } else {
448 this.updateSingleSelected(); 498 this.updateSingleSelected();
449 } 499 }
src/styles/themes/default/custom.less
@@ -46,7 +46,7 @@ @@ -46,7 +46,7 @@
46 @shadow-right : 1px 0 6px @shadow-color; 46 @shadow-right : 1px 0 6px @shadow-color;
47 47
48 // Button 48 // Button
49 -@btn-font-weight : 400; 49 +@btn-font-weight : normal;
50 @btn-padding-base : 4px 15px; 50 @btn-padding-base : 4px 15px;
51 @btn-padding-large : 6px 15px 7px 15px; 51 @btn-padding-large : 6px 15px 7px 15px;
52 @btn-padding-small : 2px 7px; 52 @btn-padding-small : 2px 7px;
src/utils/assist.js
@@ -49,4 +49,7 @@ export function getScrollBarSize (fresh) { @@ -49,4 +49,7 @@ export function getScrollBarSize (fresh) {
49 cached = widthContained - widthScroll; 49 cached = widthContained - widthScroll;
50 } 50 }
51 return cached; 51 return cached;
52 -}  
53 \ No newline at end of file 52 \ No newline at end of file
  53 +}
  54 +
  55 +// watch DOM change
  56 +export const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver || false;
54 \ No newline at end of file 57 \ No newline at end of file
test/routers/select.vue
1 <template> 1 <template>
2 - <div>  
3 - <br><br><br><br><br><br><br><br><br><br><br>  
4 - {{ city | json }}<br>  
5 - <Button @click="city = 'hangzhou'">切换城市</Button>  
6 - <br>  
7 - <i-select v-if="true" :model.sync="city" style="width:200px" filterable @on-change="change">  
8 - <i-option-group label="热门城市">  
9 - <i-option value="beijing">北京市</i-option>  
10 - <i-option value="shanghai" disabled label="上海市">上海市2</i-option>  
11 - <i-option value="shenzhen">深圳市</i-option>  
12 - </i-option-group>  
13 - <i-option-group label="二线城市">  
14 - <i-option value="nanjing">南京市</i-option>  
15 - <i-option value="hangzhou">杭州市</i-option>  
16 - <i-option value="heilongjiang" disabled>黑龙江市</i-option>  
17 - </i-option-group>  
18 - <i-option-group label="其它城市">  
19 - <i-option value="jyg">嘉峪关市</i-option>  
20 - <i-option value="lanzhou">兰州市</i-option>  
21 - <i-option value="beijingxi">北京西</i-option>  
22 - </i-option-group>  
23 - </i-select>  
24 -  
25 - <i-select v-show="true" :model.sync="focus" style="width:200px" @on-change="change" clearable filterable label-in-value>  
26 - <i-option value="beijing">北京</i-option>  
27 - <i-option value="shanghai" label="上海市">上海市</i-option>  
28 - <i-option value="shenzhen" disabled>深圳市</i-option>  
29 - <i-option value="guangzhou" label="广州市">广州市2</i-option>  
30 - <i-option value="shijiazhuang" disabled>石家庄市</i-option>  
31 - <!--<i-option value="shijiazhuang2">石家庄市2</i-option>-->  
32 - <i-option value="a">a市</i-option>  
33 - <i-option value="b">b市</i-option>  
34 - <i-option value="c">c市</i-option>  
35 - <i-option value="d">d市</i-option>  
36 - <i-option value="e">e市</i-option>  
37 - </i-select>  
38 -  
39 - <i-select v-if="true" :model.sync="focus2" style="width:300px" @on-change="change" clearable filterable multiple>  
40 - <i-option value="beijing" label="北京市">北京2</i-option>  
41 - <i-option value="shanghai">上海市</i-option>  
42 - <i-option value="shenzhen" disabled>深圳市</i-option>  
43 - <i-option value="guangzhou">广州市</i-option>  
44 - <i-option value="shijiazhuang">石家庄市</i-option>  
45 - <i-option value="a">a1市</i-option>  
46 - <i-option value="b">b2市</i-option>  
47 - <i-option value="c">c1市</i-option>  
48 - <i-option value="d">d2市</i-option>  
49 - <i-option value="e">e1市</i-option>  
50 - </i-select>  
51 -  
52 - <i-select v-if="true" :model.sync="focus2" style="width:300px" @on-change="change" clearable multiple>  
53 - <i-option value="beijing" label="北京市">北京2</i-option>  
54 - <i-option value="shanghai">上海市</i-option>  
55 - <i-option value="shenzhen" disabled>深圳市</i-option>  
56 - <i-option value="guangzhou">广州市</i-option>  
57 - <i-option value="shijiazhuang">石家庄市</i-option>  
58 - <i-option value="a">a市</i-option>  
59 - <i-option value="b">b市</i-option>  
60 - <i-option value="c">c市</i-option>  
61 - <i-option value="d">d市</i-option>  
62 - <i-option value="e">e市</i-option>  
63 - </i-select>  
64 -  
65 - <br><br><br><br><br><br><br><br><br><br><br><br>  
66 - </div> 2 + <!--<i-select :model.sync="model1" style="width:200px">-->
  3 + <!--<i-option v-for="item in cityList" :value="item.value">{{ item.label }}</i-option>-->
  4 + <!--</i-select>-->
  5 + <!--{{ model1 | json }}-->
  6 + <i-button @click="change">修改数据</i-button>
  7 + <!--<i-select :model.sync="model10" multiple style="width:240px" @on-change="datachange">-->
  8 + <!--<i-option v-for="item in cityList" :value="item.value">{{ item.label }}</i-option>-->
  9 + <!--</i-select>-->
  10 + <!--{{ model10 | json }}-->
  11 + <!--<i-select :model.sync="model11" filterable style="width:200px" @on-change="datachange">-->
  12 + <!--<i-option v-for="item in cityList" :value="item.value">{{ item.label }}</i-option>-->
  13 + <!--</i-select>-->
  14 + <!--{{ model11 | json }}-->
  15 + <i-select :model.sync="model12" filterable multiple style="width:240px" @on-change="datachange">
  16 + <i-option v-for="item in cityList" :value="item.value">{{ item.label }}</i-option>
  17 + </i-select>
  18 + {{ model12 | json }}
67 </template> 19 </template>
68 <script> 20 <script>
69 - import { iSelect, iOption, iOptionGroup, Button } from 'iview';  
70 - 21 + import { iSelect, iOption, iButton } from 'iview';
71 export default { 22 export default {
72 - components: {  
73 - iSelect,  
74 - iOption,  
75 - iOptionGroup,  
76 - Button  
77 - },  
78 - props: {  
79 -  
80 - }, 23 + components: { iSelect, iOption, iButton },
81 data () { 24 data () {
82 return { 25 return {
83 - city: '',  
84 - focus: '',  
85 - focus2: ['beijing']  
86 -// focus2: [] 26 + cityList: [
  27 + {
  28 + value: 'beijing',
  29 + label: '北京市'
  30 + },
  31 + {
  32 + value: 'shanghai',
  33 + label: '上海市'
  34 + },
  35 + {
  36 + value: 'shenzhen',
  37 + label: '深圳市'
  38 + },
  39 + {
  40 + value: 'hangzhou',
  41 + label: '杭州市'
  42 + },
  43 + {
  44 + value: 'nanjing',
  45 + label: '南京市'
  46 + },
  47 + {
  48 + value: 'chongqing',
  49 + label: '重庆市'
  50 + }
  51 + ],
  52 + model1: '',
  53 + model10: [],
  54 + model11: '',
  55 + model12: []
87 } 56 }
88 }, 57 },
89 - computed: {  
90 -  
91 - },  
92 methods: { 58 methods: {
93 - change (data) {  
94 - console.log(data) 59 + change () {
  60 + this.cityList.splice(2, 1);
  61 + },
  62 + datachange (data) {
  63 + console.log(data);
95 } 64 }
96 } 65 }
97 } 66 }
98 -</script>  
99 \ No newline at end of file 67 \ No newline at end of file
  68 +</script>
test/routers/tag.vue
@@ -28,10 +28,23 @@ @@ -28,10 +28,23 @@
28 <Tag type="border" color="red" closable>标签一</Tag> 28 <Tag type="border" color="red" closable>标签一</Tag>
29 <Tag type="border" color="yellow">标签一</Tag> 29 <Tag type="border" color="yellow">标签一</Tag>
30 <Tag type="border" color="yellow" closable>标签一</Tag> 30 <Tag type="border" color="yellow" closable>标签一</Tag>
  31 + <i-button type="primary" @click="modal1 = true">显示对话框</i-button>
  32 + <Modal
  33 + :visible.sync="modal1"
  34 + title="普通的Modal对话框标题">
  35 + <p>对话框内容</p>
  36 + <p>对话框内容</p>
  37 + <p>对话框内容</p>
  38 + </Modal>
31 </template> 39 </template>
32 <script> 40 <script>
33 - import { Tag } from 'iview'; 41 + import { Tag, Modal, iButton } from 'iview';
34 export default { 42 export default {
35 - components: { Tag } 43 + components: { Tag, Modal, iButton },
  44 + data () {
  45 + return {
  46 + modal1: false
  47 + }
  48 + }
36 } 49 }
37 </script> 50 </script>