Merge branch '2.0' into table_render

This commit is contained in:
anykno 2017-06-03 22:10:48 +08:00 committed by GitHub
commit 8e9002b970
36 changed files with 874 additions and 512 deletions

View file

@ -61,17 +61,9 @@
}
return status;
}
},
data () {
return {
alone: false
};
},
mounted () {
const child_length = this.$refs.badge.children.length;
if (child_length === 1) {
this.alone = true;
},
alone () {
return this.$slots.default === undefined;
}
}
};

View file

@ -0,0 +1,79 @@
// Thanks to https://github.com/ElemeFE/element/blob/dev/src/transitions/collapse-transition.js
import { addClass, removeClass } from '../../utils/assist';
const Transition = {
beforeEnter(el) {
addClass(el, 'collapse-transition');
if (!el.dataset) el.dataset = {};
el.dataset.oldPaddingTop = el.style.paddingTop;
el.dataset.oldPaddingBottom = el.style.paddingBottom;
el.style.height = '0';
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
},
enter(el) {
el.dataset.oldOverflow = el.style.overflow;
if (el.scrollHeight !== 0) {
el.style.height = el.scrollHeight + 'px';
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
} else {
el.style.height = '';
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
}
el.style.overflow = 'hidden';
},
afterEnter(el) {
// for safari: remove class then reset height is necessary
removeClass(el, 'collapse-transition');
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
},
beforeLeave(el) {
if (!el.dataset) el.dataset = {};
el.dataset.oldPaddingTop = el.style.paddingTop;
el.dataset.oldPaddingBottom = el.style.paddingBottom;
el.dataset.oldOverflow = el.style.overflow;
el.style.height = el.scrollHeight + 'px';
el.style.overflow = 'hidden';
},
leave(el) {
if (el.scrollHeight !== 0) {
// for safari: add class after set height, or it will jump to zero height suddenly, weired
addClass(el, 'collapse-transition');
el.style.height = 0;
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
}
},
afterLeave(el) {
removeClass(el, 'collapse-transition');
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
}
};
export default {
name: 'CollapseTransition',
functional: true,
render(h, { children }) {
const data = {
on: Transition
};
return h('transition', data, children);
}
};

View file

@ -1,24 +1,21 @@
import Notification from './notification.vue';
import Vue from 'vue';
import { camelcaseToHyphen } from '../../../utils/assist';
Notification.newInstance = properties => {
const _props = properties || {};
let props = '';
Object.keys(_props).forEach(prop => {
props += ' :' + camelcaseToHyphen(prop) + '=' + prop;
const Instance = new Vue({
data: _props,
render (h) {
return h(Notification, {
props: _props
});
}
});
const div = document.createElement('div');
div.innerHTML = `<notification${props}></notification>`;
document.body.appendChild(div);
const notification = new Vue({
el: div,
data: _props,
components: { Notification }
}).$children[0];
const component = Instance.$mount();
document.body.appendChild(component.$el);
const notification = Instance.$children[0];
return {
notice (noticeProps) {
@ -28,10 +25,10 @@ Notification.newInstance = properties => {
notification.close(name);
},
component: notification,
destroy () {
destroy (element) {
notification.closeAll();
setTimeout(function() {
document.body.removeChild(document.getElementsByClassName('ivu-message')[0].parentElement);
document.body.removeChild(document.getElementsByClassName(element)[0]);
}, 500);
}
};

View file

@ -1,10 +1,20 @@
<template>
<transition :name="transitionName">
<div :class="classes" :style="styles">
<div :class="[baseClass + '-content']" ref="content" v-html="content"></div>
<a :class="[baseClass + '-close']" @click="close" v-if="closable">
<i class="ivu-icon ivu-icon-ios-close-empty"></i>
</a>
<template v-if="type === 'notice'">
<div :class="[baseClass + '-content']" ref="content" v-html="content"></div>
<a :class="[baseClass + '-close']" @click="close" v-if="closable">
<i class="ivu-icon ivu-icon-ios-close-empty"></i>
</a>
</template>
<template v-if="type === 'message'">
<div :class="[baseClass + '-content']" ref="content">
<div :class="[baseClass + '-content-text']" v-html="content"></div>
<a :class="[baseClass + '-close']" @click="close" v-if="closable">
<i class="ivu-icon ivu-icon-ios-close-empty"></i>
</a>
</div>
</template>
</div>
</transition>
</template>
@ -19,6 +29,9 @@
type: Number,
default: 1.5
},
type: {
type: String
},
content: {
type: String,
default: ''

View file

@ -5,6 +5,7 @@
:key="notice.name"
:prefix-cls="prefixCls"
:styles="notice.styles"
:type="notice.type"
:content="notice.content"
:duration="notice.duration"
:closable="notice.closable"

View file

@ -0,0 +1,30 @@
<template>
<div ref="cell"></div>
</template>
<script>
import Vue from 'vue';
export default {
name: 'RenderCell',
props: {
render: Function
},
methods: {
compile () {
if (this.render) {
this.$el.innerHTML = '';
const component = new Vue({
functional: true,
render: (h) => {
return this.render(h);
}
});
const Cell = component.$mount();
this.$refs.cell.appendChild(Cell.$el);
}
}
},
mounted () {
this.compile();
}
};
</script>

View file

@ -4,18 +4,21 @@
<Icon type="arrow-right-b"></Icon>
<slot></slot>
</div>
<div :class="contentClasses" v-show="isActive">
<div :class="boxClasses"><slot name="content"></slot></div>
</div>
<collapse-transition>
<div :class="contentClasses" v-show="isActive">
<div :class="boxClasses"><slot name="content"></slot></div>
</div>
</collapse-transition>
</div>
</template>
<script>
import Icon from '../icon/icon.vue';
import CollapseTransition from '../base/collapse-transition';
const prefixCls = 'ivu-collapse';
export default {
name: 'Panel',
components: { Icon },
components: { Icon, CollapseTransition },
props: {
name: {
type: String

View file

@ -1,24 +1,21 @@
import LoadingBar from './loading-bar.vue';
import Vue from 'vue';
import { camelcaseToHyphen } from '../../utils/assist';
LoadingBar.newInstance = properties => {
const _props = properties || {};
let props = '';
Object.keys(_props).forEach(prop => {
props += ' :' + camelcaseToHyphen(prop) + '=' + prop;
const Instance = new Vue({
data: _props,
render (h) {
return h(LoadingBar, {
props: _props
});
}
});
const div = document.createElement('div');
div.innerHTML = `<loading-bar${props}></loading-bar>`;
document.body.appendChild(div);
const loading_bar = new Vue({
el: div,
data: _props,
components: { LoadingBar }
}).$children[0];
const component = Instance.$mount();
document.body.appendChild(component.$el);
const loading_bar = Instance.$children[0];
return {
update (options) {
@ -34,7 +31,7 @@ LoadingBar.newInstance = properties => {
},
component: loading_bar,
destroy () {
document.body.removeChild(div);
document.body.removeChild(document.getElementsByClassName('ivu-loading-bar')[0]);
}
};
};

View file

@ -4,7 +4,9 @@
<slot name="title"></slot>
<Icon type="ios-arrow-down" :class="[prefixCls + '-submenu-title-icon']"></Icon>
</div>
<ul :class="[prefixCls]" v-if="mode === 'vertical'" v-show="opened"><slot></slot></ul>
<collapse-transition v-if="mode === 'vertical'">
<ul :class="[prefixCls]" v-show="opened"><slot></slot></ul>
</collapse-transition>
<transition name="slide-up" v-else>
<Drop
v-show="opened"
@ -17,6 +19,7 @@
<script>
import Drop from '../select/dropdown.vue';
import Icon from '../icon/icon.vue';
import CollapseTransition from '../base/collapse-transition';
import { getStyle, findComponentUpward } from '../../utils/assist';
import Emitter from '../../mixins/emitter';
@ -25,7 +28,7 @@
export default {
name: 'Submenu',
mixins: [ Emitter ],
components: { Icon, Drop },
components: { Icon, Drop, CollapseTransition },
props: {
name: {
type: [String, Number],

View file

@ -28,12 +28,7 @@ function getMessageInstance () {
return messageInstance;
}
function notice (content, duration = defaultDuration, type, onClose) {
if (!onClose) {
onClose = function () {
};
}
function notice (content = '', duration = defaultDuration, type, onClose = function () {}, closable = false) {
const iconType = iconTypes[type];
// if loading
@ -52,7 +47,9 @@ function notice (content, duration = defaultDuration, type, onClose) {
<span>${content}</span>
</div>
`,
onClose: onClose
onClose: onClose,
closable: closable,
type: 'message'
});
// 用于手动消除
@ -66,20 +63,50 @@ function notice (content, duration = defaultDuration, type, onClose) {
}
export default {
info (content, duration, onClose) {
return notice(content, duration, 'info', onClose);
info (options) {
const type = typeof options;
if (type === 'string') {
options = {
content: options
};
}
return notice(options.content, options.duration, 'info', options.onClose, options.closable);
},
success (content, duration, onClose) {
return notice(content, duration, 'success', onClose);
success (options) {
const type = typeof options;
if (type === 'string') {
options = {
content: options
};
}
return notice(options.content, options.duration, 'success', options.onClose, options.closable);
},
warning (content, duration, onClose) {
return notice(content, duration, 'warning', onClose);
warning (options) {
const type = typeof options;
if (type === 'string') {
options = {
content: options
};
}
return notice(options.content, options.duration, 'warning', options.onClose, options.closable);
},
error (content, duration, onClose) {
return notice(content, duration, 'error', onClose);
error (options) {
const type = typeof options;
if (type === 'string') {
options = {
content: options
};
}
return notice(options.content, options.duration, 'error', options.onClose, options.closable);
},
loading (content, duration, onClose) {
return notice(content, duration, 'loading', onClose);
loading (options) {
const type = typeof options;
if (type === 'string') {
options = {
content: options
};
}
return notice(options.content, options.duration, 'loading', options.onClose, options.closable);
},
config (options) {
if (options.top) {
@ -92,6 +119,6 @@ export default {
destroy () {
let instance = getMessageInstance();
messageInstance = null;
instance.destroy();
instance.destroy('ivu-message');
}
};

View file

@ -1,8 +1,6 @@
import Vue from 'vue';
import Modal from './modal.vue';
import Icon from '../icon/icon.vue';
import iButton from '../button/button.vue';
import { camelcaseToHyphen } from '../../utils/assist';
import Button from '../button/button.vue';
import Locale from '../../mixins/locale';
const prefixCls = 'ivu-modal-confirm';
@ -10,36 +8,9 @@ const prefixCls = 'ivu-modal-confirm';
Modal.newInstance = properties => {
const _props = properties || {};
let props = '';
Object.keys(_props).forEach(prop => {
props += ' :' + camelcaseToHyphen(prop) + '=' + prop;
});
const div = document.createElement('div');
div.innerHTML = `
<Modal${props} v-model="visible" :width="width" :scrollable="scrollable">
<div class="${prefixCls}">
<div class="${prefixCls}-head">
<div class="${prefixCls}-head-title" v-html="title"></div>
</div>
<div class="${prefixCls}-body">
<div :class="iconTypeCls"><i :class="iconNameCls"></i></div>
<div v-html="body"></div>
</div>
<div class="${prefixCls}-footer">
<i-button type="text" size="large" v-if="showCancel" @click.native="cancel">{{ localeCancelText }}</i-button>
<i-button type="primary" size="large" :loading="buttonLoading" @click.native="ok">{{ localeOkText }}</i-button>
</div>
</div>
</Modal>
`;
document.body.appendChild(div);
const modal = new Vue({
el: div,
const Instance = new Vue({
mixins: [ Locale ],
components: { Modal, iButton, Icon },
data: Object.assign(_props, {
data: Object.assign({}, _props, {
visible: false,
width: 416,
title: '',
@ -53,6 +24,101 @@ Modal.newInstance = properties => {
buttonLoading: false,
scrollable: false
}),
render (h) {
let footerVNodes = [];
if (this.showCancel) {
footerVNodes.push(h(Button, {
props: {
type: 'text',
size: 'large'
},
on: {
click: this.cancel
}
}, this.localeCancelText));
}
footerVNodes.push(h(Button, {
props: {
type: 'primary',
size: 'large',
loading: this.buttonLoading
},
on: {
click: this.ok
}
}, this.localeOkText));
// render content
let body_render;
if (this.render) {
body_render = h('div', {
attrs: {
class: `${prefixCls}-body ${prefixCls}-body-render`
}
}, [this.render(h)]);
} else {
body_render = h('div', {
attrs: {
class: `${prefixCls}-body`
}
}, [
h('div', {
class: this.iconTypeCls
}, [
h('i', {
class: this.iconNameCls
})
]),
h('div', {
domProps: {
innerHTML: this.body
}
})
]);
}
return h(Modal, {
props: Object.assign({}, _props, {
width: this.width,
scrollable: this.scrollable
}),
domProps: {
value: this.visible
},
on: {
input: (status) => {
this.visible = status;
}
}
}, [
h('div', {
attrs: {
class: prefixCls
}
}, [
h('div', {
attrs: {
class: `${prefixCls}-head`
}
}, [
h('div', {
attrs: {
class: `${prefixCls}-head-title`
},
domProps: {
innerHTML: this.title
}
})
]),
body_render,
h('div', {
attrs: {
class: `${prefixCls}-footer`
}
}, footerVNodes)
])
]);
},
computed: {
iconTypeCls () {
return [
@ -111,7 +177,11 @@ Modal.newInstance = properties => {
onCancel () {},
onRemove () {}
}
}).$children[0];
});
const component = Instance.$mount();
document.body.appendChild(component.$el);
const modal = Instance.$children[0];
return {
show (props) {

View file

@ -2,18 +2,20 @@ import Modal from './confirm';
let modalInstance;
function getModalInstance () {
function getModalInstance (render = undefined) {
modalInstance = modalInstance || Modal.newInstance({
closable: false,
maskClosable: false,
footerHide: true
footerHide: true,
render: render
});
return modalInstance;
}
function confirm (options) {
let instance = getModalInstance();
const render = ('render' in options) ? options.render : undefined;
let instance = getModalInstance(render);
options.onRemove = function () {
modalInstance = null;

View file

@ -71,7 +71,8 @@ function notice (type, options) {
transitionName: 'move-notice',
content: content,
onClose: onClose,
closable: true
closable: true,
type: 'notice'
});
}
@ -112,6 +113,6 @@ export default {
destroy () {
let instance = getNoticeInstance();
noticeInstance = null;
instance.destroy();
instance.destroy('ivu-notice');
}
};

View file

@ -127,7 +127,8 @@
inputLength: 20,
notFound: false,
slotChangeDuration: false, // if slot change duration and in multiple, set true and after slot change, set false
model: this.value
model: this.value,
currentLabel: this.label
};
},
computed: {
@ -593,15 +594,15 @@
if (this.remote) {
if (!this.multiple && this.model !== '') {
this.selectToChangeQuery = true;
if (this.label === '') this.label = this.model;
this.lastQuery = this.label;
this.query = this.label;
if (this.currentLabel === '') this.currentLabel = this.model;
this.lastQuery = this.currentLabel;
this.query = this.currentLabel;
} else if (this.multiple && this.model.length) {
if (this.label.length !== this.model.length) this.label = this.model;
if (this.currentLabel.length !== this.model.length) this.currentLabel = this.model;
this.selectedMultiple = this.model.map((item, index) => {
return {
value: item,
label: this.label[index]
label: this.currentLabel[index]
};
});
}

View file

@ -6,7 +6,7 @@
</template>
<template v-if="renderType === 'html'"><span v-html="row[column.key]"></span></template>
<template v-if="renderType === 'normal'"><span>{{row[column.key]}}</span></template>
<template v-if="renderType === 'expand'">
<template v-if="renderType === 'expand' && !row._disableExpand">
<div :class="expandCls" @click="toggleExpand">
<Icon type="ios-arrow-right"></Icon>
</div>

View file

@ -11,7 +11,7 @@
type: String
},
label: {
type: String,
type: [String, Function],
default: ''
},
icon: {

View file

@ -8,7 +8,8 @@
<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>
{{ item.label }}
<Render v-if="item.labelType === 'function'" :render="item.label"></Render>
<template v-else>{{ item.label }}</template>
<Icon v-if="showClose(item)" type="ios-close-empty" @click.native.stop="handleRemove(index)"></Icon>
</div>
</div>
@ -22,6 +23,7 @@
</template>
<script>
import Icon from '../icon/icon.vue';
import Render from '../base/render.vue';
import { oneOf, getStyle } from '../../utils/assist';
import Emitter from '../../mixins/emitter';
@ -30,7 +32,7 @@
export default {
name: 'Tabs',
mixins: [ Emitter ],
components: { Icon },
components: { Icon, Render },
props: {
value: {
type: [String, Number]
@ -128,6 +130,7 @@
this.navList = [];
this.getTabs().forEach((pane, index) => {
this.navList.push({
labelType: typeof pane.label,
label: pane.label,
icon: pane.icon || '',
name: pane.currentName || index,

View file

@ -1,32 +1,33 @@
<template>
<transition name="slide-up">
<collapse-transition>
<ul :class="classes" v-show="visible">
<li>
<span :class="arrowClasses" @click="handleExpand">
<Icon type="arrow-right-b"></Icon>
</span>
<Checkbox
v-if="showCheckbox"
:value="data.checked"
:indeterminate="indeterminate"
:disabled="data.disabled || data.disableCheckbox"
@click.native.prevent="handleCheck"></Checkbox>
v-if="showCheckbox"
:value="data.checked"
:indeterminate="indeterminate"
:disabled="data.disabled || data.disableCheckbox"
@click.native.prevent="handleCheck"></Checkbox>
<span :class="titleClasses" v-html="data.title" @click="handleSelect"></span>
<Tree-node
v-for="item in data.children"
:key="item"
:data="item"
:visible="data.expand"
:multiple="multiple"
:show-checkbox="showCheckbox">
v-for="item in data.children"
:key="item"
:data="item"
:visible="data.expand"
:multiple="multiple"
:show-checkbox="showCheckbox">
</Tree-node>
</li>
</ul>
</transition>
</collapse-transition>
</template>
<script>
import Checkbox from '../checkbox/checkbox.vue';
import Icon from '../icon/icon.vue';
import CollapseTransition from '../base/collapse-transition';
import Emitter from '../../mixins/emitter';
import { findComponentsDownward } from '../../utils/assist';
@ -35,7 +36,7 @@
export default {
name: 'TreeNode',
mixins: [ Emitter ],
components: { Checkbox, Icon },
components: { Checkbox, Icon, CollapseTransition },
props: {
data: {
type: Object,

View file

@ -18,6 +18,7 @@ const directive = {
inserted (el, { value }, vnode) {
el.className = el.className ? el.className + ' v-transfer-dom' : 'v-transfer-dom';
const parentNode = el.parentNode;
if (!parentNode) return;
const home = document.createComment('');
let hasMovedOut = false;
@ -38,6 +39,7 @@ const directive = {
componentUpdated (el, { value }) {
// need to make sure children are done updating (vs. `update`)
const ref$1 = el.__transferDomData;
if (!ref$1) return;
// homes.get(el)
const parentNode = ref$1.parentNode;
const home = ref$1.home;
@ -59,7 +61,9 @@ const directive = {
}
},
unbind: function unbind (el, binding) {
el.className = el.className.replace('v-transfer-dom', '')
el.className = el.className.replace('v-transfer-dom', '');
const ref$1 = el.__transferDomData;
if (!ref$1) return;
if (el.__transferDomData.hasMovedOut === true) {
el.__transferDomData.parentNode && el.__transferDomData.parentNode.appendChild(el)
}

96
src/locale/lang/fr-FR.js Normal file
View file

@ -0,0 +1,96 @@
export default {
i: {
select: {
placeholder: 'Sélectionnez',
noMatch: 'Aucun résultat',
loading: 'Chargement'
},
table: {
noDataText: 'Aucune donnée',
noFilteredDataText: 'No filter data',
confirmFilter: 'Confirmez',
resetFilter: 'Reset',
clearFilter: 'Tout'
},
datepicker: {
selectDate: 'Sélectionnez une date',
selectTime: 'Sélectionnez une heure',
startTime: 'Heure de début',
endTime: 'Heure de fin',
clear: 'Annuler',
ok: 'OK',
month: '',
month1: 'Janvier',
month2: 'Février',
month3: 'Mars',
month4: 'Avril',
month5: 'Mai',
month6: 'Juin',
month7: 'Juillet',
month8: 'Août',
month9: 'Septembre',
month10: 'Octobre',
month11: 'Novembre',
month12: 'Decembre',
year: '',
weeks: {
sun: 'Dim',
mon: 'Lun',
tue: 'Mar',
wed: 'Mer',
thu: 'Jeu',
fri: 'Ven',
sat: 'Sam'
},
months: {
m1: 'Jan',
m2: 'Fev',
m3: 'Mar',
m4: 'Avr',
m5: 'Mai',
m6: 'Jun',
m7: 'Jul',
m8: 'Aoû',
m9: 'Sep',
m10: 'Oct',
m11: 'Nov',
m12: 'Déc'
}
},
transfer: {
titles: {
source: 'Source',
target: 'Cible'
},
filterPlaceholder: 'Recherche',
notFoundText: 'Pas de résultat'
},
modal: {
okText: 'OK',
cancelText: 'Annuler'
},
poptip: {
okText: 'OK',
cancelText: 'Annuler'
},
page: {
prev: 'Page Précédente',
next: 'Page Suivante',
total: 'Total',
item: 'élément',
items: 'éléments',
prev5: '5 Pages en Avant',
next5: '5 Pages en Arrière',
page: '/page',
goto: 'Aller à',
p: ''
},
rate: {
star: 'Étoile',
stars: 'Étoiles'
},
tree: {
emptyText: 'Aucune donnée'
}
}
};

View file

@ -25,4 +25,8 @@
@import "fade";
@import "move";
@import "ease";
@import "slide";
@import "slide";
.collapse-transition {
transition: @transition-time height ease-in-out, @transition-time padding-top ease-in-out, @transition-time padding-bottom ease-in-out;
}

View file

@ -14,6 +14,18 @@
vertical-align: middle;
position: absolute;
left: 50%;
&-close {
position: absolute;
right: 4px;
top: 9px;
color: #999;
outline: none;
i.@{icon-prefix-cls}{
.close-base(-3px);
}
}
}
&-notice-content {
@ -25,6 +37,15 @@
box-shadow: @shadow-base;
background: #fff;
display: block;
&-text{
display: inline-block;
}
}
&-notice-closable{
.@{message-prefix-cls}-notice-content-text{
padding-right: 32px;
}
}
&-success .@{icon-prefix-cls} {

View file

@ -98,6 +98,11 @@
color: @text-color;
position: relative;
&-render{
margin: 0;
padding: 0;
}
&-icon {
font-size: 36px;
position: absolute;

View file

@ -232,4 +232,66 @@ function findComponentsDownward (context, componentName, components = []) {
}
return components;
}
export {findComponentsDownward};
export {findComponentsDownward};
/* istanbul ignore next */
const trim = function(string) {
return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '');
};
/* istanbul ignore next */
export function hasClass(el, cls) {
if (!el || !cls) return false;
if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.');
if (el.classList) {
return el.classList.contains(cls);
} else {
return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1;
}
}
/* istanbul ignore next */
export function addClass(el, cls) {
if (!el) return;
let curClass = el.className;
const classes = (cls || '').split(' ');
for (let i = 0, j = classes.length; i < j; i++) {
const clsName = classes[i];
if (!clsName) continue;
if (el.classList) {
el.classList.add(clsName);
} else {
if (!hasClass(el, clsName)) {
curClass += ' ' + clsName;
}
}
}
if (!el.classList) {
el.className = curClass;
}
}
/* istanbul ignore next */
export function removeClass(el, cls) {
if (!el || !cls) return;
const classes = cls.split(' ');
let curClass = ' ' + el.className + ' ';
for (let i = 0, j = classes.length; i < j; i++) {
const clsName = classes[i];
if (!clsName) continue;
if (el.classList) {
el.classList.remove(clsName);
} else {
if (hasClass(el, clsName)) {
curClass = curClass.replace(' ' + clsName + ' ', ' ');
}
}
}
if (!el.classList) {
el.className = trim(curClass);
}
}