Merge remote-tracking branch 'iview/2.0' into 2.0

This commit is contained in:
jilen 2020-02-13 17:52:42 +08:00
commit 82f2344b2a
268 changed files with 8115 additions and 24590 deletions

View file

@ -48,6 +48,10 @@
},
offsetBottom: {
type: Number
},
useCapture: {
type: Boolean,
default: false
}
},
data () {
@ -78,8 +82,8 @@
mounted () {
// window.addEventListener('scroll', this.handleScroll, false);
// window.addEventListener('resize', this.handleScroll, false);
on(window, 'scroll', this.handleScroll);
on(window, 'resize', this.handleScroll);
on(window, 'scroll', this.handleScroll, this.useCapture);
on(window, 'resize', this.handleScroll, this.useCapture);
this.$nextTick(() => {
this.handleScroll();
});
@ -87,8 +91,8 @@
beforeDestroy () {
// window.removeEventListener('scroll', this.handleScroll, false);
// window.removeEventListener('resize', this.handleScroll, false);
off(window, 'scroll', this.handleScroll);
off(window, 'resize', this.handleScroll);
off(window, 'scroll', this.handleScroll, this.useCapture);
off(window, 'resize', this.handleScroll, this.useCapture);
},
methods: {
handleScroll () {

View file

@ -168,7 +168,9 @@ export default {
this.handleScrollTo();
this.handleSetInkTop();
this.updateTitleOffset();
this.upperFirstTitle = this.scrollElement.scrollTop < this.titlesOffsetArr[0].offset;
if (this.titlesOffsetArr[0]) {
this.upperFirstTitle = this.scrollElement.scrollTop < this.titlesOffsetArr[0].offset;
}
on(this.scrollContainer, 'scroll', this.handleScroll);
on(window, 'hashchange', this.handleHashChange);
});

View file

@ -13,7 +13,8 @@
remote
auto-complete
:remote-method="remoteMethod"
@on-change="handleChange"
@on-select="handleSelect"
@on-clickoutside="handleClickOutside"
:transfer="transfer">
<slot name="input">
<i-input
@ -87,14 +88,14 @@
},
placement: {
validator (value) {
return oneOf(value, ['top', 'bottom']);
return oneOf(value, ['top', 'bottom', 'top-start', 'bottom-start', 'top-end', 'bottom-end']);
},
default: 'bottom'
},
transfer: {
type: Boolean,
default () {
return this.$IVIEW.transfer === '' ? false : this.$IVIEW.transfer;
return !this.$IVIEW || this.$IVIEW.transfer === '' ? false : this.$IVIEW.transfer;
}
},
name: {
@ -113,7 +114,8 @@
computed: {
inputIcon () {
let icon = '';
if (this.clearable && this.currentValue) {
//#6161 #7
if (this.clearable && this.currentValue && !this.disabled) {
icon = 'ios-close';
} else if (this.icon) {
icon = this.icon;
@ -150,9 +152,10 @@
remoteMethod (query) {
this.$emit('on-search', query);
},
handleChange (val) {
handleSelect (val) {
if (val === undefined || val === null) return;
this.currentValue = val;
this.$refs.input.blur();
this.$emit('on-select', val);
},
@ -167,6 +170,11 @@
this.currentValue = '';
this.$refs.select.reset();
this.$emit('on-clear');
},
handleClickOutside(){
this.$nextTick(() => {
this.$refs.input.blur();
});
}
}
};

View file

@ -67,9 +67,15 @@ const Transition = {
export default {
name: 'CollapseTransition',
functional: true,
render(h, { children }) {
props: {
appear: Boolean
},
render(h, { children, props }) {
const data = {
on: Transition
on: Transition,
props: {
appear: props.appear
}
};
return h('transition', data, children);

View file

@ -1,5 +1,5 @@
<template>
<transition :name="transitionName" @enter="handleEnter" @leave="handleLeave">
<transition :name="transitionName" @enter="handleEnter" @leave="handleLeave" appear>
<div :class="classes" :style="styles">
<template v-if="type === 'notice'">
<div :class="contentClasses" ref="content" v-html="content"></div>

View file

@ -4,10 +4,10 @@
<Icon type="ios-arrow-back"></Icon>
</button>
<div :class="[prefixCls + '-list']">
<div :class="[prefixCls + '-track', showCopyTrack ? '' : 'higher']" :style="trackStyles" ref="originTrack">
<div :class="[prefixCls + '-track', showCopyTrack ? '' : 'higher']" :style="trackStyles" ref="originTrack" @click="handlerClickEvent('currentIndex')">
<slot></slot>
</div>
<div :class="[prefixCls + '-track', showCopyTrack ? 'higher' : '']" :style="copyTrackStyles" ref="copyTrack" v-if="loop">
<div :class="[prefixCls + '-track', showCopyTrack ? 'higher' : '']" :style="copyTrackStyles" @click="handlerClickEvent('copyTrackIndex')" ref="copyTrack" v-if="loop">
</div>
</div>
<button type="button" :class="arrowClasses" class="right" @click="arrowEvent(1)">
@ -113,10 +113,13 @@
];
},
trackStyles () {
// #6076
const visibleStyle = this.trackIndex === -1 ? 'hidden' : 'visible';
return {
width: `${this.trackWidth}px`,
transform: `translate3d(${-this.trackOffset}px, 0px, 0px)`,
transition: `transform 500ms ${this.easing}`
transition: `transform 500ms ${this.easing}`,
visibility : visibleStyle
};
},
copyTrackStyles () {
@ -125,7 +128,7 @@
transform: `translate3d(${-this.trackCopyOffset}px, 0px, 0px)`,
transition: `transform 500ms ${this.easing}`,
position: 'absolute',
top: 0
//top: 0
};
},
arrowClasses () {
@ -142,6 +145,9 @@
}
},
methods: {
handlerClickEvent(type){
this.$emit('on-click',this[type]);
},
// find option component
findChild (cb) {
const find = function (child) {
@ -195,8 +201,8 @@
child.width = this.listWidth;
child.height = typeof this.height === 'number' ? `${this.height}px` : this.height;
});
this.trackWidth = (this.slides.length || 0) * this.listWidth;
const slidesLength = this.slides.length || 0;
this.trackWidth = slidesLength * this.listWidth;
},
// use when slot changed
slotChange () {
@ -266,8 +272,10 @@
},
dotsEvent (event, n) {
let curIndex = this.showCopyTrack ? this.copyTrackIndex : this.trackIndex;
const oldCurrentIndex = this.currentIndex;
if (event === this.trigger && curIndex !== n) {
this.updateTrackIndex(n);
this.$emit('on-change', oldCurrentIndex, this.currentIndex);
this.$emit('input', n);
// Reset autoplay timer when trigger be activated
this.setAutoplay();

View file

@ -17,7 +17,7 @@
v-show="filterable && query === ''"
@click="handleFocus">{{ displayRender }}</div>
<Icon type="ios-close-circle" :class="[prefixCls + '-arrow']" v-show="showCloseIcon" @click.native.stop="clearSelect"></Icon>
<Icon type="ios-arrow-down" :class="[prefixCls + '-arrow']"></Icon>
<Icon :type="arrowType" :custom="customArrowType" :size="arrowSize" :class="[prefixCls + '-arrow']"></Icon>
</slot>
</div>
<transition name="transition-drop">
@ -44,10 +44,11 @@
[selectPrefixCls + '-item-disabled']: item.disabled
}]"
v-for="(item, index) in querySelections"
:key="index"
@click="handleSelectItem(index)" v-html="item.display"></li>
</ul>
</div>
<ul v-show="filterable && query !== '' && !querySelections.length" :class="[prefixCls + '-not-found-tip']"><li>{{ localeNotFoundText }}</li></ul>
<ul v-show="(filterable && query !== '' && !querySelections.length) || !data.length" :class="[prefixCls + '-not-found-tip']"><li>{{ localeNotFoundText }}</li></ul>
</div>
</Drop>
</transition>
@ -207,7 +208,7 @@
for (let i = 0; i < arr.length; i++) {
let item = arr[i];
item.__label = label ? label + ' / ' + item.label : item.label;
item.__value = value ? value + ',' + item.value : item.value;
item.__value = value ? [...value, item.value] : [item.value];
if (item.children && item.children.length) {
getSelections(item.children, item.__label, item.__value);
@ -232,6 +233,41 @@
return item;
});
return selections;
},
// 3.4.0, global setting customArrow arrow
arrowType () {
let type = 'ios-arrow-down';
if (this.$IVIEW) {
if (this.$IVIEW.cascader.customArrow) {
type = '';
} else if (this.$IVIEW.cascader.arrow) {
type = this.$IVIEW.cascader.arrow;
}
}
return type;
},
// 3.4.0, global setting
customArrowType () {
let type = '';
if (this.$IVIEW) {
if (this.$IVIEW.cascader.customArrow) {
type = this.$IVIEW.cascader.customArrow;
}
}
return type;
},
// 3.4.0, global setting
arrowSize () {
let size = '';
if (this.$IVIEW) {
if (this.$IVIEW.cascader.arrowSize) {
size = this.$IVIEW.cascader.arrowSize;
}
}
return size;
}
},
methods: {
@ -241,7 +277,7 @@
this.currentValue = this.selected = this.tmpSelected = [];
this.handleClose();
this.emitValue(this.currentValue, oldVal);
// this.$broadcast('on-clear');
// this.$broadcast('on-clear');
this.broadcast('Caspanel', 'on-clear');
},
handleClose () {
@ -293,7 +329,7 @@
this.query = '';
this.$refs.input.currentValue = '';
const oldVal = JSON.stringify(this.currentValue);
this.currentValue = item.value.split(',');
this.currentValue = item.value;
// use setTimeout for #4786, can not use nextTick, because @on-find-selected use nextTick
setTimeout(() => {
this.emitValue(this.currentValue, oldVal);
@ -316,7 +352,7 @@
if ('__label' in new_item) {
delete new_item.__label;
}
if ('children' in new_item && new_item.children.length) {
if (Array.isArray(new_item.children) && new_item.children.length) {
new_item.children = new_item.children.map(i => deleteData(i));
}
return new_item;

View file

@ -1,13 +1,16 @@
<template>
<li :class="classes">
{{ data.label }}
<i v-if="showArrow" class="ivu-icon ivu-icon-ios-arrow-forward"></i>
<i v-if="showLoading" class="ivu-icon ivu-icon-ios-loading ivu-load-loop"></i>
<Icon :type="arrowType" :custom="customArrowType" :size="arrowSize" v-if="showArrow" />
<i v-if="showLoading" class="ivu-icon ivu-icon-ios-loading ivu-load-loop ivu-cascader-menu-item-loading"></i>
</li>
</template>
<script>
import Icon from '../icon/icon.vue';
export default {
name: 'Casitem',
components: { Icon },
props: {
data: Object,
prefixCls: String,
@ -28,6 +31,41 @@
},
showLoading () {
return 'loading' in this.data && this.data.loading;
},
// 3.4.0, global setting customArrow arrow
arrowType () {
let type = 'ios-arrow-forward';
if (this.$IVIEW) {
if (this.$IVIEW.cascader.customItemArrow) {
type = '';
} else if (this.$IVIEW.cascader.itemArrow) {
type = this.$IVIEW.cascader.itemArrow;
}
}
return type;
},
// 3.4.0, global setting
customArrowType () {
let type = '';
if (this.$IVIEW) {
if (this.$IVIEW.cascader.customItemArrow) {
type = this.$IVIEW.cascader.customItemArrow;
}
}
return type;
},
// 3.4.0, global setting
arrowSize () {
let size = '';
if (this.$IVIEW) {
if (this.$IVIEW.cascader.itemArrowSize) {
size = this.$IVIEW.cascader.itemArrowSize;
}
}
return size;
}
}
};

View file

@ -7,9 +7,18 @@
:prefix-cls="prefixCls"
:data="item"
:tmp-item="tmpItem"
@click.native.stop="handleClickItem(item)"
@mouseenter.native.stop="handleHoverItem(item)"></Casitem>
</ul><Caspanel v-if="sublist && sublist.length" :prefix-cls="prefixCls" :data="sublist" :disabled="disabled" :trigger="trigger" :change-on-select="changeOnSelect"></Caspanel>
@click.native.stop="handleClickItem(item, $event)"
@mouseenter.native.stop="handleHoverItem(item)"
></Casitem>
</ul>
<Caspanel
v-if="sublist && sublist.length"
:prefix-cls="prefixCls"
:data="sublist"
:disabled="disabled"
:trigger="trigger"
:change-on-select="changeOnSelect">
</Caspanel>
</span>
</template>
<script>
@ -48,15 +57,25 @@
}
},
methods: {
handleClickItem (item) {
isIcon(node){
let nodeName = (node.nodeName || '').toLocaleUpperCase();
let isIvu = node.classList.contains('ivu-icon');
if(nodeName == 'I' && isIvu){
return true;
}
return false;
},
handleClickItem (item, ev) {
let isIcon = this.isIcon(ev.target);
if (this.trigger !== 'click' && item.children && item.children.length) return; // #1922
this.handleTriggerItem(item, false, true);
this.handleTriggerItem(item, false, true,isIcon);
},
handleHoverItem (item) {
if (this.trigger !== 'hover' || !item.children || !item.children.length) return; // #1922
this.handleTriggerItem(item, false, true);
this.handleTriggerItem(item, false, true,false);
},
handleTriggerItem (item, fromInit = false, fromUser = false) {
//#6158 -- default fromInit = false to fromInit = true;
handleTriggerItem (item, fromInit = true, fromUser = false,isIcon=false) {
if (item.disabled) return;
const cascader = findComponentUpward(this, 'Cascader');
@ -89,7 +108,7 @@
if (item.children && item.children.length){
this.sublist = item.children;
this.dispatch('Cascader', 'on-result-change', {
!isIcon && this.dispatch('Cascader', 'on-result-change', {
lastValue: false,
changeOnSelect: this.changeOnSelect,
fromInit: fromInit
@ -104,7 +123,7 @@
}
} else {
this.sublist = [];
this.dispatch('Cascader', 'on-result-change', {
!isIcon && this.dispatch('Cascader', 'on-result-change', {
lastValue: true,
changeOnSelect: this.changeOnSelect,
fromInit: fromInit

View file

@ -25,7 +25,7 @@
</div>
<div class="ivu-cell-arrow" v-if="to">
<slot name="arrow">
<Icon type="ios-arrow-forward"></Icon>
<Icon :type="arrowType" :custom="customArrowType" :size="arrowSize" />
</slot>
</div>
</div>
@ -83,6 +83,41 @@
}
];
},
// 3.4.0, global setting customArrow arrow
arrowType () {
let type = 'ios-arrow-forward';
if (this.$IVIEW) {
if (this.$IVIEW.cell.customArrow) {
type = '';
} else if (this.$IVIEW.cell.arrow) {
type = this.$IVIEW.cell.arrow;
}
}
return type;
},
// 3.4.0, global setting
customArrowType () {
let type = '';
if (this.$IVIEW) {
if (this.$IVIEW.cell.customArrow) {
type = this.$IVIEW.cell.customArrow;
}
}
return type;
},
// 3.4.0, global setting
arrowSize () {
let size = '';
if (this.$IVIEW) {
if (this.$IVIEW.cell.arrowSize) {
size = this.$IVIEW.cell.arrowSize;
}
}
return size;
}
},
methods: {
handleClickItem (event, new_window) {

View file

@ -49,7 +49,7 @@
},
methods: {
updateModel (update) {
this.childrens = findComponentsDownward(this, 'Checkbox');
this.childrens = findComponentsDownward(this, 'Checkbox', 'CheckboxGroup');
if (this.childrens) {
const { value } = this;
this.childrens.forEach(child => {

View file

@ -42,12 +42,13 @@
methods: {
setActive () {
const activeKey = this.getActiveKey();
this.$nextTick(() => {
this.$children.forEach((child, index) => {
const name = child.name || index.toString();
this.$children.forEach((child, index) => {
const name = child.name || index.toString();
child.isActive = activeKey.indexOf(name) > -1;
child.index = index;
child.isActive = activeKey.indexOf(name) > -1;
child.index = index;
});
});
},
getActiveKey () {

View file

@ -4,7 +4,7 @@
<Icon type="ios-arrow-forward" v-if="!hideArrow"></Icon>
<slot></slot>
</div>
<collapse-transition>
<collapse-transition v-if="mounted">
<div :class="contentClasses" v-show="isActive">
<div :class="boxClasses"><slot name="content"></slot></div>
</div>
@ -31,7 +31,8 @@
data () {
return {
index: 0, // use index for default when name is null
isActive: false
isActive: false,
mounted: false
};
},
computed: {
@ -60,6 +61,9 @@
isActive: this.isActive
});
}
},
mounted () {
this.mounted = true;
}
};
</script>

View file

@ -10,7 +10,7 @@
:name="name"
:value="currentValue"
type="hidden">
<i :class="arrowClasses"></i>
<Icon :type="arrowType" :custom="customArrowType" :size="arrowSize" :class="arrowClasses"></Icon>
<div
ref="input"
:tabindex="disabled ? undefined : 0"
@ -125,6 +125,7 @@ import Hue from './hue.vue';
import Alpha from './alpha.vue';
import iInput from '../input/input.vue';
import iButton from '../button/button.vue';
import Icon from '../icon/icon.vue';
import Locale from '../../mixins/locale';
import {oneOf} from '../../utils/assist';
import Emitter from '../../mixins/emitter';
@ -134,7 +135,7 @@ import {changeColor, toRGBAString} from './utils';
export default {
name: 'ColorPicker',
components: {Drop, RecommendColors, Saturation, Hue, Alpha, iInput, iButton},
components: {Drop, RecommendColors, Saturation, Hue, Alpha, iInput, iButton, Icon},
directives: {clickOutside, TransferDom},
@ -260,8 +261,6 @@ export default {
computed: {
arrowClasses() {
return [
this.iconPrefixCls,
`${this.iconPrefixCls}-ios-arrow-down`,
`${this.inputPrefixCls}-icon`,
`${this.inputPrefixCls}-icon-normal`,
];
@ -352,6 +351,41 @@ export default {
[`${this.prefixCls}-confirm-color-editable`]: this.editable
}
];
},
// 3.4.0, global setting customArrow arrow
arrowType () {
let type = 'ios-arrow-down';
if (this.$IVIEW) {
if (this.$IVIEW.colorPicker.customArrow) {
type = '';
} else if (this.$IVIEW.colorPicker.arrow) {
type = this.$IVIEW.colorPicker.arrow;
}
}
return type;
},
// 3.4.0, global setting
customArrowType () {
let type = '';
if (this.$IVIEW) {
if (this.$IVIEW.colorPicker.customArrow) {
type = this.$IVIEW.colorPicker.customArrow;
}
}
return type;
},
// 3.4.0, global setting
arrowSize () {
let size = '';
if (this.$IVIEW) {
if (this.$IVIEW.colorPicker.arrowSize) {
size = this.$IVIEW.colorPicker.arrowSize;
}
}
return size;
}
},

View file

@ -75,7 +75,10 @@
return this.calendar(tableYear, tableMonth, (cell) => {
// normalize date offset from the dates provided by jsCalendar
if (cell.date instanceof Date) cell.date.setTime(cell.date.getTime() + cell.date.getTimezoneOffset() * 60000);
// Comment out this code to fix daylight saving time bug
// https://www.cnblogs.com/hamsterPP/p/5415472.html
if (cell.date instanceof Date) cell.date.setTime(cell.date.getTime() + cell.date.getTimezoneOffset() * 60000 + 480 * 60 * 1000);
//if (cell.date instanceof Date) cell.date.setTime(clearHours(cell.date));
const time = cell.date && clearHours(cell.date);
const dateIsInCurrentMonth = cell.date && tableMonth === cell.date.getMonth();

View file

@ -296,7 +296,18 @@
},
changePanelDate(panel, type, increment, updateOtherPanel = true){
const current = new Date(this[`${panel}PanelDate`]);
current[`set${type}`](current[`get${type}`]() + increment);
if (this.splitPanels) {
// fix #6404
current[`set${type}`](current[`get${type}`]() + increment);
} else {
if (panel === 'left') {
current[`set${type}`](current[`get${type}`]() + increment);
} else {
current[`set${type}`](current[`get${type}`]() + increment);
}
}
this[`${panel}PanelDate`] = current;
if (!updateOtherPanel) return;

View file

@ -2,6 +2,7 @@
<div
:class="wrapperClasses"
v-click-outside:mousedown.capture="handleClose"
v-click-outside:touchstart.capture="handleClose"
v-click-outside.capture="handleClose"
>
<div ref="reference" :class="[prefixCls + '-rel']">
@ -21,14 +22,13 @@
@on-input-change="handleInputChange"
@on-focus="handleFocus"
@on-blur="handleBlur"
@on-click="handleIconClick"
@click.native="handleFocus"
@keydown.native="handleKeydown"
@mouseenter.native="handleInputMouseenter"
@mouseleave.native="handleInputMouseleave"
:icon="iconType"
></i-input>
>
<Icon @click="handleIconClick" :type="arrowType" :custom="customArrowType" :size="arrowSize" slot="suffix" />
</i-input>
</slot>
</div>
<transition name="transition-drop">
@ -79,6 +79,7 @@
import iInput from '../../components/input/input.vue';
import Drop from '../../components/select/dropdown.vue';
import Icon from '../../components/icon/icon.vue';
import {directive as clickOutside} from 'v-click-outside-x';
import TransferDom from '../../directives/transfer-dom';
import { oneOf } from '../../utils/assist';
@ -120,7 +121,7 @@
export default {
mixins: [ Emitter ],
components: { iInput, Drop },
components: { iInput, Drop, Icon },
directives: { clickOutside, TransferDom },
props: {
format: {
@ -267,12 +268,6 @@
opened () {
return this.open === null ? this.visible : this.open;
},
iconType () {
let icon = 'ios-calendar-outline';
if (this.type === 'time' || this.type === 'timerange') icon = 'ios-time-outline';
if (this.showClose) icon = 'ios-close-circle';
return icon;
},
transition () {
const bottomPlaced = this.placement.match(/^bottom/);
return bottomPlaced ? 'slide-up' : 'slide-down';
@ -282,6 +277,80 @@
},
isConfirm(){
return this.confirm || this.type === 'datetime' || this.type === 'datetimerange' || this.multiple;
},
// 3.4.0, global setting customArrow arrow
arrowType () {
let type = '';
if (this.type === 'time' || this.type === 'timerange') {
type = 'ios-time-outline';
if (this.$IVIEW) {
if (this.$IVIEW.timePicker.customIcon) {
type = '';
} else if (this.$IVIEW.timePicker.icon) {
type = this.$IVIEW.timePicker.icon;
}
}
} else {
type = 'ios-calendar-outline';
if (this.$IVIEW) {
if (this.$IVIEW.datePicker.customIcon) {
type = '';
} else if (this.$IVIEW.datePicker.icon) {
type = this.$IVIEW.datePicker.icon;
}
}
}
if (this.showClose) type = 'ios-close-circle';
return type;
},
// 3.4.0, global setting
customArrowType () {
let type = '';
if (!this.showClose) {
if (this.type === 'time' || this.type === 'timerange') {
if (this.$IVIEW) {
if (this.$IVIEW.timePicker.customIcon) {
type = this.$IVIEW.timePicker.customIcon;
}
}
} else {
if (this.$IVIEW) {
if (this.$IVIEW.datePicker.customIcon) {
type = this.$IVIEW.datePicker.customIcon;
}
}
}
}
return type;
},
// 3.4.0, global setting
arrowSize () {
let size = '';
if (!this.showClose) {
if (this.type === 'time' || this.type === 'timerange') {
if (this.$IVIEW) {
if (this.$IVIEW.timePicker.iconSize) {
size = this.$IVIEW.timePicker.iconSize;
}
}
} else {
if (this.$IVIEW) {
if (this.$IVIEW.datePicker.iconSize) {
size = this.$IVIEW.datePicker.iconSize;
}
}
}
}
return size;
}
},
methods: {
@ -313,6 +382,7 @@
this.visible = false;
e && e.preventDefault();
e && e.stopPropagation();
this.$emit('on-clickoutside', e);
return;
}

View file

@ -1,11 +1,11 @@
<template>
<div v-transfer-dom :data-transfer="transfer">
<transition name="fade">
<div :class="maskClasses" :style="maskStyle" v-show="visible" v-if="mask" @click="handleMask"></div>
<div :class="maskClasses" :style="maskStyle" v-if="mask && visible" @click="handleMask"></div>
</transition>
<div :class="wrapClasses" @click="handleWrapClick">
<transition :name="'move-' + placement">
<div :class="classes" :style="mainStyles" v-show="visible">
<div :class="classes" :style="mainStyles" v-if="visible">
<div :class="contentClasses" ref="content">
<a class="ivu-drawer-close" v-if="closable" @click="close">
<slot name="close">
@ -303,6 +303,9 @@
if (this.$slots.header === undefined) {
this.showHead = !!val;
}
},
width (val) {
this.dragWidth = val;
}
}
};

View file

@ -37,14 +37,10 @@
},
methods: {
handleClick () {
if (this.disabled) return;
const $parent = findComponentUpward(this, 'Dropdown');
const hasChildren = this.$parent && this.$parent.$options.name === 'Dropdown';
if (this.disabled) {
this.$nextTick(() => {
$parent.currentVisible = true;
});
} else if (hasChildren) {
if (hasChildren) {
this.$parent.$emit('on-haschild-click');
} else {
if ($parent && $parent.$options.name === 'Dropdown') {

View file

@ -57,6 +57,10 @@
transferClassName: {
type: String
},
stopPropagation: {
type: Boolean,
default: false
},
},
computed: {
transition () {
@ -164,6 +168,7 @@
},
mounted () {
this.$on('on-click', (key) => {
if (this.stopPropagation) return;
const $parent = this.hasParent();
if ($parent) $parent.$emit('on-click', key);
});

View file

@ -178,33 +178,36 @@
return rules.filter(rule => !rule.trigger || rule.trigger.indexOf(trigger) !== -1);
},
validate(trigger, callback = function () {}) {
let rules = this.getFilteredRule(trigger);
if (!rules || rules.length === 0) {
if (!this.required) {
callback();
return true;
}else {
rules = [{required: true}];
this.$nextTick(() => {
let rules = this.getFilteredRule(trigger);
if (!rules || rules.length === 0) {
if (!this.required) {
this.validateState = '';
callback();
return true;
}else {
rules = [{required: true}];
}
}
}
this.validateState = 'validating';
this.validateState = 'validating';
let descriptor = {};
descriptor[this.prop] = rules;
let descriptor = {};
descriptor[this.prop] = rules;
const validator = new AsyncValidator(descriptor);
let model = {};
const validator = new AsyncValidator(descriptor);
let model = {};
model[this.prop] = this.fieldValue;
model[this.prop] = this.fieldValue;
validator.validate(model, { firstFields: true }, errors => {
this.validateState = !errors ? 'success' : 'error';
this.validateMessage = errors ? errors[0].message : '';
validator.validate(model, { firstFields: true }, errors => {
this.validateState = !errors ? 'success' : 'error';
this.validateMessage = errors ? errors[0].message : '';
callback(this.validateMessage);
callback(this.validateMessage);
});
this.validateDisabled = false;
});
this.validateDisabled = false;
},
resetField () {
this.validateState = '';

View file

@ -24,6 +24,7 @@
@blur="blur"
@keydown.stop="keyDown"
@input="change"
ref="precisionCursor"
@mouseup="preventDefault"
@change="change"
:readonly="readonly || !editable"
@ -224,7 +225,6 @@
if (this.disabled || this.readonly) {
return false;
}
const targetVal = Number(e.target.value);
let val = Number(this.currentValue);
const step = Number(this.step);
@ -261,7 +261,8 @@
if (val && !isNaN(this.precision)) val = Number(Number(val).toFixed(this.precision));
const {min, max} = this;
if (val!==null) {
// #6245
if ( val!==null && !this.activeChange ) {
if (val > max) {
val = max;
} else if (val < min) {
@ -297,6 +298,7 @@
}
},
change (event) {
if (event.type == 'change' && this.activeChange) return;
if (event.type == 'input' && !this.activeChange) return;
let val = event.target.value.trim();
@ -309,15 +311,24 @@
this.setValue(null);
return;
}
if (event.type == 'input' && val.match(/^\-?\.?$|\.$/)) return; // prevent fire early if decimal. If no more input the change event will fire later
if (event.type == 'input' && val.match(/^\-?\.?$|\.$/g)) return; // prevent fire early if decimal. If no more input the change event will fire later
//#fixed when setting the precision val, input point cannot show problem
const precision = this.precision;
let cacheVal = this.currentValue;
if( precision ){
const valMatchPointArr = (val+'').match(/\./g);
if( valMatchPointArr && valMatchPointArr.length >= 2 ){
cacheVal = this.currentValue + '.';
}
}
val = Number(val);
if (!isNaN(val)) {
if (!isNaN(val) ) {
this.currentValue = val;
this.setValue(val);
} else {
event.target.value = this.currentValue;
event.target.value = cacheVal;
}
},
changeVal (val) {
@ -342,6 +353,14 @@
},
currentValue (val) {
this.changeVal(val);
//optimization - Solve the problem of cursor positioning inaccuracy
this.$nextTick(()=>{
if( this.precision ){
const currentValueLength = ( this.currentValue || 0 ).toString().length;
const precisionCursor = this.$refs.precisionCursor;
precisionCursor.selectionStart = precisionCursor.selectionEnd = currentValueLength;
}
});
},
min () {
this.changeVal(this.currentValue);

View file

@ -2,39 +2,41 @@
<div :class="wrapClasses">
<template v-if="type !== 'textarea'">
<div :class="[prefixCls + '-group-prepend']" v-if="prepend" v-show="slotReady"><slot name="prepend"></slot></div>
<i class="ivu-icon" :class="['ivu-icon-ios-close-circle', prefixCls + '-icon', prefixCls + '-icon-clear' , prefixCls + '-icon-normal']" v-if="clearable && currentValue && !disabled" @click="handleClear"></i>
<i class="ivu-icon" :class="['ivu-icon-' + icon, prefixCls + '-icon', prefixCls + '-icon-normal']" v-else-if="icon" @click="handleIconClick"></i>
<i class="ivu-icon ivu-icon-ios-search" :class="[prefixCls + '-icon', prefixCls + '-icon-normal', prefixCls + '-search-icon']" v-else-if="search && enterButton === false" @click="handleSearch"></i>
<span class="ivu-input-suffix" v-else-if="showSuffix"><slot name="suffix"><i class="ivu-icon" :class="['ivu-icon-' + suffix]" v-if="suffix"></i></slot></span>
<transition name="fade">
<i class="ivu-icon ivu-icon-ios-loading ivu-load-loop" :class="[prefixCls + '-icon', prefixCls + '-icon-validate']" v-if="!icon"></i>
</transition>
<input
:id="elementId"
:autocomplete="autocomplete"
:spellcheck="spellcheck"
ref="input"
:type="type"
:class="inputClasses"
:placeholder="placeholder"
:disabled="disabled"
:maxlength="maxlength"
:readonly="readonly"
:name="name"
:value="currentValue"
:number="number"
:autofocus="autofocus"
@keyup.enter="handleEnter"
@keyup="handleKeyup"
@keypress="handleKeypress"
@keydown="handleKeydown"
@focus="handleFocus"
@blur="handleBlur"
@compositionstart="handleComposition"
@compositionupdate="handleComposition"
@compositionend="handleComposition"
@input="handleInput"
@change="handleChange">
<div :class="[prefixCls + '-inner-container']">
<i class="ivu-icon" :class="['ivu-icon-ios-close-circle', prefixCls + '-icon', prefixCls + '-icon-clear' , prefixCls + '-icon-normal']" v-if="clearable && currentValue && !disabled" @click="handleClear"></i>
<i class="ivu-icon" :class="['ivu-icon-' + icon, prefixCls + '-icon', prefixCls + '-icon-normal']" v-else-if="icon" @click="handleIconClick"></i>
<i class="ivu-icon ivu-icon-ios-search" :class="[prefixCls + '-icon', prefixCls + '-icon-normal', prefixCls + '-search-icon']" v-else-if="search && enterButton === false" @click="handleSearch"></i>
<span class="ivu-input-suffix" v-else-if="showSuffix"><slot name="suffix"><i class="ivu-icon" :class="['ivu-icon-' + suffix]" v-if="suffix"></i></slot></span>
<transition name="fade">
<i class="ivu-icon ivu-icon-ios-loading ivu-load-loop" :class="[prefixCls + '-icon', prefixCls + '-icon-validate']" v-if="!icon"></i>
</transition>
<input
:id="elementId"
:autocomplete="autocomplete"
:spellcheck="spellcheck"
ref="input"
:type="type"
:class="inputClasses"
:placeholder="placeholder"
:disabled="disabled"
:maxlength="maxlength"
:readonly="readonly"
:name="name"
:value="currentValue"
:number="number"
:autofocus="autofocus"
@keyup.enter="handleEnter"
@keyup="handleKeyup"
@keypress="handleKeypress"
@keydown="handleKeydown"
@focus="handleFocus"
@blur="handleBlur"
@compositionstart="handleComposition"
@compositionupdate="handleComposition"
@compositionend="handleComposition"
@input="handleInput"
@change="handleChange">
</div>
<div :class="[prefixCls + '-group-append']" v-if="append" v-show="slotReady"><slot name="append"></slot></div>
<div :class="[prefixCls + '-group-append', prefixCls + '-search']" v-else-if="search && enterButton" @click="handleSearch">
<i class="ivu-icon ivu-icon-ios-search" v-if="enterButton === true"></i>
@ -141,9 +143,7 @@
default: false
},
autocomplete: {
validator (value) {
return oneOf(value, ['on', 'off']);
},
type: String,
default: 'off'
},
clearable: {
@ -312,6 +312,7 @@
this.$emit('input', '');
this.setCurrentValue('');
this.$emit('on-change', e);
this.$emit('on-clear');
},
handleSearch () {
if (this.disabled) return false;

View file

@ -0,0 +1,8 @@
import List from './list.vue';
import ListItem from './list-item.vue';
import ListItemMeta from './list-item-meta.vue';
List.Item = ListItem;
List.Item.Meta = ListItemMeta;
export default List;

View file

@ -0,0 +1,35 @@
<template>
<div class="ivu-list-item-meta">
<div class="ivu-list-item-meta-avatar" v-if="avatar || $slots.avatar">
<slot name="avatar">
<Avatar :src="avatar" />
</slot>
</div>
<div class="ivu-list-item-meta-content">
<div v-if="title || $slots.title" class="ivu-list-item-meta-title"><slot name="title">{{ title }}</slot></div>
<div v-if="description || $slots.description" class="ivu-list-item-meta-description"><slot name="description">{{ description }}</slot></div>
</div>
</div>
</template>
<script>
import Avatar from '../../components/avatar/avatar.vue';
export default {
name: 'ListItemMeta',
components: { Avatar },
props: {
avatar: {
type: String,
default: ''
},
title: {
type: String,
default: ''
},
description: {
type: String,
default: ''
}
}
};
</script>

View file

@ -0,0 +1,63 @@
<template>
<li class="ivu-list-item" :class="classes">
<template v-if="itemLayout === 'vertical' && $slots.extra">
<div class="ivu-list-item-main">
<slot></slot>
<ul class="ivu-list-item-action" v-if="$slots.action">
<slot name="action"></slot>
</ul>
</div>
<div class="ivu-list-item-extra">
<slot name="extra"></slot>
</div>
</template>
<template v-else>
<slot></slot>
<ul class="ivu-list-item-action" v-if="$slots.action">
<slot name="action"></slot>
</ul>
<div class="ivu-list-item-extra">
<slot name="extra"></slot>
</div>
</template>
</li>
</template>
<script>
export default {
name: 'ListItem',
inject: ['ListInstance'],
props: {
},
computed: {
itemLayout () {
return this.ListInstance.itemLayout;
},
isItemContainsTextNode () {
let result;
this.$slots.default.forEach(item => {
if (typeof item === 'string') {
result = true;
}
});
return result;
},
isFlexMode () {
const extra = this.$slots.extra;
if (this.itemLayout === 'vertical') {
return !!extra;
}
return !this.isItemContainsTextNode;
},
classes () {
return [
{
'ivu-list-item-no-flex': !this.isFlexMode
}
];
}
}
};
</script>

View file

@ -0,0 +1,84 @@
<template>
<div :class="classes">
<div class="ivu-list-header" v-if="header || $slots.header"><slot name="header">{{ header }}</slot></div>
<div class="ivu-list-container">
<ul class="ivu-list-items"><slot></slot></ul>
</div>
<Spin v-if="loading" fix size="large"><slot name="spin"></slot></Spin>
<div class="ivu-list-footer" v-if="footer || $slots.footer"><slot name="footer">{{ footer }}</slot></div>
</div>
</template>
<script>
import { oneOf } from '../../utils/assist';
const prefixCls = 'ivu-list';
export default {
name: 'List',
provide () {
return {
ListInstance: this
};
},
props: {
border: {
type: Boolean,
default: false
},
itemLayout: {
validator (value) {
return oneOf(value, ['horizontal', 'vertical']);
},
default: 'horizontal'
},
// slot
header: {
type: String,
default: ''
},
// slot
footer: {
type: String,
default: ''
},
// slot: spin
loading: {
type: Boolean,
default: false
},
size: {
validator (value) {
return oneOf(value, ['small', 'large', 'default']);
},
default () {
return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
}
},
split: {
type: Boolean,
default: true
}
},
data () {
return {
};
},
computed: {
classes () {
return [
`${prefixCls}`,
`${prefixCls}-${this.size}`,
`${prefixCls}-${this.itemLayout}`,
{
[`${prefixCls}-bordered`]: this.border,
[`${prefixCls}-split`]: this.split
}
];
},
},
methods: {
}
};
</script>

View file

@ -2,6 +2,7 @@ import LoadingBar from './loading-bar';
let loadingBarInstance;
let color = 'primary';
let duration = 800;
let failedColor = 'error';
let height = 2;
let timer;
@ -32,7 +33,7 @@ function hide() {
percent: 0
});
}, 200);
}, 800);
}, duration);
}
function clearTimer() {
@ -96,6 +97,9 @@ export default {
if (options.color) {
color = options.color;
}
if (options.duration) {
duration = options.duration;
}
if (options.failedColor) {
failedColor = options.failedColor;
}

View file

@ -133,9 +133,9 @@
}
},
mounted () {
this.updateActiveName();
this.openedNames = [...this.openNames];
this.updateOpened();
this.$nextTick(() => this.updateActiveName());
this.$on('on-menu-item-select', (name) => {
this.currentActiveName = name;
this.$emit('on-select', name);

View file

@ -2,7 +2,7 @@
<li :class="classes" @mouseenter="handleMouseenter" @mouseleave="handleMouseleave">
<div :class="[prefixCls + '-submenu-title']" ref="reference" @click.stop="handleClick" :style="titleStyle">
<slot name="title"></slot>
<Icon type="ios-arrow-down" :class="[prefixCls + '-submenu-title-icon']"></Icon>
<Icon :type="arrowType" :custom="customArrowType" :size="arrowSize" :class="[prefixCls + '-submenu-title-icon']" />
</div>
<collapse-transition v-if="mode === 'vertical'">
<ul :class="[prefixCls]" v-show="opened"><slot></slot></ul>
@ -75,6 +75,41 @@
return this.hasParentSubmenu && this.mode !== 'horizontal' ? {
paddingLeft: 43 + (this.parentSubmenuNum - 1) * 24 + 'px'
} : {};
},
// 3.4.0, global setting customArrow arrow
arrowType () {
let type = 'ios-arrow-down';
if (this.$IVIEW) {
if (this.$IVIEW.menu.customArrow) {
type = '';
} else if (this.$IVIEW.menu.arrow) {
type = this.$IVIEW.menu.arrow;
}
}
return type;
},
// 3.4.0, global setting
customArrowType () {
let type = '';
if (this.$IVIEW) {
if (this.$IVIEW.menu.customArrow) {
type = this.$IVIEW.menu.customArrow;
}
}
return type;
},
// 3.4.0, global setting
arrowSize () {
let size = '';
if (this.$IVIEW) {
if (this.$IVIEW.menu.arrowSize) {
size = this.$IVIEW.menu.arrowSize;
}
}
return size;
}
},
methods: {

View file

@ -24,7 +24,8 @@ Modal.newInstance = properties => {
buttonLoading: false,
scrollable: false,
closable: false,
autoClose: true
autoClose: true,
closing: false // 关闭有动画,期间使用此属性避免重复点击
}),
render (h) {
let footerVNodes = [];
@ -160,12 +161,14 @@ Modal.newInstance = properties => {
},
methods: {
cancel () {
if (this.closing) return;
this.$children[0].visible = false;
this.buttonLoading = false;
this.onCancel();
this.remove();
},
ok () {
if (this.closing) return;
if (this.loading) {
this.buttonLoading = true;
} else {
@ -178,13 +181,17 @@ Modal.newInstance = properties => {
this.onOk();
},
remove () {
this.closing = true;
setTimeout(() => {
this.closing = false;
this.destroy();
}, 300);
},
destroy () {
this.$destroy();
document.body.removeChild(this.$el);
if( this.$el ){
document.body.removeChild(this.$el);
}
this.onRemove();
},
onOk () {},
@ -279,4 +286,4 @@ Modal.newInstance = properties => {
};
};
export default Modal;
export default Modal;

View file

@ -5,7 +5,7 @@
</transition>
<div :class="wrapClasses" :style="wrapStyles" @click="handleWrapClick">
<transition :name="transitionNames[0]" @after-leave="animationFinish">
<div :class="classes" :style="mainStyles" v-show="visible">
<div :class="classes" :style="mainStyles" v-show="visible" @mousedown="handleMousedown">
<div :class="contentClasses" ref="content" :style="contentStyles" @click="handleClickModal">
<a :class="[prefixCls + '-close']" v-if="closable" @click="close">
<slot name="close">
@ -60,7 +60,9 @@
},
maskClosable: {
type: Boolean,
default: true
default () {
return !this.$IVIEW || this.$IVIEW.modal.maskClosable === '' ? true : this.$IVIEW.modal.maskClosable;
}
},
title: {
type: String
@ -80,7 +82,10 @@
default: false
},
styles: {
type: Object
type: Object,
default() {
return {};
}
},
className: {
type: String
@ -142,6 +147,7 @@
dragging: false
},
modalIndex: this.handleGetModalIndex(), // for Esc close the top modal
isMouseTriggerIn: false, // #5800
};
},
computed: {
@ -203,8 +209,10 @@
let style = {};
if (this.draggable) {
if (this.dragData.x !== null) style.left = `${this.dragData.x}px`;
if (this.dragData.y !== null) style.top = `${this.dragData.y}px`;
let customTop = this.styles.top ? parseFloat(this.styles.top) : 0;
let customLeft = this.styles.left ? parseFloat(this.styles.left) : 0;
if (this.dragData.x !== null) style.left = `${this.dragData.x - customLeft}px`;
if (this.dragData.y !== null) style.top = `${this.dragData.y - customTop}px`;
const width = parseInt(this.width);
const styleWidth = {
width: width <= 100 ? `${width}%` : `${width}px`
@ -245,10 +253,17 @@
}
},
handleWrapClick (event) {
if (this.isMouseTriggerIn) {
this.isMouseTriggerIn = false;
return;
}
// use indexOf,do not use === ,because ivu-modal-wrap can have other custom className
const className = event.target.getAttribute('class');
if (className && className.indexOf(`${prefixCls}-wrap`) > -1) this.handleMask();
},
handleMousedown () {
this.isMouseTriggerIn = true;
},
cancel () {
this.close();
},

View file

@ -3,7 +3,7 @@
<li
:title="t('i.page.prev')"
:class="prevClasses"
@click="prev">
@click.stop="prev">
<a><i class="ivu-icon ivu-icon-ios-arrow-back"></i></a>
</li>
<div :class="simplePagerClasses" :title="currentPage + '/' + allPages">
@ -21,7 +21,7 @@
<li
:title="t('i.page.next')"
:class="nextClasses"
@click="next">
@click.stop="next">
<a><i class="ivu-icon ivu-icon-ios-arrow-forward"></i></a>
</li>
</ul>
@ -32,24 +32,24 @@
<li
:title="t('i.page.prev')"
:class="prevClasses"
@click="prev">
@click.stop="prev">
<a><template v-if="prevText !== ''">{{ prevText }}</template><i v-else class="ivu-icon ivu-icon-ios-arrow-back"></i></a>
</li>
<li title="1" :class="firstPageClasses" @click="changePage(1)"><a>1</a></li>
<li :title="t('i.page.prev5')" v-if="currentPage > 5" :class="[prefixCls + '-item-jump-prev']" @click="fastPrev"><a><i class="ivu-icon ivu-icon-ios-arrow-back"></i></a></li>
<li :title="currentPage - 3" v-if="currentPage === 5" :class="[prefixCls + '-item']" @click="changePage(currentPage - 3)"><a>{{ currentPage - 3 }}</a></li>
<li :title="currentPage - 2" v-if="currentPage - 2 > 1" :class="[prefixCls + '-item']" @click="changePage(currentPage - 2)"><a>{{ currentPage - 2 }}</a></li>
<li :title="currentPage - 1" v-if="currentPage - 1 > 1" :class="[prefixCls + '-item']" @click="changePage(currentPage - 1)"><a>{{ currentPage - 1 }}</a></li>
<li title="1" :class="firstPageClasses" @click.stop="changePage(1)"><a>1</a></li>
<li :title="t('i.page.prev5')" v-if="currentPage > 5" :class="[prefixCls + '-item-jump-prev']" @click.stop="fastPrev"><a><i class="ivu-icon ivu-icon-ios-arrow-back"></i></a></li>
<li :title="currentPage - 3" v-if="currentPage === 5" :class="[prefixCls + '-item']" @click.stop="changePage(currentPage - 3)"><a>{{ currentPage - 3 }}</a></li>
<li :title="currentPage - 2" v-if="currentPage - 2 > 1" :class="[prefixCls + '-item']" @click.stop="changePage(currentPage - 2)"><a>{{ currentPage - 2 }}</a></li>
<li :title="currentPage - 1" v-if="currentPage - 1 > 1" :class="[prefixCls + '-item']" @click.stop="changePage(currentPage - 1)"><a>{{ currentPage - 1 }}</a></li>
<li :title="currentPage" v-if="currentPage != 1 && currentPage != allPages" :class="[prefixCls + '-item',prefixCls + '-item-active']"><a>{{ currentPage }}</a></li>
<li :title="currentPage + 1" v-if="currentPage + 1 < allPages" :class="[prefixCls + '-item']" @click="changePage(currentPage + 1)"><a>{{ currentPage + 1 }}</a></li>
<li :title="currentPage + 2" v-if="currentPage + 2 < allPages" :class="[prefixCls + '-item']" @click="changePage(currentPage + 2)"><a>{{ currentPage + 2 }}</a></li>
<li :title="currentPage + 3" v-if="allPages - currentPage === 4" :class="[prefixCls + '-item']" @click="changePage(currentPage + 3)"><a>{{ currentPage + 3 }}</a></li>
<li :title="t('i.page.next5')" v-if="allPages - currentPage >= 5" :class="[prefixCls + '-item-jump-next']" @click="fastNext"><a><i class="ivu-icon ivu-icon-ios-arrow-forward"></i></a></li>
<li :title="allPages" v-if="allPages > 1" :class="lastPageClasses" @click="changePage(allPages)"><a>{{ allPages }}</a></li>
<li :title="currentPage + 1" v-if="currentPage + 1 < allPages" :class="[prefixCls + '-item']" @click.stop="changePage(currentPage + 1)"><a>{{ currentPage + 1 }}</a></li>
<li :title="currentPage + 2" v-if="currentPage + 2 < allPages" :class="[prefixCls + '-item']" @click.stop="changePage(currentPage + 2)"><a>{{ currentPage + 2 }}</a></li>
<li :title="currentPage + 3" v-if="allPages - currentPage === 4" :class="[prefixCls + '-item']" @click.stop="changePage(currentPage + 3)"><a>{{ currentPage + 3 }}</a></li>
<li :title="t('i.page.next5')" v-if="allPages - currentPage >= 5" :class="[prefixCls + '-item-jump-next']" @click.stop="fastNext"><a><i class="ivu-icon ivu-icon-ios-arrow-forward"></i></a></li>
<li :title="allPages" v-if="allPages > 1" :class="lastPageClasses" @click.stop="changePage(allPages)"><a>{{ allPages }}</a></li>
<li
:title="t('i.page.next')"
:class="nextClasses"
@click="next">
@click.stop="next">
<a><template v-if="nextText !== ''">{{ nextText }}</template><i v-else class="ivu-icon ivu-icon-ios-arrow-forward"></i></a>
</li>
<Options

View file

@ -117,6 +117,11 @@
type: Boolean,
default: false,
},
// 3.4.0
disabled: {
type: Boolean,
default: false
}
},
data () {
return {
@ -186,6 +191,8 @@
},
methods: {
handleClick () {
if (this.disabled) return;
if (this.confirm) {
this.visible = !this.visible;
return true;
@ -215,6 +222,8 @@
}
},
handleFocus (fromInput = true) {
if (this.disabled) return;
if (this.trigger !== 'focus' || this.confirm || (this.isInput && !fromInput)) {
return false;
}
@ -227,6 +236,8 @@
this.visible = false;
},
handleMouseenter () {
if (this.disabled) return;
if (this.trigger !== 'hover' || this.confirm) {
return false;
}

View file

@ -2,10 +2,10 @@
<div :class="wrapClasses">
<div :class="outerClasses">
<div :class="innerClasses">
<div :class="bgClasses" :style="bgStyle"></div><div :class="successBgClasses" :style="successBgStyle"></div>
<div :class="bgClasses" :style="bgStyle"><div class="ivu-progress-inner-text" v-if="textInside">{{ percent }}%</div></div><div :class="successBgClasses" :style="successBgStyle"></div>
</div>
</div>
<span v-if="!hideInfo" :class="textClasses">
<span v-if="!hideInfo && !textInside" :class="textClasses">
<slot>
<span v-if="isStatus" :class="textInnerClasses">
<Icon :type="statusIcon"></Icon>
@ -54,7 +54,11 @@
default: false
},
strokeColor: {
type: String
type: [String, Array]
},
textInside: {
type: Boolean,
default: false
}
},
data () {
@ -89,7 +93,11 @@
};
if (this.strokeColor) {
style['background-color'] = this.strokeColor;
if (typeof this.strokeColor === 'string') {
style['background-color'] = this.strokeColor;
} else {
style['background-image'] = `linear-gradient(to right, ${this.strokeColor[0]} 0%, ${this.strokeColor[1]} 100%)`;
}
}
return style;
@ -108,7 +116,7 @@
`${prefixCls}`,
`${prefixCls}-${this.currentStatus}`,
{
[`${prefixCls}-show-info`]: !this.hideInfo,
[`${prefixCls}-show-info`]: !this.hideInfo && !this.textInside,
[`${prefixCls}-vertical`]: this.vertical
}

View file

@ -1,8 +1,21 @@
<template>
<div @click="onHeaderClick">
<div class="ivu-tag ivu-tag-checked" v-for="item in selectedMultiple">
<div @click="onHeaderClick" :class="headCls">
<span :class="[prefixCls + '-prefix']" v-if="$slots.prefix || prefix">
<slot name="prefix">
<Icon :type="prefix" v-if="prefix" />
</slot>
</span>
<div
class="ivu-tag ivu-tag-checked"
v-for="(item, index) in selectedMultiple"
v-if="maxTagCount === undefined || index < maxTagCount">
<span class="ivu-tag-text">{{ item.label }}</span>
<Icon type="ios-close" @click.native.stop="removeTag(item)"></Icon>
</div><div class="ivu-tag ivu-tag-checked" v-if="maxTagCount !== undefined && selectedMultiple.length > maxTagCount">
<span class="ivu-tag-text ivu-select-max-tag">
<template v-if="maxTagPlaceholder">{{ maxTagPlaceholder(selectedMultiple.length - maxTagCount) }}</template>
<template v-else>+ {{ selectedMultiple.length - maxTagCount }}...</template>
</span>
</div>
<span
:class="singleDisplayClasses"
@ -26,7 +39,7 @@
ref="input">
<Icon type="ios-close-circle" :class="[prefixCls + '-arrow']" v-if="resetSelect" @click.native.stop="onClear"></Icon>
<Icon type="ios-arrow-down" :class="[prefixCls + '-arrow']" v-if="!resetSelect && !remote && !disabled"></Icon>
<Icon :type="arrowType" :custom="customArrowType" :size="arrowSize" :class="[prefixCls + '-arrow']" v-if="!resetSelect && !remote"></Icon>
</div>
</template>
<script>
@ -77,6 +90,17 @@
queryProp: {
type: String,
default: ''
},
prefix: {
type: String
},
// 3.4.0
maxTagCount: {
type: Number
},
// 3.4.0
maxTagPlaceholder: {
type: Function
}
},
data () {
@ -92,6 +116,7 @@
singleDisplayClasses(){
const {filterable, multiple, showPlaceholder} = this;
return [{
[prefixCls + '-head-with-prefix']: this.$slots.prefix || this.prefix,
[prefixCls + '-placeholder']: showPlaceholder && !filterable,
[prefixCls + '-selected-value']: !showPlaceholder && !multiple && !filterable,
}];
@ -143,6 +168,47 @@
},
selectedMultiple(){
return this.multiple ? this.values : [];
},
// 使 prefix filterable
headCls () {
return {
[`${prefixCls}-head-flex`]: this.filterable && (this.$slots.prefix || this.prefix)
};
},
// 3.4.0, global setting customArrow arrow
arrowType () {
let type = 'ios-arrow-down';
if (this.$IVIEW) {
if (this.$IVIEW.select.customArrow) {
type = '';
} else if (this.$IVIEW.select.arrow) {
type = this.$IVIEW.select.arrow;
}
}
return type;
},
// 3.4.0, global setting
customArrowType () {
let type = '';
if (this.$IVIEW) {
if (this.$IVIEW.select.customArrow) {
type = this.$IVIEW.select.customArrow;
}
}
return type;
},
// 3.4.0, global setting
arrowSize () {
let size = '';
if (this.$IVIEW) {
if (this.$IVIEW.select.arrowSize) {
size = this.$IVIEW.select.arrowSize;
}
}
return size;
}
},
methods: {
@ -161,8 +227,9 @@
this.inputLength = this.$refs.input.value.length * 12 + 20;
this.$emit('on-keydown');
},
handleInputDelete () {
if (this.multiple && this.selectedMultiple.length && this.query === '') {
handleInputDelete (e) {
const targetValue = e.target.value;
if (this.multiple && this.selectedMultiple.length && this.query === '' && targetValue === '' ) {
this.removeTag(this.selectedMultiple[this.selectedMultiple.length - 1]);
}
},

View file

@ -3,6 +3,7 @@
:class="classes"
v-click-outside.capture="onClickOutside"
v-click-outside:mousedown.capture="onClickOutside"
v-click-outside:touchstart.capture="onClickOutside"
>
<div
ref="reference"
@ -33,18 +34,23 @@
:multiple="multiple"
:values="values"
:clearable="canBeCleared"
:prefix="prefix"
:disabled="disabled"
:remote="remote"
:input-element-id="elementId"
:initial-label="initialLabel"
:placeholder="placeholder"
:query-prop="query"
:max-tag-count="maxTagCount"
:max-tag-placeholder="maxTagPlaceholder"
@on-query-change="onQueryChange"
@on-input-focus="isFocused = true"
@on-input-blur="isFocused = false"
@on-clear="clearSingleSelect"
/>
>
<slot name="prefix" slot="prefix"></slot>
</select-head>
</slot>
</div>
<transition name="transition-drop">
@ -57,7 +63,9 @@
:transfer="transfer"
v-transfer-dom
>
<ul v-show="showNotFoundLabel" :class="[prefixCls + '-not-found']"><li>{{ localeNotFoundText }}</li></ul>
<ul v-show="showNotFoundLabel && !$slots.empty" :class="[prefixCls + '-not-found']"><li>{{ localeNotFoundText }}</li></ul>
<!--feature #5327-->
<ul v-if="showNotFoundLabel && $slots.empty" :class="[prefixCls + '-not-found']" @mousedown.prevent><li><slot name="empty"></slot></li></ul>
<ul :class="prefixCls + '-dropdown-list'">
<functional-options
v-if="(!remote) || (remote && !loading)"
@ -235,12 +243,24 @@
transferClassName: {
type: String
},
// 3.4.0
prefix: {
type: String
},
// 3.4.0
maxTagCount: {
type: Number
},
// 3.4.0
maxTagPlaceholder: {
type: Function
}
},
mounted(){
this.$on('on-select-selected', this.onOptionClick);
// set the initial values if there are any
if (!this.remote && this.selectOptions.length > 0){
if ( this.selectOptions.length > 0){
this.values = this.getInitialValue().map(value => {
if (typeof value !== 'number' && !value) return null;
return this.getOptionData(value);
@ -268,6 +288,8 @@
hasExpectedValue: false,
preventRemoteCall: false,
filterQueryChange: false, // #4273
// #6349
hideMenuTimer: null
};
},
computed: {
@ -392,9 +414,8 @@
const optionPassesFilter = this.filterable ? this.validateOption(cOptions) : option;
if (!optionPassesFilter) continue;
}
optionCounter = optionCounter + 1;
selectOptions.push(this.processOption(option, selectedValues, optionCounter === currentIndex));
selectOptions.push(this.processOption(option, selectedValues, currentIndex === optionCounter));
}
}
@ -419,12 +440,14 @@
if (query === null) {
this.onQueryChange('');
this.values = [];
// #5620,
this.lastRemoteQuery = '';
}
},
clearSingleSelect(){ // PUBLIC API
this.$emit('on-clear');
this.hideMenu();
if (this.clearable) this.reset();
this.$emit('on-clear'); // #6331
},
getOptionData(value){
const option = this.flatOptions.find(({componentOptions}) => componentOptions.propsData.value === value);
@ -452,7 +475,6 @@
const optionValue = option.componentOptions.propsData.value;
const disabled = option.componentOptions.propsData.disabled;
const isSelected = values.includes(optionValue);
const propsData = {
...option.componentOptions.propsData,
selected: isSelected,
@ -470,15 +492,18 @@
},
validateOption({children, elm, propsData}){
const value = propsData.value;
const label = propsData.label || '';
const textContent = (elm && elm.textContent) || (children || []).reduce((str, node) => {
const nodeText = node.elm ? node.elm.textContent : node.text;
return `${str} ${nodeText}`;
}, '') || '';
const stringValues = JSON.stringify([value, label, textContent]);
const stringValues = [label, textContent];
const query = this.query.toLowerCase().trim();
return stringValues.toLowerCase().includes(query);
const findValuesIndex = stringValues.findIndex(item=>{
let itemToLowerCase = item.toLowerCase();
return itemToLowerCase.includes(query);
});
return findValuesIndex === -1 ? false : true;
},
toggleMenu (e, force) {
@ -492,9 +517,22 @@
this.broadcast('Drop', 'on-update-popper');
}
},
updateFocusIndex(){
this.focusIndex = this.flatOptions.findIndex((opt) => {
if (!opt || !opt.componentOptions) return false;
return opt.componentOptions.propsData.value === this.publicValue;
});
},
hideMenu () {
this.toggleMenu(null, false);
setTimeout(() => this.unchangedQuery = true, ANIMATION_TIMEOUT);
setTimeout(() =>{
this.unchangedQuery = true;
// resolve if we use filterable, dropItem not selected #6349
this.hideMenuTimer = setTimeout(()=>{
this.updateFocusIndex();
this.hideMenuTimer = null;
});
}, ANIMATION_TIMEOUT);
},
onClickOutside(event){
if (this.visible) {
@ -524,6 +562,7 @@
event.preventDefault();
this.hideMenu();
this.isFocused = true;
this.$emit('on-clickoutside', event);
} else {
this.caretPosition = -1;
this.isFocused = false;
@ -537,31 +576,32 @@
this.filterQueryChange = false;
},
handleKeydown (e) {
if (e.key === 'Backspace'){
const key = e.key || e.code;
if ( key === 'Backspace'){
return; // so we don't call preventDefault
}
if (this.visible) {
e.preventDefault();
if (e.key === 'Tab'){
if ( key === 'Tab'){
e.stopPropagation();
}
// Esc slide-up
if (e.key === 'Escape') {
if ( key === 'Escape') {
e.stopPropagation();
this.hideMenu();
}
// next
if (e.key === 'ArrowUp') {
if ( key === 'ArrowUp') {
this.navigateOptions(-1);
}
// prev
if (e.key === 'ArrowDown') {
if ( key === 'ArrowDown') {
this.navigateOptions(1);
}
// enter
if (e.key === 'Enter') {
if ( key === 'Enter') {
if (this.focusIndex === -1) return this.hideMenu();
const optionComponent = this.flatOptions[this.focusIndex];
@ -610,7 +650,6 @@
},
onOptionClick(option) {
if (this.multiple){
// keep the query for remote select
if (this.remote) this.lastRemoteQuery = this.lastRemoteQuery || this.query;
else this.lastRemoteQuery = '';
@ -621,25 +660,19 @@
} else {
this.values = this.values.concat(option);
}
this.isFocused = true; // so we put back focus after clicking with mouse on option elements
} else {
this.query = String(option.label).trim();
this.query = '';
this.values = [option];
this.lastRemoteQuery = '';
this.hideMenu();
}
this.focusIndex = this.flatOptions.findIndex((opt) => {
if (!opt || !opt.componentOptions) return false;
return opt.componentOptions.propsData.value === option.value;
});
if (this.filterable){
const inputField = this.$el.querySelector('input[type="text"]');
if (!this.autoComplete) this.$nextTick(() => inputField.focus());
}
this.broadcast('Drop', 'on-update-popper');
this.$emit('on-select', this.publicValue); // # 4441
setTimeout(() => {
this.filterQueryChange = false;
}, ANIMATION_TIMEOUT);
@ -663,6 +696,9 @@
this.query = query;
this.unchangedQuery = this.visible;
this.filterQueryChange = true;
if(this.filterable){
this.updateFocusIndex();
}
},
toggleHeaderFocus({type}){
if (this.disabled) {
@ -682,13 +718,13 @@
watch: {
value(value){
const {getInitialValue, getOptionData, publicValue, values} = this;
this.checkUpdateStatus();
const vModelValue = (publicValue && this.labelInValue) ?
(this.multiple ? publicValue.map(({value}) => value) : publicValue.value) : publicValue;
if (value === '') this.values = [];
else if (checkValuesNotEqual(value,publicValue,values)) {
else if (checkValuesNotEqual(value,vModelValue,values)) {
this.$nextTick(() => this.values = getInitialValue().map(getOptionData).filter(Boolean));
this.dispatch('FormItem', 'on-form-change', this.publicValue);
if (!this.multiple) this.dispatch('FormItem', 'on-form-change', this.publicValue);
}
},
values(now, before){
@ -750,14 +786,15 @@
const optionInstance = findChild(this, ({$options}) => {
return $options.componentName === 'select-item' && $options.propsData.value === optionValue;
});
let bottomOverflowDistance = optionInstance.$el.getBoundingClientRect().bottom - this.$refs.dropdown.$el.getBoundingClientRect().bottom;
let topOverflowDistance = optionInstance.$el.getBoundingClientRect().top - this.$refs.dropdown.$el.getBoundingClientRect().top;
if (bottomOverflowDistance > 0) {
this.$refs.dropdown.$el.scrollTop += bottomOverflowDistance;
}
if (topOverflowDistance < 0) {
this.$refs.dropdown.$el.scrollTop += topOverflowDistance;
if(optionInstance && optionInstance.$el ){
let bottomOverflowDistance = optionInstance.$el.getBoundingClientRect().bottom - this.$refs.dropdown.$el.getBoundingClientRect().bottom;
let topOverflowDistance = optionInstance.$el.getBoundingClientRect().top - this.$refs.dropdown.$el.getBoundingClientRect().top;
if (bottomOverflowDistance > 0) {
this.$refs.dropdown.$el.scrollTop += bottomOverflowDistance;
}
if (topOverflowDistance < 0) {
this.$refs.dropdown.$el.scrollTop += topOverflowDistance;
}
}
},
dropVisible(open){

View file

@ -0,0 +1,16 @@
export default {
name: 'SliderMarker',
props: {
mark: {
type: [String, Object]
}
},
render (h) {
let label = typeof this.mark === 'string' ? this.mark : [this.mark.label];
return h('div', {
class: 'ivu-slider-marks-item',
style: this.mark.style || {}
}, label);
}
};

View file

@ -7,25 +7,45 @@
:max="max"
:step="step"
:value="exportValue[0]"
:disabled="disabled"
:disabled="itemDisabled"
:active-change="activeChange"
@on-change="handleInputChange"></Input-number>
<div
:class="[prefixCls + '-wrap']"
ref="slider" @click.self="sliderClick"
>
<input type="hidden" :name="name" :value="exportValue">
<template v-if="showStops">
<div
:class="[prefixCls + '-stop']"
v-for="item in stops"
:style="{ 'left': item + '%' }"
@click.self="sliderClick"
></div>
</template>
<div
:class="[prefixCls + '-bar']"
:style="barStyle"
@click.self="sliderClick"></div>
<template v-if="showStops">
<div
:class="[prefixCls + '-stop']"
v-for="(item,index) in stops"
:key="index"
:style="{ 'left': item + '%' }"
@click.self="sliderClick"
></div>
</template>
<template v-if="markList.length > 0">
<div
v-for="(item, key) in markList"
:key="key"
:class="[prefixCls + '-stop']"
:style="{ 'left': item.position + '%' }"
@click.self="sliderClick"
></div>
<div class="ivu-slider-marks">
<SliderMarker
v-for="(item, key) in markList"
:key="key"
:mark="item.mark"
:style="{ 'left': item.position + '%' }"
@click.native="sliderClick"
/>
</div>
</template>
<div
:class="[prefixCls + '-button-wrap']"
:style="{left: minPosition + '%'}"
@ -82,17 +102,19 @@
<script>
import InputNumber from '../../components/input-number/input-number.vue';
import Tooltip from '../../components/tooltip/tooltip.vue';
import SliderMarker from './marker';
import { getStyle, oneOf } from '../../utils/assist';
import { on, off } from '../../utils/dom';
import Emitter from '../../mixins/emitter';
import mixinsForm from '../../mixins/form';
import elementResizeDetectorMaker from 'element-resize-detector';
const prefixCls = 'ivu-slider';
export default {
name: 'Slider',
mixins: [ Emitter ],
components: { InputNumber, Tooltip },
mixins: [ Emitter, mixinsForm ],
components: { InputNumber, Tooltip, SliderMarker },
props: {
min: {
type: Number,
@ -148,6 +170,15 @@
},
name: {
type: String
},
// 3.4.0
activeChange: {
type: Boolean,
default: true
},
// 3.5.4
marks: {
type: Object
}
},
data () {
@ -194,7 +225,7 @@
{
[`${prefixCls}-input`]: this.showInput && !this.range,
[`${prefixCls}-range`]: this.range,
[`${prefixCls}-disabled`]: this.disabled
[`${prefixCls}-disabled`]: this.itemDisabled
}
];
},
@ -248,6 +279,19 @@
}
return result;
},
markList() {
if (!this.marks) return [];
const marksKeys = Object.keys(this.marks);
return marksKeys.map(parseFloat)
.sort((a, b) => a - b)
.filter(point => point <= this.max && point >= this.min)
.map(point => ({
point,
position: (point - this.min) * 100 / (this.max - this.min),
mark: this.marks[point]
}));
},
tipDisabled () {
return this.tipFormat(this.currentValue[0]) === null || this.showTip === 'never';
},
@ -274,7 +318,7 @@
return [min, max];
},
getCurrentValue (event, type) {
if (this.disabled) {
if (this.itemDisabled) {
return;
}
@ -298,7 +342,7 @@
}
},
onPointerDown (event, type) {
if (this.disabled) return;
if (this.itemDisabled) return;
event.preventDefault();
this.pointerDown = type;
@ -353,10 +397,10 @@
this.currentValue = [...value];
if (!this.dragging) {
if (this.currentValue[index] !== this.oldValue[index]) {
this.emitChange();
this.oldValue[index] = this.currentValue[index];
}
// if (this.currentValue[index] !== this.oldValue[index]) {
this.emitChange();
// this.oldValue[index] = this.currentValue[index];
// }
}
},
handleDecimal(pos,step){
@ -380,7 +424,7 @@
},
sliderClick (event) {
if (this.disabled) return;
if (this.itemDisabled) return;
const currentX = this.getPointerX(event);
const sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left;
let newPos = ((currentX - sliderOffsetLeft) / this.sliderWidth * this.valueRange) + this.min;
@ -431,4 +475,4 @@
this.observer.removeListener(this.$refs.slider, this.handleSetSliderWidth);
}
};
</script>
</script>

View file

@ -69,7 +69,10 @@
prefix: 'ivu-split',
offset: 0,
oldOffset: 0,
isMoving: false
isMoving: false,
computedMin: 0,
computedMax: 0,
currentValue: 0.5
};
},
computed: {
@ -98,12 +101,6 @@
},
offsetSize () {
return this.isHorizontal ? 'offsetWidth' : 'offsetHeight';
},
computedMin () {
return this.getComputedThresholdValue('min');
},
computedMax () {
return this.getComputedThresholdValue('max');
}
},
methods: {
@ -157,22 +154,35 @@
this.$emit('on-move-start');
},
computeOffset(){
this.offset = (this.valueIsPx ? this.px2percent(this.value, this.$refs.outerWrapper[this.offsetSize]) : this.value) * 10000 / 100;
this.$nextTick(() => {
this.computedMin = this.getComputedThresholdValue('min');
this.computedMax = this.getComputedThresholdValue('max');
let value = this.valueIsPx ? this.px2percent(this.value, this.$refs.outerWrapper[this.offsetSize]) : this.value;
let anotherValue = this.getAnotherOffset(value);
if (parseFloat(value) <= parseFloat(this.computedMin)) value = this.getMax(value, this.computedMin);
if (parseFloat(anotherValue) <= parseFloat(this.computedMax)) value = this.getAnotherOffset(this.getMax(anotherValue, this.computedMax));
this.offset = value * 10000 / 100;
this.currentValue = value;
this.$emit('input', value);
});
}
},
watch: {
value () {
this.computeOffset();
value (val) {
if (val !== this.currentValue) {
this.currentValue = val;
this.computeOffset();
}
}
},
mounted () {
this.$nextTick(() => {
this.computeOffset();
});
window.addEventListener('resize', ()=>{
this.computeOffset();
});
on(window, 'resize', this.computeOffset);
},
beforeDestroy () {
off(window, 'resize', this.computeOffset);
}
};
</script>

View file

@ -3,8 +3,10 @@
<div :class="[prefixCls + '-tail']"><i></i></div>
<div :class="[prefixCls + '-head']">
<div :class="[prefixCls + '-head-inner']">
<span v-if="!icon && currentStatus != 'finish' && currentStatus != 'error'">{{ stepNumber }}</span>
<span v-else :class="iconClasses"></span>
<slot name="status">
<span v-if="!icon && currentStatus != 'finish' && currentStatus != 'error'">{{ stepNumber }}</span>
<span v-else :class="iconClasses"></span>
</slot>
</div>
</div>
<div :class="[prefixCls + '-main']">

View file

@ -2,6 +2,7 @@
<span
tabindex="0"
:class="wrapClasses"
:style="wrapStyles"
@click="toggle"
@keydown.space="toggle"
>
@ -15,9 +16,7 @@
<script>
import { oneOf } from '../../utils/assist';
import Emitter from '../../mixins/emitter';
const prefixCls = 'ivu-switch';
export default {
name: 'iSwitch',
mixins: [ Emitter ],
@ -52,7 +51,14 @@
loading: {
type: Boolean,
default: false
}
},
trueColor: {
type: String
},
falseColor: {
type: String
},
beforeChange: Function
},
data () {
return {
@ -71,23 +77,45 @@
}
];
},
wrapStyles () {
let style = {};
if (this.trueColor && this.currentValue === this.trueValue) {
style['border-color'] = this.trueColor;
style['background-color'] = this.trueColor;
} else if (this.falseColor && this.currentValue === this.falseValue) {
style['border-color'] = this.falseColor;
style['background-color'] = this.falseColor;
}
return style;
},
innerClasses () {
return `${prefixCls}-inner`;
}
},
methods: {
handleToggle () {
const checked = this.currentValue === this.trueValue ? this.falseValue : this.trueValue;
this.currentValue = checked;
this.$emit('input', checked);
this.$emit('on-change', checked);
this.dispatch('FormItem', 'on-form-change', checked);
},
toggle (event) {
event.preventDefault();
if (this.disabled || this.loading) {
return false;
}
const checked = this.currentValue === this.trueValue ? this.falseValue : this.trueValue;
this.currentValue = checked;
this.$emit('input', checked);
this.$emit('on-change', checked);
this.dispatch('FormItem', 'on-form-change', checked);
if (!this.beforeChange) {
return this.handleToggle();
}
const before = this.beforeChange();
if (before && before.then) {
before.then(() => {
this.handleToggle();
});
} else {
this.handleToggle();
}
}
},
watch: {

View file

@ -8,7 +8,7 @@
<table-tr
:draggable="draggable"
:row="row"
:key="row._rowKey"
:key="rowKey ? row._rowKey : index"
:prefix-cls="prefixCls"
@mouseenter.native.stop="handleMouseIn(row._index)"
@mouseleave.native.stop="handleMouseOut(row._index)"
@ -31,7 +31,7 @@
</table-tr>
<tr v-if="rowExpanded(row._index)" :class="{[prefixCls + '-expanded-hidden']: fixed}">
<td :colspan="columns.length" :class="prefixCls + '-expanded-cell'">
<Expand :key="row._rowKey" :row="row" :render="expandRender" :index="row._index"></Expand>
<Expand :key="rowKey ? row._rowKey : index" :row="row" :render="expandRender" :index="row._index"></Expand>
</td>
</tr>
</template>
@ -63,6 +63,10 @@
draggable: {
type: Boolean,
default: false
},
rowKey: {
type: Boolean,
default: false
}
},
computed: {

View file

@ -16,7 +16,7 @@
<span v-if="!column.renderHeader">{{ column.title || '' }}</span>
<render-header v-else :render="column.renderHeader" :column="column" :index="index"></render-header>
</template>
<template v-else-if="column.type === 'selection'"><Checkbox :value="isSelectAll" :disabled="!data.length" @on-change="selectAll"></Checkbox></template>
<template v-else-if="column.type === 'selection'"><Checkbox :value="isSelectAll" :disabled="isSelectDisabled" @on-change="selectAll"></Checkbox></template>
<template v-else>
<span v-if="!column.renderHeader" :class="{[prefixCls + '-cell-sort']: column.sortable}" @click="handleSortByHead(getColumn(rowIndex, index)._index)">{{ column.title || '#' }}</span>
<render-header v-else :render="column.renderHeader" :column="column" :index="index"></render-header>
@ -61,7 +61,7 @@
</template>
</div>
</th>
<th v-if="$parent.showVerticalScrollBar && rowIndex===0" :class='scrollBarCellClass()' :rowspan="headRows.length"></th>
</tr>
</thead>
@ -121,6 +121,12 @@
} else {
return [this.columns];
}
},
isSelectDisabled () {
let isSelectDisabled = false;
if (!this.data.length) isSelectDisabled = true;
if (!this.data.find(item => !item._disabled)) isSelectDisabled = true;
return isSelectDisabled;
}
},
methods: {
@ -171,7 +177,8 @@
this.$parent.selectAll(status);
},
handleSort (index, type) {
const column = this.columns[index];
// index #5580
const column = this.columns.find(item => item._index === index);
const _index = column._index;
if (column._sortType === type) {
@ -180,7 +187,8 @@
this.$parent.handleSort(_index, type);
},
handleSortByHead (index) {
const column = this.columns[index];
// index #5580
const column = this.columns.find(item => item._index === index);
if (column.sortable) {
const type = column._sortType;
if (type === 'normal') {

View file

@ -21,6 +21,7 @@
:styleObject="tableStyle"
:columns="cloneColumns"
:data="rebuildData"
:row-key="rowKey"
:columns-width="columnsWidth"
:obj-data="objData"></table-body>
</div>
@ -59,6 +60,7 @@
:styleObject="fixedTableStyle"
:columns="leftFixedColumns"
:data="rebuildData"
:row-key="rowKey"
:columns-width="columnsWidth"
:obj-data="objData"></table-body>
</div>
@ -84,6 +86,7 @@
:styleObject="fixedRightTableStyle"
:columns="rightFixedColumns"
:data="rebuildData"
:row-key="rowKey"
:columns-width="columnsWidth"
:obj-data="objData"></table-body>
</div>
@ -149,6 +152,10 @@
height: {
type: [Number, String]
},
// 3.4.0
maxHeight: {
type: [Number, String]
},
stripe: {
type: Boolean,
default: false
@ -196,6 +203,11 @@
return oneOf(value, ['dark', 'light']);
},
default: 'dark'
},
// #5380 :key 使 index
rowKey: {
type: Boolean,
default: false
}
},
data () {
@ -275,6 +287,10 @@
const height = parseInt(this.height);
style.height = `${height}px`;
}
if (this.maxHeight) {
const maxHeight = parseInt(this.maxHeight);
style.maxHeight = `${maxHeight}px`;
}
if (this.width) style.width = `${this.width}px`;
return style;
},
@ -336,7 +352,11 @@
let style = {};
if (this.bodyHeight !== 0) {
const height = this.bodyHeight;
style.height = `${height}px`;
if (this.height) {
style.height = `${height}px`;
} else if (this.maxHeight) {
style.maxHeight = `${height}px`;
}
}
return style;
},
@ -548,7 +568,7 @@
this.objData[_index]._isExpanded = status;
this.$emit('on-expand', JSON.parse(JSON.stringify(this.cloneData[_index])), status);
if(this.height){
if(this.height || this.maxHeight){
this.$nextTick(()=>this.fixedBody());
}
},
@ -578,12 +598,16 @@
},
fixedHeader () {
if (this.height) {
if (this.height || this.maxHeight) {
this.$nextTick(() => {
const titleHeight = parseInt(getStyle(this.$refs.title, 'height')) || 0;
const headerHeight = parseInt(getStyle(this.$refs.header, 'height')) || 0;
const footerHeight = parseInt(getStyle(this.$refs.footer, 'height')) || 0;
this.bodyHeight = this.height - titleHeight - headerHeight - footerHeight;
if (this.height) {
this.bodyHeight = this.height - titleHeight - headerHeight - footerHeight;
} else if (this.maxHeight) {
this.bodyHeight = this.maxHeight - titleHeight - headerHeight - footerHeight;
}
this.$nextTick(()=>this.fixedBody());
});
} else {
@ -943,7 +967,9 @@
this.$on('on-visible-change', (val) => {
if (val) {
this.handleResize();
this.$nextTick(()=>{
this.handleResize();
});
}
});
},
@ -986,6 +1012,9 @@
height () {
this.handleResize();
},
maxHeight () {
this.handleResize();
},
showHorizontalScrollBar () {
this.handleResize();
},

View file

@ -13,13 +13,13 @@
<span :class="[prefixCls + '-nav-prev', scrollable ? '' : prefixCls + '-nav-scroll-disabled']" @click="scrollPrev"><Icon type="ios-arrow-back"></Icon></span>
<span :class="[prefixCls + '-nav-next', scrollable ? '' : prefixCls + '-nav-scroll-disabled']" @click="scrollNext"><Icon type="ios-arrow-forward"></Icon></span>
<div ref="navScroll" :class="[prefixCls + '-nav-scroll']">
<div ref="nav" :class="[prefixCls + '-nav']" class="nav-text" :style="navStyle">
<div ref="nav" :class="[prefixCls + '-nav']" :style="navStyle">
<div :class="barClasses" :style="barStyle"></div>
<div :class="tabCls(item)" v-for="(item, index) in navList" @click="handleChange(index)">
<Icon v-if="item.icon !== ''" :type="item.icon"></Icon>
<Render v-if="item.labelType === 'function'" :render="item.label"></Render>
<template v-else>{{ item.label }}</template>
<Icon v-if="showClose(item)" type="ios-close" @click.native.stop="handleRemove(index)"></Icon>
<Icon :class="[prefixCls + '-close']" v-if="showClose(item)" :type="arrowType" :custom="customArrowType" :size="arrowSize" @click.native.stop="handleRemove(index)"></Icon>
</div>
</div>
</div>
@ -100,6 +100,13 @@
name: {
type: String
},
custContentClass: {
type: String,
default: ''
},
custContentStyle: {
type: Object,
}
},
data () {
return {
@ -133,7 +140,8 @@
`${prefixCls}-content`,
{
[`${prefixCls}-content-animated`]: this.animated
}
},
this.custContentClass
];
},
barClasses () {
@ -154,6 +162,12 @@
transform: `translateX(${p}) translateZ(0px)`
};
}
const { custContentStyle } = this;
if (custContentStyle) {
for (const key in custContentStyle){
style[key] = custContentStyle[key];
}
}
return style;
},
barStyle () {
@ -169,6 +183,41 @@
}
return style;
},
// 3.4.0, global setting customArrow arrow
arrowType () {
let type = 'ios-close';
if (this.$IVIEW) {
if (this.$IVIEW.tabs.customCloseIcon) {
type = '';
} else if (this.$IVIEW.tabs.closeIcon) {
type = this.$IVIEW.tabs.closeIcon;
}
}
return type;
},
// 3.4.0, global setting
customArrowType () {
let type = '';
if (this.$IVIEW) {
if (this.$IVIEW.tabs.customCloseIcon) {
type = this.$IVIEW.tabs.customCloseIcon;
}
}
return type;
},
// 3.4.0, global setting
arrowSize () {
let size = '';
if (this.$IVIEW) {
if (this.$IVIEW.tabs.closeIconSize) {
size = this.$IVIEW.tabs.closeIconSize;
}
}
return size;
}
},
methods: {
@ -182,7 +231,7 @@
if (item.tab === this.name) {
TabPanes.push(item);
}
} else {
}else if (this.$children.includes(item)) { // #6279 #6299
TabPanes.push(item);
}
});

View file

@ -235,9 +235,11 @@
},
handleLeftCheckedKeysChange (keys) {
this.leftCheckedKeys = keys;
this.handleCheckedKeys();
},
handleRightCheckedKeysChange (keys) {
this.rightCheckedKeys = keys;
this.handleCheckedKeys();
},
handleCheckedKeys () {
const sourceSelectedKeys = this.getValidKeys('left');

View file

@ -1,10 +1,10 @@
<template>
<collapse-transition>
<collapse-transition :appear="appear">
<ul :class="classes">
<li>
<span :class="arrowClasses" @click="handleExpand">
<Icon v-if="showArrow" type="ios-arrow-forward"></Icon>
<Icon v-if="showLoading" type="ios-loading" class="ivu-load-loop"></Icon>
<Icon v-if="showArrow" :type="arrowType" :custom="customArrowType" :size="arrowSize" />
<Icon v-if="showLoading" type="ios-loading" class="ivu-load-loop" />
</span>
<Checkbox
v-if="showCheckbox"
@ -17,6 +17,7 @@
<span v-else :class="titleClasses" @click="handleSelect">{{ data.title }}</span>
<Tree-node
v-if="data.expand"
:appear="appearByClickArrow"
v-for="(item, i) in children"
:key="i"
:data="item"
@ -61,11 +62,18 @@
showCheckbox: {
type: Boolean,
default: false
},
appear: {
type: Boolean,
default: false
}
},
data () {
return {
prefixCls: prefixCls
prefixCls: prefixCls,
appearByClickArrow: false,
// #6139
loadingChildrenState : true
};
},
computed: {
@ -99,7 +107,7 @@
];
},
showArrow () {
return (this.data[this.childrenKey] && this.data[this.childrenKey].length) || ('loading' in this.data && !this.data.loading);
return (this.data[this.childrenKey] && this.data[this.childrenKey].length) || ('loading' in this.data && !this.data.loading && this.loadingChildrenState);
},
showLoading () {
return 'loading' in this.data && this.data.loading;
@ -127,6 +135,41 @@
},
children () {
return this.data[this.childrenKey];
},
// 3.4.0, global setting customArrow arrow
arrowType () {
let type = 'ios-arrow-forward';
if (this.$IVIEW) {
if (this.$IVIEW.tree.customArrow) {
type = '';
} else if (this.$IVIEW.tree.arrow) {
type = this.$IVIEW.tree.arrow;
}
}
return type;
},
// 3.4.0, global setting
customArrowType () {
let type = '';
if (this.$IVIEW) {
if (this.$IVIEW.tree.customArrow) {
type = this.$IVIEW.tree.customArrow;
}
}
return type;
},
// 3.4.0, global setting
arrowSize () {
let size = '';
if (this.$IVIEW) {
if (this.$IVIEW.tree.arrowSize) {
size = this.$IVIEW.tree.arrowSize;
}
}
return size;
}
},
methods: {
@ -134,6 +177,9 @@
const item = this.data;
if (item.disabled) return;
// Vue.js 2.6.9 transition appear iView appear appear false
this.appearByClickArrow = true;
// async loading
if (item[this.childrenKey].length === 0) {
const tree = findComponentUpward(this, 'Tree');
@ -144,6 +190,8 @@
if (children.length) {
this.$set(this.data, this.childrenKey, children);
this.$nextTick(() => this.handleExpand());
}else{
this.loadingChildrenState = false;
}
});
return;

View file

@ -121,9 +121,9 @@
const node = this.flatState[nodeKey].node;
const parent = this.flatState[parentKey].node;
if (node.checked == parent.checked && node.indeterminate == parent.indeterminate) return; // no need to update upwards
if (node.checked == true) {
this.$set(parent, 'checked', parent[this.childrenKey].every(node => node.checked));
// #6121
this.$set(parent, 'checked', parent[this.childrenKey].every(node => node.checked || node.disabled !== undefined ));
this.$set(parent, 'indeterminate', !parent.checked);
} else {
this.$set(parent, 'checked', false);
@ -160,10 +160,16 @@
},
updateTreeDown(node, changes = {}) {
if (this.checkStrictly) return;
for (let key in changes) {
this.$set(node, key, changes[key]);
// after #6121
if( key === 'checked' && node.disabled ){
this.$set(node, key, node.checked);
}else{
this.$set(node, key, changes[key]);
}
// before -- this.$set(node, key, changes[key]);
}
if (node[this.childrenKey]) {
node[this.childrenKey].forEach(child => {
this.updateTreeDown(child, changes);