mirror of https://github.com/ElemeFE/element
Merge remote-tracking branch 'eleme/dev' into es-doc
# Conflicts: # examples/app.vuepull/8230/head
commit
de86b737e3
|
@ -6,7 +6,7 @@
|
|||
"expect": true,
|
||||
"sinon": true
|
||||
},
|
||||
"plugins": ['vue'],
|
||||
"plugins": ['vue','json'],
|
||||
"extends": 'elemefe',
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
## Changelog
|
||||
|
||||
### 2.0.4
|
||||
|
||||
*2017-11-10*
|
||||
|
||||
- Improved accessibility for Cascader, Dropdown, Message, Notification, Popover, Tooltip and Tree
|
||||
- Fixed Container resize when the width of viewport decreases, #8042
|
||||
- Fixed Tree's `updateKeyChildren` incorrectly deleting child nodes, #8100
|
||||
- Fixed bordered CheckboxButton's height when nested in a Form, #8100
|
||||
- Fixed Menu's parsing error for custom colors, #8153 (by @zhouyixiang)
|
||||
|
||||
### 2.0.3
|
||||
|
||||
*2017-11-03*
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
## 更新日志
|
||||
|
||||
### 2.0.4
|
||||
|
||||
*2017-11-10*
|
||||
|
||||
- 提升 Cascader、Dropdown、Message、Notification、Popover、Tooltip、Tree 的可访问性
|
||||
- 修复当视口变窄时 Container 无法同步更新其宽度的问题,#8042
|
||||
- 修复 Tree 的 `updateKeyChildren` 在删除子节点时的行为错误,#8100
|
||||
- 修复带有边框的 CheckboxButton 在 Form 中高度错误的问题,#8100
|
||||
- 修复 Menu 在解析自定义颜色时的错误,#8153(by @zhouyixiang)
|
||||
|
||||
### 2.0.3
|
||||
|
||||
*2017-11-03*
|
||||
|
|
|
@ -191,7 +191,6 @@
|
|||
|
||||
const lang = location.hash.replace('#', '').split('/')[1] || 'zh-CN';
|
||||
const localize = lang => {
|
||||
console.log(lang);
|
||||
switch (lang) {
|
||||
case 'zh-CN':
|
||||
use(zhLocale);
|
||||
|
@ -232,6 +231,7 @@
|
|||
const preferGithub = localStorage.getItem('PREFER_GITHUB');
|
||||
if (href.indexOf('element-cn') > -1 || preferGithub) return;
|
||||
setTimeout(() => {
|
||||
if (this.lang !== 'zh-CN') return;
|
||||
this.$confirm('建议大陆用户访问部署在国内的站点,是否跳转?', '提示')
|
||||
.then(() => {
|
||||
location.href = location.href.replace('element.', 'element-cn.');
|
||||
|
@ -249,12 +249,12 @@
|
|||
this.suggestJump();
|
||||
}
|
||||
setTimeout(() => {
|
||||
const notified = localStorage.getItem('RELEASE_NOTIFIED');
|
||||
if (!notified) {
|
||||
const notified = localStorage.getItem('ES_NOTIFIED');
|
||||
if (!notified && this.lang !== 'zh-CN') {
|
||||
const h = this.$createElement;
|
||||
const title = this.lang === 'zh-CN'
|
||||
? '2.0 正式发布'
|
||||
: '2.0 available now';
|
||||
? '帮助我们完成西班牙语文档'
|
||||
: 'Help us with Spanish docs';
|
||||
const messages = this.lang === 'zh-CN'
|
||||
? ['点击', '这里', '查看详情']
|
||||
: ['Click ', 'here', ' to learn more'];
|
||||
|
@ -266,13 +266,13 @@
|
|||
h('a', {
|
||||
attrs: {
|
||||
target: '_blank',
|
||||
href: `https://github.com/ElemeFE/element/issues/${ this.lang === 'zh-CN' ? '7755' : '7756' }`
|
||||
href: 'https://github.com/ElemeFE/element/issues/8074'
|
||||
}
|
||||
}, messages[1]),
|
||||
messages[2]
|
||||
]),
|
||||
onClose() {
|
||||
localStorage.setItem('RELEASE_NOTIFIED', 1);
|
||||
localStorage.setItem('ES_NOTIFIED', 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -101,6 +101,7 @@
|
|||
value8: '',
|
||||
value9: [],
|
||||
value10: [],
|
||||
value11: [],
|
||||
loading: false,
|
||||
states: ["Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"]
|
||||
};
|
||||
|
@ -320,7 +321,7 @@ You can clear Select using a clear icon.
|
|||
|
||||
Multiple select uses tags to display selected options.
|
||||
|
||||
:::demo Set `multiple` attribute for `el-select` to enable multiple mode. In this case, the value of `v-model` will be an array of selected options.
|
||||
:::demo Set `multiple` attribute for `el-select` to enable multiple mode. In this case, the value of `v-model` will be an array of selected options. By default the selected options will be displayed as Tags. You can collapse them to a text by using `collapse-tags` attribute.
|
||||
```html
|
||||
<template>
|
||||
<el-select v-model="value5" multiple placeholder="Select">
|
||||
|
@ -331,6 +332,20 @@ Multiple select uses tags to display selected options.
|
|||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
|
||||
<el-select
|
||||
v-model="value11"
|
||||
multiple
|
||||
collapse-tags
|
||||
style="margin-left: 20px;"
|
||||
placeholder="Select">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -650,6 +665,7 @@ If the binding value of Select is an object, make sure to assign `value-key` as
|
|||
| value-key | unique identity key name for value, required when value is an object | string | — | value |
|
||||
| size | size of Input | string | large/small/mini | — |
|
||||
| clearable | whether single select can be cleared | boolean | — | false |
|
||||
| collapse-tags | whether to collapse tags to a text when multiple selecting | boolean | — | false |
|
||||
| multiple-limit | maximum number of options user can select when `multiple` is `true`. No limit when set to 0 | number | — | 0 |
|
||||
| name | the name attribute of select input | string | — | — |
|
||||
| placeholder | placeholder | string | — | Select |
|
||||
|
|
|
@ -101,6 +101,7 @@
|
|||
value8: '',
|
||||
value9: '',
|
||||
value10: [],
|
||||
value11: [],
|
||||
loading: false,
|
||||
states: ["Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"]
|
||||
};
|
||||
|
@ -319,7 +320,7 @@
|
|||
|
||||
适用性较广的基础多选,用 Tag 展示已选项
|
||||
|
||||
:::demo 为`el-select`设置`multiple`属性即可启用多选,此时`v-model`的值为当前选中值所组成的数组
|
||||
:::demo 为`el-select`设置`multiple`属性即可启用多选,此时`v-model`的值为当前选中值所组成的数组。默认情况下选中值会以 Tag 的形式展现,你也可以设置`collapse-tags`属性将它们合并为一段文字。
|
||||
```html
|
||||
<template>
|
||||
<el-select v-model="value5" multiple placeholder="请选择">
|
||||
|
@ -330,6 +331,20 @@
|
|||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
|
||||
<el-select
|
||||
v-model="value11"
|
||||
multiple
|
||||
collapse-tags
|
||||
style="margin-left: 20px;"
|
||||
placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -645,6 +660,7 @@
|
|||
| value-key | 作为 value 唯一标识的键名,绑定值为对象类型时必填 | string | — | value |
|
||||
| size | 输入框尺寸 | string | large/small/mini | — |
|
||||
| clearable | 单选时是否可以清空选项 | boolean | — | false |
|
||||
| collapse-tags | 多选时是否将选中值按文字的形式展示 | boolean | — | false |
|
||||
| multiple-limit | 多选时用户最多可以选择的项目数,为 0 则不限制 | number | — | 0 |
|
||||
| name | select input 的 name 属性 | string | — | — |
|
||||
| placeholder | 占位符 | string | — | 请选择 |
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
},
|
||||
{
|
||||
"name": "Element Angular",
|
||||
"href": "https://eleme.github.io/element-angular/"
|
||||
"href": "https://element-angular.faas.ele.me/"
|
||||
},
|
||||
{
|
||||
"name": "开发指南",
|
||||
|
@ -260,7 +260,7 @@
|
|||
},
|
||||
{
|
||||
"name": "Element Angular",
|
||||
"href": "https://eleme.github.io/element-angular/"
|
||||
"href": "https://element-angular.faas.ele.me/"
|
||||
},
|
||||
{
|
||||
"name": "Development",
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"1.0.9":"1.0","1.1.6":"1.1","1.2.9":"1.2","1.3.7":"1.3","1.4.9":"1.4","2.0.3":"2.0"}
|
||||
{"1.0.9":"1.0","1.1.6":"1.1","1.2.9":"1.2","1.3.7":"1.3","1.4.9":"1.4","2.0.4":"2.0"}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "element-ui",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.4",
|
||||
"description": "A Component Library for Vue.js.",
|
||||
"main": "lib/element-ui.common.js",
|
||||
"files": [
|
||||
|
@ -82,6 +82,7 @@
|
|||
"css-loader": "^0.28.7",
|
||||
"es6-promise": "^4.0.5",
|
||||
"eslint": "^3.10.2",
|
||||
"eslint-plugin-json": "^1.2.0",
|
||||
"extract-text-webpack-plugin": "^3.0.1",
|
||||
"file-loader": "^1.1.5",
|
||||
"file-save": "^0.2.0",
|
||||
|
|
|
@ -10,9 +10,12 @@
|
|||
]"
|
||||
@click="handleClick"
|
||||
@mouseenter="inputHover = true"
|
||||
@focus="inputHover = true"
|
||||
@mouseleave="inputHover = false"
|
||||
@blur="inputHover = false"
|
||||
ref="reference"
|
||||
v-clickoutside="handleClickoutside"
|
||||
@keydown="handleKeydown"
|
||||
>
|
||||
<el-input
|
||||
ref="input"
|
||||
|
@ -63,6 +66,7 @@ import emitter from 'element-ui/src/mixins/emitter';
|
|||
import Locale from 'element-ui/src/mixins/locale';
|
||||
import { t } from 'element-ui/src/locale';
|
||||
import debounce from 'throttle-debounce/debounce';
|
||||
import { generateId } from 'element-ui/src/utils/util';
|
||||
|
||||
const popperMixin = {
|
||||
props: {
|
||||
|
@ -149,6 +153,10 @@ export default {
|
|||
beforeFilter: {
|
||||
type: Function,
|
||||
default: () => (() => {})
|
||||
},
|
||||
hoverThreshold: {
|
||||
type: Number,
|
||||
default: 500
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -191,11 +199,15 @@ export default {
|
|||
},
|
||||
cascaderSize() {
|
||||
return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
|
||||
},
|
||||
id() {
|
||||
return generateId();
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
menuVisible(value) {
|
||||
this.$refs.input.$refs.input.setAttribute('aria-expanded', value);
|
||||
value ? this.showMenu() : this.hideMenu();
|
||||
},
|
||||
value(value) {
|
||||
|
@ -204,6 +216,10 @@ export default {
|
|||
currentValue(value) {
|
||||
this.dispatch('ElFormItem', 'el.form.change', [value]);
|
||||
},
|
||||
currentLabels(value) {
|
||||
const inputLabel = this.showAllLevels ? value.join('/') : value[value.length - 1] ;
|
||||
this.$refs.input.$refs.input.setAttribute('value', inputLabel);
|
||||
},
|
||||
options: {
|
||||
deep: true,
|
||||
handler(value) {
|
||||
|
@ -224,10 +240,13 @@ export default {
|
|||
this.menu.expandTrigger = this.expandTrigger;
|
||||
this.menu.changeOnSelect = this.changeOnSelect;
|
||||
this.menu.popperClass = this.popperClass;
|
||||
this.menu.hoverThreshold = this.hoverThreshold;
|
||||
this.popperElm = this.menu.$el;
|
||||
this.menu.$refs.menus[0].setAttribute('id', `cascader-menu-${this.id}`);
|
||||
this.menu.$on('pick', this.handlePick);
|
||||
this.menu.$on('activeItemChange', this.handleActiveItemChange);
|
||||
this.menu.$on('menuLeave', this.doDestroy);
|
||||
this.menu.$on('closeInside', this.handleClickoutside);
|
||||
},
|
||||
showMenu() {
|
||||
if (!this.menu) {
|
||||
|
@ -245,6 +264,7 @@ export default {
|
|||
hideMenu() {
|
||||
this.inputValue = '';
|
||||
this.menu.visible = false;
|
||||
this.$refs.input.focus();
|
||||
},
|
||||
handleActiveItemChange(value) {
|
||||
this.$nextTick(_ => {
|
||||
|
@ -252,6 +272,23 @@ export default {
|
|||
});
|
||||
this.$emit('active-item-change', value);
|
||||
},
|
||||
handleKeydown(e) {
|
||||
const keyCode = e.keyCode;
|
||||
if (keyCode === 13) {
|
||||
this.handleClick();
|
||||
} else if (keyCode === 40) { // down
|
||||
this.menuVisible = true; // 打开
|
||||
setTimeout(() => {
|
||||
const firstMenu = this.popperElm.querySelectorAll('.el-cascader-menu')[0];
|
||||
firstMenu.querySelectorAll("[tabindex='-1']")[0].focus();
|
||||
});
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
} else if (keyCode === 27 || keyCode === 9) { // esc tab
|
||||
this.inputValue = '';
|
||||
if (this.menu) this.menu.visible = false;
|
||||
}
|
||||
},
|
||||
handlePick(value, close = true) {
|
||||
this.currentValue = value;
|
||||
this.$emit('input', value);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { isDef } from 'element-ui/src/utils/shared';
|
||||
import scrollIntoView from 'element-ui/src/utils/scroll-into-view';
|
||||
import { generateId } from 'element-ui/src/utils/util';
|
||||
|
||||
const copyArray = (arr, props) => {
|
||||
if (!arr || !Array.isArray(arr) || !props) return arr;
|
||||
|
@ -39,7 +40,8 @@
|
|||
value: [],
|
||||
expandTrigger: 'click',
|
||||
changeOnSelect: false,
|
||||
popperClass: ''
|
||||
popperClass: '',
|
||||
hoverTimer: 0
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -94,6 +96,9 @@
|
|||
formatOptions(optionsCopy);
|
||||
return loadActiveOptions(optionsCopy);
|
||||
}
|
||||
},
|
||||
id() {
|
||||
return generateId();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -135,11 +140,41 @@
|
|||
activeOptions,
|
||||
visible,
|
||||
expandTrigger,
|
||||
popperClass
|
||||
popperClass,
|
||||
hoverThreshold
|
||||
} = this;
|
||||
let itemId = null;
|
||||
let itemIndex = 0;
|
||||
|
||||
let hoverMenuRefs = {};
|
||||
const hoverMenuHandler = e => {
|
||||
const offsetX = e.offsetX;
|
||||
const width = hoverMenuRefs.activeMenu.offsetWidth;
|
||||
const height = hoverMenuRefs.activeMenu.offsetHeight;
|
||||
|
||||
if (e.target === hoverMenuRefs.activeItem) {
|
||||
clearTimeout(this.hoverTimer);
|
||||
const {activeItem} = hoverMenuRefs;
|
||||
const offsetY_top = activeItem.offsetTop;
|
||||
const offsetY_Bottom = offsetY_top + activeItem.offsetHeight;
|
||||
|
||||
hoverMenuRefs.hoverZone.innerHTML = `
|
||||
<path style="pointer-events: auto;" fill="transparent" d="M${offsetX} ${offsetY_top} L${width} 0 V${offsetY_top} Z" />
|
||||
<path style="pointer-events: auto;" fill="transparent" d="M${offsetX} ${offsetY_Bottom} L${width} ${height} V${offsetY_Bottom} Z" />
|
||||
`;
|
||||
} else {
|
||||
if (!this.hoverTimer) {
|
||||
this.hoverTimer = setTimeout(() => {
|
||||
hoverMenuRefs.hoverZone.innerHTML = '';
|
||||
}, hoverThreshold);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const menus = this._l(activeOptions, (menu, menuIndex) => {
|
||||
let isFlat = false;
|
||||
const menuId = `menu-${this.id}-${ menuIndex}`;
|
||||
const ownsId = `menu-${this.id}-${ menuIndex + 1 }`;
|
||||
const items = this._l(menu, item => {
|
||||
const events = {
|
||||
on: {}
|
||||
|
@ -148,12 +183,52 @@
|
|||
if (item.__IS__FLAT__OPTIONS) isFlat = true;
|
||||
|
||||
if (!item.disabled) {
|
||||
// keydown up/down/left/right/enter
|
||||
events.on.keydown = (ev) => {
|
||||
const keyCode = ev.keyCode;
|
||||
if (![37, 38, 39, 40, 13, 9, 27].indexOf(keyCode) > -1) {
|
||||
return;
|
||||
}
|
||||
const currentEle = ev.target;
|
||||
const parentEle = this.$refs.menus[menuIndex];
|
||||
const menuItemList = parentEle.querySelectorAll("[tabindex='-1']");
|
||||
const currentIndex = Array.prototype.indexOf.call(menuItemList, currentEle); // 当前索引
|
||||
let nextIndex, nextMenu;
|
||||
if ([38, 40].indexOf(keyCode) > -1) {
|
||||
if (keyCode === 38) { // up键
|
||||
nextIndex = currentIndex !== 0 ? (currentIndex - 1) : currentIndex;
|
||||
} else if (keyCode === 40) { // down
|
||||
nextIndex = currentIndex !== (menuItemList.length - 1) ? currentIndex + 1 : currentIndex;
|
||||
}
|
||||
menuItemList[nextIndex].focus();
|
||||
} else if (keyCode === 37) { // left键
|
||||
if (menuIndex !== 0) {
|
||||
const previousMenu = this.$refs.menus[menuIndex - 1];
|
||||
previousMenu.querySelector('[aria-expanded=true]').focus();
|
||||
}
|
||||
} else if (keyCode === 39) { // right
|
||||
if (item.children) {
|
||||
// 有子menu 选择子menu的第一个menuitem
|
||||
nextMenu = this.$refs.menus[menuIndex + 1];
|
||||
nextMenu.querySelectorAll("[tabindex='-1']")[0].focus();
|
||||
}
|
||||
} else if (keyCode === 13) {
|
||||
if (!item.children) {
|
||||
const id = currentEle.getAttribute('id');
|
||||
parentEle.setAttribute('aria-activedescendant', id);
|
||||
this.select(item, menuIndex);
|
||||
this.$nextTick(() => this.scrollMenu(this.$refs.menus[menuIndex]));
|
||||
}
|
||||
} else if (keyCode === 9 || keyCode === 27) { // esc tab
|
||||
this.$emit('closeInside');
|
||||
}
|
||||
};
|
||||
if (item.children) {
|
||||
let triggerEvent = {
|
||||
click: 'click',
|
||||
hover: 'mouseenter'
|
||||
}[expandTrigger];
|
||||
events.on[triggerEvent] = () => {
|
||||
events.on[triggerEvent] = events.on['focus'] = () => { // focus 选中
|
||||
this.activeItem(item, menuIndex);
|
||||
this.$nextTick(() => {
|
||||
// adjust self and next level
|
||||
|
@ -168,7 +243,10 @@
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (!item.disabled && !item.children) { // no children set id
|
||||
itemId = `${menuId}-${itemIndex}`;
|
||||
itemIndex++;
|
||||
}
|
||||
return (
|
||||
<li
|
||||
class={{
|
||||
|
@ -177,7 +255,14 @@
|
|||
'is-active': item.value === activeValue[menuIndex],
|
||||
'is-disabled': item.disabled
|
||||
}}
|
||||
ref={item.value === activeValue[menuIndex] ? 'activeItem' : null}
|
||||
{...events}
|
||||
tabindex= { item.disabled ? null : -1 }
|
||||
role="menuitem"
|
||||
aria-haspopup={ !!item.children }
|
||||
aria-expanded={ item.value === activeValue[menuIndex] }
|
||||
id = { itemId }
|
||||
aria-owns = { !item.children ? null : ownsId }
|
||||
>
|
||||
{item.label}
|
||||
</li>
|
||||
|
@ -188,19 +273,68 @@
|
|||
menuStyle.minWidth = this.inputWidth + 'px';
|
||||
}
|
||||
|
||||
const isHoveredMenu = expandTrigger === 'hover' && activeValue.length - 1 === menuIndex;
|
||||
const hoverMenuEvent = {
|
||||
on: {
|
||||
}
|
||||
};
|
||||
|
||||
if (isHoveredMenu) {
|
||||
hoverMenuEvent.on.mousemove = hoverMenuHandler;
|
||||
menuStyle.position = 'relative';
|
||||
}
|
||||
|
||||
return (
|
||||
<ul
|
||||
class={{
|
||||
'el-cascader-menu': true,
|
||||
'el-cascader-menu--flexible': isFlat
|
||||
}}
|
||||
{...hoverMenuEvent}
|
||||
style={menuStyle}
|
||||
refInFor
|
||||
ref="menus">
|
||||
ref="menus"
|
||||
role="menu"
|
||||
id = { menuId }
|
||||
>
|
||||
{items}
|
||||
{
|
||||
isHoveredMenu
|
||||
? (<svg
|
||||
ref="hoverZone"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
left: 0,
|
||||
pointerEvents: 'none'
|
||||
}}
|
||||
></svg>) : null
|
||||
}
|
||||
</ul>
|
||||
);
|
||||
});
|
||||
|
||||
if (expandTrigger === 'hover') {
|
||||
this.$nextTick(() => {
|
||||
const activeItem = this.$refs.activeItem;
|
||||
|
||||
if (activeItem) {
|
||||
const activeMenu = activeItem.parentElement;
|
||||
const hoverZone = this.$refs.hoverZone;
|
||||
|
||||
hoverMenuRefs = {
|
||||
activeMenu,
|
||||
activeItem,
|
||||
hoverZone
|
||||
};
|
||||
} else {
|
||||
hoverMenuRefs = {};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<transition name="el-zoom-in-top" on-before-enter={this.handleMenuEnter} on-after-leave={this.handleMenuLeave}>
|
||||
<div
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
'el-dropdown-menu__item--divided': divided
|
||||
}"
|
||||
@click="handleClick"
|
||||
:aria-disabled="disabled"
|
||||
:tabindex="disabled ? null : -1"
|
||||
>
|
||||
<slot></slot>
|
||||
</li>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
import Migrating from 'element-ui/src/mixins/migrating';
|
||||
import ElButton from 'element-ui/packages/button';
|
||||
import ElButtonGroup from 'element-ui/packages/button-group';
|
||||
import { generateId } from 'element-ui/src/utils/util';
|
||||
|
||||
export default {
|
||||
name: 'ElDropdown',
|
||||
|
@ -61,25 +62,43 @@
|
|||
return {
|
||||
timeout: null,
|
||||
visible: false,
|
||||
triggerElm: null
|
||||
triggerElm: null,
|
||||
menuItems: null,
|
||||
menuItemsArray: null,
|
||||
dropdownElm: null,
|
||||
focusing: false
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
dropdownSize() {
|
||||
return this.size || (this.$ELEMENT || {}).size;
|
||||
},
|
||||
listId() {
|
||||
return `dropdown-menu-${generateId()}`;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$on('menu-item-click', this.handleMenuItemClick);
|
||||
this.initEvent();
|
||||
this.initAria();
|
||||
},
|
||||
|
||||
watch: {
|
||||
visible(val) {
|
||||
this.broadcast('ElDropdownMenu', 'visible', val);
|
||||
this.$emit('visible-change', val);
|
||||
},
|
||||
focusing(val) {
|
||||
const selfDefine = this.$el.querySelector('.el-dropdown-selfdefine');
|
||||
if (selfDefine) { // 自定义
|
||||
if (val) {
|
||||
selfDefine.className += ' focusing';
|
||||
} else {
|
||||
selfDefine.className = selfDefine.className.replace('focusing', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -100,6 +119,8 @@
|
|||
},
|
||||
hide() {
|
||||
if (this.triggerElm.disabled) return;
|
||||
this.removeTabindex();
|
||||
this.resetTabindex(this.triggerElm);
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = setTimeout(() => {
|
||||
this.visible = false;
|
||||
|
@ -109,18 +130,98 @@
|
|||
if (this.triggerElm.disabled) return;
|
||||
this.visible = !this.visible;
|
||||
},
|
||||
handleTriggerKeyDown(ev) {
|
||||
const keyCode = ev.keyCode;
|
||||
if ([38, 40].indexOf(keyCode) > -1) { // up/down
|
||||
this.removeTabindex();
|
||||
this.resetTabindex(this.menuItems[0]);
|
||||
this.menuItems[0].focus();
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
} else if (keyCode === 13) { // space enter选中
|
||||
this.handleClick();
|
||||
} else if ([9, 27].indexOf(keyCode) > -1) { // tab || esc
|
||||
this.hide();
|
||||
}
|
||||
return;
|
||||
},
|
||||
handleItemKeyDown(ev) {
|
||||
const keyCode = ev.keyCode;
|
||||
const target = ev.target;
|
||||
const currentIndex = this.menuItemsArray.indexOf(target);
|
||||
const max = this.menuItemsArray.length - 1;
|
||||
let nextIndex;
|
||||
if ([38, 40].indexOf(keyCode) > -1) { // up/down
|
||||
if (keyCode === 38) { // up
|
||||
nextIndex = currentIndex !== 0 ? currentIndex - 1 : 0;
|
||||
} else { // down
|
||||
nextIndex = currentIndex < max ? currentIndex + 1 : max;
|
||||
}
|
||||
this.removeTabindex();
|
||||
this.resetTabindex(this.menuItems[nextIndex]);
|
||||
this.menuItems[nextIndex].focus();
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
} else if (keyCode === 13) { // enter选中
|
||||
this.triggerElm.focus();
|
||||
target.click();
|
||||
if (!this.hideOnClick) { // click关闭
|
||||
this.visible = false;
|
||||
}
|
||||
} else if ([9, 27].indexOf(keyCode) > -1) { // tab // esc
|
||||
this.hide();
|
||||
this.triggerElm.focus();
|
||||
}
|
||||
return;
|
||||
},
|
||||
resetTabindex(ele) { // 下次tab时组件聚焦元素
|
||||
this.removeTabindex();
|
||||
ele.setAttribute('tabindex', '0'); // 下次期望的聚焦元素
|
||||
},
|
||||
removeTabindex() {
|
||||
this.triggerElm.setAttribute('tabindex', '-1');
|
||||
this.menuItemsArray.forEach((item) => {
|
||||
item.setAttribute('tabindex', '-1');
|
||||
});
|
||||
},
|
||||
initAria() {
|
||||
this.dropdownElm.setAttribute('id', this.listId);
|
||||
this.triggerElm.setAttribute('aria-haspopup', 'list');
|
||||
this.triggerElm.setAttribute('aria-controls', this.listId);
|
||||
this.menuItems = this.dropdownElm.querySelectorAll("[tabindex='-1']");
|
||||
this.menuItemsArray = Array.prototype.slice.call(this.menuItems);
|
||||
|
||||
if (!this.splitButton) { // 自定义
|
||||
this.triggerElm.setAttribute('role', 'button');
|
||||
this.triggerElm.setAttribute('tabindex', '0');
|
||||
this.triggerElm.className += ' el-dropdown-selfdefine'; // 控制
|
||||
}
|
||||
},
|
||||
initEvent() {
|
||||
let { trigger, show, hide, handleClick, splitButton } = this;
|
||||
let { trigger, show, hide, handleClick, splitButton, handleTriggerKeyDown, handleItemKeyDown } = this;
|
||||
this.triggerElm = splitButton
|
||||
? this.$refs.trigger.$el
|
||||
: this.$slots.default[0].elm;
|
||||
|
||||
let dropdownElm = this.dropdownElm = this.$slots.dropdown[0].elm;
|
||||
|
||||
this.triggerElm.addEventListener('keydown', handleTriggerKeyDown); // triggerElm keydown
|
||||
dropdownElm.addEventListener('keydown', handleItemKeyDown, true); // item keydown
|
||||
// 控制自定义元素的样式
|
||||
if (!splitButton) {
|
||||
this.triggerElm.addEventListener('focus', () => {
|
||||
this.focusing = true;
|
||||
});
|
||||
this.triggerElm.addEventListener('blur', () => {
|
||||
this.focusing = false;
|
||||
});
|
||||
this.triggerElm.addEventListener('click', () => {
|
||||
this.focusing = false;
|
||||
});
|
||||
}
|
||||
if (trigger === 'hover') {
|
||||
this.triggerElm.addEventListener('mouseenter', show);
|
||||
this.triggerElm.addEventListener('mouseleave', hide);
|
||||
|
||||
let dropdownElm = this.$slots.dropdown[0].elm;
|
||||
|
||||
dropdownElm.addEventListener('mouseenter', show);
|
||||
dropdownElm.addEventListener('mouseleave', hide);
|
||||
} else if (trigger === 'click') {
|
||||
|
|
|
@ -157,14 +157,14 @@
|
|||
},
|
||||
getColorChannels(color) {
|
||||
color = color.replace('#', '');
|
||||
if (/^[1-9a-fA-F]{3}$/.test(color)) {
|
||||
if (/^[0-9a-fA-F]{3}$/.test(color)) {
|
||||
color = color.split('');
|
||||
for (let i = 2; i >= 0; i--) {
|
||||
color.splice(i, 0, color[i]);
|
||||
}
|
||||
color = color.join('');
|
||||
}
|
||||
if (/^[1-9a-fA-F]{6}$/.test(color)) {
|
||||
if (/^[0-9a-fA-F]{6}$/.test(color)) {
|
||||
return {
|
||||
red: parseInt(color.slice(0, 2), 16),
|
||||
green: parseInt(color.slice(2, 4), 16),
|
||||
|
|
|
@ -173,11 +173,13 @@
|
|||
},
|
||||
handleTitleMouseenter() {
|
||||
if (this.mode === 'horizontal' && !this.rootMenu.backgroundColor) return;
|
||||
this.$refs['submenu-title'].style.backgroundColor = this.rootMenu.hoverBackground;
|
||||
const title = this.$refs['submenu-title'];
|
||||
title && (title.style.backgroundColor = this.rootMenu.hoverBackground);
|
||||
},
|
||||
handleTitleMouseleave() {
|
||||
if (this.mode === 'horizontal' && !this.rootMenu.backgroundColor) return;
|
||||
this.$refs['submenu-title'].style.backgroundColor = this.rootMenu.backgroundColor || '';
|
||||
const title = this.$refs['submenu-title'];
|
||||
title && (title.style.backgroundColor = this.rootMenu.backgroundColor || '');
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
|
|
@ -9,15 +9,15 @@
|
|||
v-show="visible"
|
||||
@mouseenter="clearTimer"
|
||||
@mouseleave="startTimer"
|
||||
role="alertdialog"
|
||||
role="alert"
|
||||
>
|
||||
<i :class="iconClass" v-if="iconClass"></i>
|
||||
<i :class="typeClass" v-else></i>
|
||||
<slot>
|
||||
<p v-if="!dangerouslyUseHTMLString" class="el-message__content" tabindex="0">{{ message }}</p>
|
||||
<p v-else v-html="message" class="el-message__content" tabindex="0"></p>
|
||||
<p v-if="!dangerouslyUseHTMLString" class="el-message__content">{{ message }}</p>
|
||||
<p v-else v-html="message" class="el-message__content"></p>
|
||||
</slot>
|
||||
<i v-if="showClose" class="el-message__closeBtn el-icon-close" @click="close" tabindex="0" role="button" aria-label="close" @keydown.enter.stop="close"></i>
|
||||
<i v-if="showClose" class="el-message__closeBtn el-icon-close" @click="close"></i>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
@ -44,9 +44,7 @@
|
|||
closed: false,
|
||||
timer: null,
|
||||
dangerouslyUseHTMLString: false,
|
||||
center: false,
|
||||
initFocus: null,
|
||||
originFocus: null
|
||||
center: false
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -87,18 +85,6 @@
|
|||
if (typeof this.onClose === 'function') {
|
||||
this.onClose(this);
|
||||
}
|
||||
if (!this.originFocus || !this.originFocus.getBoundingClientRect) return;
|
||||
|
||||
// restore keyboard focus
|
||||
const { top, left, bottom, right } = this.originFocus.getBoundingClientRect();
|
||||
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
||||
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
|
||||
if (top >= 0 &&
|
||||
left >= 0 &&
|
||||
bottom <= viewportHeight &&
|
||||
right <= viewportWidth) {
|
||||
this.originFocus.focus();
|
||||
}
|
||||
},
|
||||
|
||||
clearTimer() {
|
||||
|
@ -115,24 +101,15 @@
|
|||
}
|
||||
},
|
||||
keydown(e) {
|
||||
if (e.keyCode === 46 || e.keyCode === 8) {
|
||||
this.clearTimer(); // detele 取消倒计时
|
||||
} else if (e.keyCode === 27) { // esc关闭消息
|
||||
if (e.keyCode === 27) { // esc关闭消息
|
||||
if (!this.closed) {
|
||||
this.close();
|
||||
}
|
||||
} else {
|
||||
this.startTimer(); // 恢复倒计时
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.startTimer();
|
||||
this.originFocus = document.activeElement;
|
||||
this.initFocus = this.showClose ? this.$el.querySelector('.el-icon-close') : this.$el.querySelector('.el-message__content');
|
||||
setTimeout(() => {
|
||||
this.initFocus && this.initFocus.focus();
|
||||
});
|
||||
document.addEventListener('keydown', this.keydown);
|
||||
},
|
||||
beforeDestroy() {
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
:style="positionStyle"
|
||||
@mouseenter="clearTimer()"
|
||||
@mouseleave="startTimer()"
|
||||
@click="click">
|
||||
@click="click"
|
||||
role="alert"
|
||||
>
|
||||
<i
|
||||
class="el-notification__icon"
|
||||
:class="[ typeClass, iconClass ]"
|
||||
|
@ -119,9 +121,19 @@
|
|||
}
|
||||
}, this.duration);
|
||||
}
|
||||
},
|
||||
keydown(e) {
|
||||
if (e.keyCode === 46 || e.keyCode === 8) {
|
||||
this.clearTimer(); // detele 取消倒计时
|
||||
} else if (e.keyCode === 27) { // esc关闭消息
|
||||
if (!this.closed) {
|
||||
this.close();
|
||||
}
|
||||
} else {
|
||||
this.startTimer(); // 恢复倒计时
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.duration > 0) {
|
||||
this.timer = setTimeout(() => {
|
||||
|
@ -130,6 +142,11 @@
|
|||
}
|
||||
}, this.duration);
|
||||
}
|
||||
document.addEventListener('keydown', this.keydown);
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('keydown', this.keydown);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -6,7 +6,11 @@
|
|||
:class="[popperClass, content && 'el-popover--plain']"
|
||||
ref="popper"
|
||||
v-show="!disabled && showPopper"
|
||||
:style="{ width: width + 'px' }">
|
||||
:style="{ width: width + 'px' }"
|
||||
role="tooltip"
|
||||
:id="tooltipId"
|
||||
:aria-hidden="(disabled || !showPopper) ? 'true' : 'false'"
|
||||
>
|
||||
<div class="el-popover__title" v-if="title" v-text="title"></div>
|
||||
<slot>{{ content }}</slot>
|
||||
</div>
|
||||
|
@ -14,10 +18,11 @@
|
|||
<slot name="reference"></slot>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Popper from 'element-ui/src/utils/vue-popper';
|
||||
import { on, off } from 'element-ui/src/utils/dom';
|
||||
import { addClass, removeClass } from 'element-ui/src/utils/dom';
|
||||
import { generateId } from 'element-ui/src/utils/util';
|
||||
|
||||
export default {
|
||||
name: 'ElPopover',
|
||||
|
@ -49,25 +54,35 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
tooltipId() {
|
||||
return `el-popover-${generateId()}`;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
showPopper(newVal, oldVal) {
|
||||
newVal ? this.$emit('show') : this.$emit('hide');
|
||||
},
|
||||
'$refs.reference': {
|
||||
deep: true,
|
||||
handler(val) {
|
||||
console.log(val);
|
||||
}
|
||||
showPopper(val) {
|
||||
val ? this.$emit('show') : this.$emit('hide');
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
let reference = this.reference || this.$refs.reference;
|
||||
let reference = this.referenceElm = this.reference || this.$refs.reference;
|
||||
const popper = this.popper || this.$refs.popper;
|
||||
|
||||
if (!reference && this.$slots.reference && this.$slots.reference[0]) {
|
||||
reference = this.referenceElm = this.$slots.reference[0].elm;
|
||||
}
|
||||
// 可访问性
|
||||
if (reference) {
|
||||
addClass(reference, 'el-popover__reference');
|
||||
reference.setAttribute('aria-describedby', this.tooltipId);
|
||||
reference.setAttribute('tabindex', 0); // tab序列
|
||||
|
||||
this.trigger !== 'click' && on(reference, 'focus', this.handleFocus);
|
||||
this.trigger !== 'click' && on(reference, 'blur', this.handleBlur);
|
||||
on(reference, 'keydown', this.handleKeydown);
|
||||
on(reference, 'click', this.handleClick);
|
||||
}
|
||||
if (this.trigger === 'click') {
|
||||
on(reference, 'click', this.doToggle);
|
||||
on(document, 'click', this.handleDocumentClick);
|
||||
|
@ -114,6 +129,17 @@ export default {
|
|||
doClose() {
|
||||
this.showPopper = false;
|
||||
},
|
||||
handleFocus() {
|
||||
addClass(this.referenceElm, 'focusing');
|
||||
this.showPopper = true;
|
||||
},
|
||||
handleClick() {
|
||||
removeClass(this.referenceElm, 'focusing');
|
||||
},
|
||||
handleBlur() {
|
||||
removeClass(this.referenceElm, 'focusing');
|
||||
this.showPopper = false;
|
||||
},
|
||||
handleMouseEnter() {
|
||||
clearTimeout(this._timer);
|
||||
if (this.openDelay) {
|
||||
|
@ -124,6 +150,11 @@ export default {
|
|||
this.showPopper = true;
|
||||
}
|
||||
},
|
||||
handleKeydown(ev) {
|
||||
if (ev.keyCode === 27) { // esc
|
||||
this.doClose();
|
||||
}
|
||||
},
|
||||
handleMouseLeave() {
|
||||
clearTimeout(this._timer);
|
||||
this._timer = setTimeout(() => {
|
||||
|
|
|
@ -53,9 +53,10 @@
|
|||
},
|
||||
mounted() {
|
||||
// 当radioGroup没有默认选项时,第一个可以选中Tab导航
|
||||
let radios = this.$el.querySelectorAll('[type=radio]');
|
||||
if (![].some.call(radios, radio => radio.checked)) {
|
||||
this.$el.querySelectorAll('[role=radio]')[0].tabIndex = 0;
|
||||
const radios = this.$el.querySelectorAll('[type=radio]');
|
||||
const firstLabel = this.$el.querySelectorAll('[role=radio]')[0];
|
||||
if (![].some.call(radios, radio => radio.checked) && firstLabel) {
|
||||
firstLabel.tabIndex = 0;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<ul class="el-select-group__wrap">
|
||||
<li class="el-select-group__title" v-show="visible">{{ label }}</li>
|
||||
<ul class="el-select-group__wrap" v-show="visible">
|
||||
<li class="el-select-group__title">{{ label }}</li>
|
||||
<li>
|
||||
<ul class="el-select-group">
|
||||
<slot></slot>
|
||||
|
|
|
@ -9,7 +9,12 @@
|
|||
@click.stop="toggleMenu"
|
||||
ref="tags"
|
||||
:style="{ 'max-width': inputWidth - 32 + 'px' }">
|
||||
<transition-group @after-leave="resetInputHeight">
|
||||
<span
|
||||
class="el-select__multiple-text"
|
||||
v-if="collapseTags">
|
||||
{{ multipleText }}
|
||||
</span>
|
||||
<transition-group @after-leave="resetInputHeight" v-if="!collapseTags">
|
||||
<el-tag
|
||||
v-for="item in selected"
|
||||
:key="getValueKey(item)"
|
||||
|
@ -29,6 +34,7 @@
|
|||
:class="[selectSize ? `is-${ selectSize }` : '']"
|
||||
:disabled="disabled"
|
||||
@focus="handleFocus"
|
||||
@click.stop
|
||||
@keyup="managePlaceholder"
|
||||
@keydown="resetInputState"
|
||||
@keydown.down.prevent="navigateOptions('next')"
|
||||
|
@ -183,6 +189,14 @@
|
|||
|
||||
selectSize() {
|
||||
return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
|
||||
},
|
||||
|
||||
multipleText() {
|
||||
const selected = this.selected;
|
||||
if (!selected || !selected.length) return '';
|
||||
const length = selected.length;
|
||||
const countText = length > 1 ? `(+${ selected.length - 1 })` : '';
|
||||
return `${ selected[0].currentLabel } ${ countText }`;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -231,7 +245,8 @@
|
|||
valueKey: {
|
||||
type: String,
|
||||
default: 'value'
|
||||
}
|
||||
},
|
||||
collapseTags: Boolean
|
||||
},
|
||||
|
||||
data() {
|
||||
|
@ -534,6 +549,7 @@
|
|||
},
|
||||
|
||||
resetInputHeight() {
|
||||
if (this.collapseTags) return;
|
||||
this.$nextTick(() => {
|
||||
if (!this.$refs.reference) return;
|
||||
let inputChildNodes = this.$refs.reference.$el.childNodes;
|
||||
|
|
|
@ -119,12 +119,10 @@ export default {
|
|||
{
|
||||
column.sortable
|
||||
? <span class="caret-wrapper" on-click={ ($event) => this.handleSortClick($event, column) }>
|
||||
<span class="sort-caret ascending" on-click={ ($event) => this.handleSortClick($event, column, 'ascending') }>
|
||||
<i class="el-icon-sort-up"></i>
|
||||
</span>
|
||||
<span class="sort-caret descending" on-click={ ($event) => this.handleSortClick($event, column, 'descending') }>
|
||||
<i class="el-icon-sort-down"></i>
|
||||
</span>
|
||||
<i class="sort-caret ascending el-icon-caret-top" on-click={ ($event) => this.handleSortClick($event, column, 'ascending') }>
|
||||
</i>
|
||||
<i class="sort-caret descending el-icon-caret-bottom" on-click={ ($event) => this.handleSortClick($event, column, 'descending') }>
|
||||
</i>
|
||||
</span>
|
||||
: ''
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "element-theme-chalk",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.4",
|
||||
"description": "Element component chalk theme.",
|
||||
"main": "lib/index.css",
|
||||
"style": "lib/index.css",
|
||||
|
@ -28,7 +28,8 @@
|
|||
"devDependencies": {
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-cssmin": "^0.1.7",
|
||||
"gulp-sass": "^3.1.0"
|
||||
"gulp-sass": "^3.1.0",
|
||||
"gulp-autoprefixer": "^4.0.0"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@
|
|||
line-height: 1.5;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
|
||||
outline: none;
|
||||
@include m(extensible) {
|
||||
&:after {
|
||||
font-family: 'element-icons';
|
||||
|
@ -154,7 +154,7 @@
|
|||
color: $--select-option-selected;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&:hover, &:focus:not(:active) {
|
||||
background-color: $--select-option-hover-background;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
padding: $--checkbox-bordered-padding;
|
||||
border-radius: $--border-radius-base;
|
||||
border: $--border-base;
|
||||
box-sizing: border-box;
|
||||
line-height: normal;
|
||||
height: $--checkbox-bordered-height;
|
||||
|
||||
&.is-checked {
|
||||
border-color: $--color-primary;
|
||||
|
@ -34,6 +37,7 @@
|
|||
&.el-checkbox--medium {
|
||||
padding: $--checkbox-bordered-medium-padding;
|
||||
border-radius: $--button-medium-border-radius;
|
||||
height: $--checkbox-bordered-medium-height;
|
||||
|
||||
.el-checkbox__label {
|
||||
line-height: 17px;
|
||||
|
@ -49,6 +53,7 @@
|
|||
&.el-checkbox--small {
|
||||
padding: $--checkbox-bordered-small-padding;
|
||||
border-radius: $--button-small-border-radius;
|
||||
height: $--checkbox-bordered-small-height;
|
||||
|
||||
.el-checkbox__label {
|
||||
line-height: 15px;
|
||||
|
@ -69,6 +74,7 @@
|
|||
&.el-checkbox--mini {
|
||||
padding: $--checkbox-bordered-mini-padding;
|
||||
border-radius: $--button-mini-border-radius;
|
||||
height: $--checkbox-bordered-mini-height;
|
||||
|
||||
.el-checkbox__label {
|
||||
line-height: 12px;
|
||||
|
|
|
@ -137,16 +137,20 @@ $--checkbox-checked-icon-color: $--fill-base !default;
|
|||
|
||||
$--checkbox-input-border-color-hover: $--color-primary !default;
|
||||
|
||||
$--checkbox-bordered-height: 40px !default;
|
||||
$--checkbox-bordered-padding: 9px 20px 9px 10px !default;
|
||||
$--checkbox-bordered-medium-padding: 7px 20px 7px 10px !default;
|
||||
$--checkbox-bordered-small-padding: 3px 15px 7px 10px !default;
|
||||
$--checkbox-bordered-mini-padding: 1px 15px 5px 10px !default;
|
||||
$--checkbox-bordered-small-padding: 5px 15px 5px 10px !default;
|
||||
$--checkbox-bordered-mini-padding: 3px 15px 3px 10px !default;
|
||||
$--checkbox-bordered-medium-input-height: 14px !default;
|
||||
$--checkbox-bordered-medium-input-width: 14px !default;
|
||||
$--checkbox-bordered-medium-height: 36px !default;
|
||||
$--checkbox-bordered-small-input-height: 12px !default;
|
||||
$--checkbox-bordered-small-input-width: 12px !default;
|
||||
$--checkbox-bordered-small-height: 32px !default;
|
||||
$--checkbox-bordered-mini-input-height: 12px !default;
|
||||
$--checkbox-bordered-mini-input-width: 12px !default;
|
||||
$--checkbox-bordered-mini-height: 28px !default;
|
||||
|
||||
$--checkbox-button-font-size: $--font-size-base !default;
|
||||
$--checkbox-button-checked-fill: $--color-primary !default;
|
||||
|
@ -183,16 +187,20 @@ $--radio-checked-icon-color: $--color-primary !default;
|
|||
|
||||
$--radio-input-border-color-hover: $--color-primary !default;
|
||||
|
||||
$--radio-bordered-padding: 10px 20px 10px 10px !default;
|
||||
$--radio-bordered-medium-padding: 8px 20px 8px 10px !default;
|
||||
$--radio-bordered-small-padding: 6px 15px 6px 10px !default;
|
||||
$--radio-bordered-mini-padding: 4px 15px 4px 10px !default;
|
||||
$--radio-bordered-height: 40px !default;
|
||||
$--radio-bordered-padding: 12px 20px 0 10px !default;
|
||||
$--radio-bordered-medium-padding: 10px 20px 0 10px !default;
|
||||
$--radio-bordered-small-padding: 8px 15px 0 10px !default;
|
||||
$--radio-bordered-mini-padding: 6px 15px 0 10px !default;
|
||||
$--radio-bordered-medium-input-height: 14px !default;
|
||||
$--radio-bordered-medium-input-width: 14px !default;
|
||||
$--radio-bordered-medium-height: 36px !default;
|
||||
$--radio-bordered-small-input-height: 12px !default;
|
||||
$--radio-bordered-small-input-width: 12px !default;
|
||||
$--radio-bordered-small-height: 32px !default;
|
||||
$--radio-bordered-mini-input-height: 12px !default;
|
||||
$--radio-bordered-mini-input-width: 12px !default;
|
||||
$--radio-bordered-mini-height: 28px !default;
|
||||
|
||||
$--radio-button-font-size: $--font-size-base !default;
|
||||
$--radio-button-checked-fill: $--color-primary !default;
|
||||
|
|
|
@ -50,6 +50,12 @@
|
|||
font-size: 12px;
|
||||
margin: 0 3px;
|
||||
}
|
||||
|
||||
.el-dropdown-selfdefine { // 自定义
|
||||
&:focus:active, &:focus:not(.focusing) {
|
||||
outline-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include b(dropdown-menu) {
|
||||
|
@ -72,8 +78,8 @@
|
|||
font-size: $--font-size-base;
|
||||
color: $--color-text-regular;
|
||||
cursor: pointer;
|
||||
|
||||
&:not(.is-disabled):hover {
|
||||
outline: none;
|
||||
&:not(.is-disabled):hover, &:focus {
|
||||
background-color: $--dropdown-menuItem-hover-fill;
|
||||
color: $--dropdown-menuItem-hover-color;
|
||||
}
|
||||
|
|
|
@ -27,4 +27,10 @@
|
|||
line-height: 1;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
@include e(reference) {
|
||||
&:focus:not(.focusing), &:focus:hover {
|
||||
outline-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
padding: $--radio-bordered-padding;
|
||||
border-radius: $--border-radius-base;
|
||||
border: $--border-base;
|
||||
box-sizing: border-box;
|
||||
height: $--radio-bordered-height;
|
||||
|
||||
&.is-checked {
|
||||
border-color: $--color-primary;
|
||||
|
@ -38,6 +40,7 @@
|
|||
&.is-bordered {
|
||||
padding: $--radio-bordered-medium-padding;
|
||||
border-radius: $--button-medium-border-radius;
|
||||
height: $--radio-bordered-medium-height;
|
||||
.el-radio__label {
|
||||
font-size: $--button-medium-font-size;
|
||||
}
|
||||
|
@ -51,6 +54,7 @@
|
|||
&.is-bordered {
|
||||
padding: $--radio-bordered-small-padding;
|
||||
border-radius: $--button-small-border-radius;
|
||||
height: $--radio-bordered-small-height;
|
||||
.el-radio__label {
|
||||
font-size: $--button-small-font-size;
|
||||
}
|
||||
|
@ -64,6 +68,7 @@
|
|||
&.is-bordered {
|
||||
padding: $--radio-bordered-mini-padding;
|
||||
border-radius: $--button-mini-border-radius;
|
||||
height: $--radio-bordered-mini-height;
|
||||
.el-radio__label {
|
||||
font-size: $--button-mini-font-size;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@import "mixins/mixins";
|
||||
@import "mixins/utils";
|
||||
@import "common/var";
|
||||
@import "select-dropdown";
|
||||
@import "input";
|
||||
|
@ -88,6 +89,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
@include e(multiple-text) {
|
||||
margin-left: 15px;
|
||||
color: $--input-color;
|
||||
font-size: $--font-size-base;
|
||||
display: block;
|
||||
@include utils-ellipsis;
|
||||
}
|
||||
|
||||
@include e(close) {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
|
|
|
@ -426,20 +426,29 @@
|
|||
}
|
||||
|
||||
.caret-wrapper {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
height: 13px;
|
||||
width: 24px;
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
overflow: initial;
|
||||
}
|
||||
|
||||
.sort-caret {
|
||||
color: $--icon-color-base;
|
||||
color: $--color-text-placeholder;
|
||||
width: 14px;
|
||||
overflow: hidden;
|
||||
font-size: 13px;
|
||||
font-size: 15px;
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
|
||||
&.ascending {
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
&.descending {
|
||||
bottom: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.ascending .sort-caret.ascending {
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
@import "common/var";
|
||||
|
||||
@include b(tooltip) {
|
||||
&:focus:not(.focusing), &:focus:hover {
|
||||
outline-width: 0;
|
||||
}
|
||||
@include e(popper) {
|
||||
position: absolute;
|
||||
border-radius: 4px;
|
||||
|
|
|
@ -25,7 +25,12 @@
|
|||
|
||||
@include b(tree-node) {
|
||||
white-space: nowrap;
|
||||
|
||||
outline: none;
|
||||
&:focus { /* focus */
|
||||
> .el-tree-node__content {
|
||||
background-color: $--tree-node-hover-color;
|
||||
}
|
||||
}
|
||||
@include e(content) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Popper from 'element-ui/src/utils/vue-popper';
|
||||
import debounce from 'throttle-debounce/debounce';
|
||||
import { getFirstComponentChild } from 'element-ui/src/utils/vdom';
|
||||
import { generateId } from 'element-ui/src/utils/util';
|
||||
import Vue from 'vue';
|
||||
|
||||
export default {
|
||||
|
@ -48,10 +49,15 @@ export default {
|
|||
|
||||
data() {
|
||||
return {
|
||||
timeoutPending: null
|
||||
timeoutPending: null,
|
||||
focusing: false
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
tooltipId() {
|
||||
return `el-tooltip-${generateId()}`;
|
||||
}
|
||||
},
|
||||
beforeCreate() {
|
||||
if (this.$isServer) return;
|
||||
|
||||
|
@ -75,6 +81,9 @@ export default {
|
|||
onMouseleave={ () => { this.setExpectedState(false); this.debounceClose(); } }
|
||||
onMouseenter= { () => { this.setExpectedState(true); } }
|
||||
ref="popper"
|
||||
role="tooltip"
|
||||
id={this.tooltipId}
|
||||
aria-hidden={ (this.disabled || !this.showPopper) ? 'true' : 'false' }
|
||||
v-show={!this.disabled && this.showPopper}
|
||||
class={
|
||||
['el-tooltip__popper', 'is-' + this.effect, this.popperClass]
|
||||
|
@ -87,24 +96,38 @@ export default {
|
|||
if (!this.$slots.default || !this.$slots.default.length) return this.$slots.default;
|
||||
|
||||
const vnode = getFirstComponentChild(this.$slots.default);
|
||||
|
||||
if (!vnode) return vnode;
|
||||
|
||||
const data = vnode.data = vnode.data || {};
|
||||
const on = vnode.data.on = vnode.data.on || {};
|
||||
const nativeOn = vnode.data.nativeOn = vnode.data.nativeOn || {};
|
||||
|
||||
data.staticClass = this.concatClass(data.staticClass, 'el-tooltip');
|
||||
on.mouseenter = this.addEventHandle(on.mouseenter, this.show);
|
||||
on.mouseleave = this.addEventHandle(on.mouseleave, this.hide);
|
||||
nativeOn.mouseenter = this.addEventHandle(nativeOn.mouseenter, this.show);
|
||||
nativeOn.mouseleave = this.addEventHandle(nativeOn.mouseleave, this.hide);
|
||||
|
||||
nativeOn.mouseenter = on.mouseenter = this.addEventHandle(on.mouseenter, this.show);
|
||||
nativeOn.mouseleave = on.mouseleave = this.addEventHandle(on.mouseleave, this.hide);
|
||||
nativeOn.focus = on.focus = this.addEventHandle(on.focus, this.handleFocus);
|
||||
nativeOn.blur = on.blur = this.addEventHandle(on.blur, this.handleBlur);
|
||||
nativeOn.click = on.click = this.addEventHandle(on.click, () => { this.focusing = false; });
|
||||
return vnode;
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.referenceElm = this.$el;
|
||||
if (this.$el.nodeType === 1) {
|
||||
this.$el.setAttribute('aria-describedby', this.tooltipId);
|
||||
this.$el.setAttribute('tabindex', 0);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
focusing(val) {
|
||||
if (val) {
|
||||
this.referenceElm.className += ' focusing';
|
||||
} else {
|
||||
this.referenceElm.className = this.referenceElm.className.replace('focusing', '');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
show() {
|
||||
this.setExpectedState(true);
|
||||
|
@ -115,7 +138,14 @@ export default {
|
|||
this.setExpectedState(false);
|
||||
this.debounceClose();
|
||||
},
|
||||
|
||||
handleFocus() {
|
||||
this.focusing = true;
|
||||
this.show();
|
||||
},
|
||||
handleBlur() {
|
||||
this.focusing = false;
|
||||
this.hide();
|
||||
},
|
||||
addEventHandle(old, fn) {
|
||||
if (!old) {
|
||||
return fn;
|
||||
|
|
|
@ -198,9 +198,10 @@ export default class TreeStore {
|
|||
const node = this.nodesMap[key];
|
||||
if (!node) return;
|
||||
const childNodes = node.childNodes;
|
||||
childNodes.forEach(child => {
|
||||
for (let i = childNodes.length - 1; i >= 0; i--) {
|
||||
const child = childNodes[i];
|
||||
this.remove(child.data);
|
||||
});
|
||||
}
|
||||
for (let i = 0, j = data.length; i < j; i++) {
|
||||
const child = data[i];
|
||||
this.append(child, node.data);
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
<template>
|
||||
<div class="el-tree-node"
|
||||
<div
|
||||
class="el-tree-node"
|
||||
@click.stop="handleClick"
|
||||
v-show="node.visible"
|
||||
:class="{
|
||||
'is-expanded': expanded,
|
||||
'is-current': tree.store.currentNode === node,
|
||||
'is-hidden': !node.visible
|
||||
}">
|
||||
'is-hidden': !node.visible,
|
||||
'is-focusable': !node.disabled,
|
||||
'is-checked': !node.disabled && node.checked
|
||||
}"
|
||||
role="treeitem"
|
||||
tabindex="-1"
|
||||
:aria-expanded="expanded"
|
||||
:aria-disabled="node.disabled"
|
||||
:aria-checked="node.checked"
|
||||
>
|
||||
<div class="el-tree-node__content"
|
||||
:style="{ 'padding-left': (node.level - 1) * tree.indent + 'px' }">
|
||||
<span
|
||||
|
@ -20,7 +29,8 @@
|
|||
:indeterminate="node.indeterminate"
|
||||
:disabled="!!node.disabled"
|
||||
@click.native.stop
|
||||
@change="handleCheckChange">
|
||||
@change="handleCheckChange"
|
||||
>
|
||||
</el-checkbox>
|
||||
<span
|
||||
v-if="node.loading"
|
||||
|
@ -32,7 +42,10 @@
|
|||
<div
|
||||
class="el-tree-node__children"
|
||||
v-if="childNodeRendered"
|
||||
v-show="expanded">
|
||||
v-show="expanded"
|
||||
role="group"
|
||||
:aria-expanded="expanded"
|
||||
>
|
||||
<el-tree-node
|
||||
:render-content="renderContent"
|
||||
v-for="child in node.childNodes"
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<template>
|
||||
<div class="el-tree" :class="{ 'el-tree--highlight-current': highlightCurrent }">
|
||||
<div
|
||||
class="el-tree"
|
||||
:class="{ 'el-tree--highlight-current': highlightCurrent }"
|
||||
role="tree"
|
||||
>
|
||||
<el-tree-node
|
||||
v-for="child in root.childNodes"
|
||||
:node="child"
|
||||
|
@ -33,7 +37,9 @@
|
|||
return {
|
||||
store: null,
|
||||
root: null,
|
||||
currentNode: null
|
||||
currentNode: null,
|
||||
treeItems: null,
|
||||
checkboxItems: []
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -101,6 +107,9 @@
|
|||
get() {
|
||||
return this.data;
|
||||
}
|
||||
},
|
||||
treeItemArray() {
|
||||
return Array.prototype.slice.call(this.treeItems);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -115,6 +124,11 @@
|
|||
},
|
||||
data(newVal) {
|
||||
this.store.setData(newVal);
|
||||
},
|
||||
checkboxItems(val) {
|
||||
Array.prototype.forEach.call(val, (checkbox) => {
|
||||
checkbox.setAttribute('tabindex', -1);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -171,6 +185,42 @@
|
|||
updateKeyChildren(key, data) {
|
||||
if (!this.nodeKey) throw new Error('[Tree] nodeKey is required in updateKeyChild');
|
||||
this.store.updateChildren(key, data);
|
||||
},
|
||||
initTabindex() {
|
||||
this.treeItems = this.$el.querySelectorAll('.is-focusable[role=treeitem]');
|
||||
this.checkboxItems = this.$el.querySelectorAll('input[type=checkbox]');
|
||||
const checkedItem = this.$el.querySelectorAll('.is-checked[role=treeitem]');
|
||||
if (checkedItem.length) {
|
||||
checkedItem[0].setAttribute('tabindex', 0);
|
||||
return;
|
||||
}
|
||||
this.treeItems[0].setAttribute('tabindex', 0);
|
||||
},
|
||||
handelKeydown(ev) {
|
||||
const currentItem = ev.target;
|
||||
const keyCode = ev.keyCode;
|
||||
this.treeItems = this.$el.querySelectorAll('.is-focusable[role=treeitem]');
|
||||
const currentIndex = this.treeItemArray.indexOf(currentItem);
|
||||
let nextIndex;
|
||||
if ([38, 40].indexOf(keyCode) > -1) { // up、down
|
||||
if (keyCode === 38) { // up
|
||||
nextIndex = currentIndex !== 0 ? currentIndex - 1 : 0;
|
||||
} else {
|
||||
nextIndex = (currentIndex < this.treeItemArray.length - 1) ? currentIndex + 1 : 0;
|
||||
}
|
||||
this.treeItemArray[nextIndex].focus(); // 选中
|
||||
}
|
||||
const hasInput = currentItem.querySelector('[type="checkbox"]');
|
||||
if ([37, 39].indexOf(keyCode) > -1) { // left、right 展开
|
||||
currentItem.click(); // 选中
|
||||
}
|
||||
if ([13, 32].indexOf(keyCode) > -1) { // space enter选中checkbox
|
||||
if (hasInput) {
|
||||
hasInput.click();
|
||||
}
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -194,6 +244,14 @@
|
|||
});
|
||||
|
||||
this.root = this.store.root;
|
||||
},
|
||||
mounted() {
|
||||
this.initTabindex();
|
||||
this.$el.addEventListener('keydown', this.handelKeydown);
|
||||
},
|
||||
updated() {
|
||||
this.treeItems = this.$el.querySelectorAll('[role=treeitem]');
|
||||
this.checkboxItems = this.$el.querySelectorAll('input[type=checkbox]');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
function getError(action, option, xhr) {
|
||||
let msg;
|
||||
if (xhr.response) {
|
||||
msg = `${xhr.status} ${xhr.response.error || xhr.response}`;
|
||||
msg = `${xhr.response.error || xhr.response}`;
|
||||
} else if (xhr.responseText) {
|
||||
msg = `${xhr.status} ${xhr.responseText}`;
|
||||
msg = `${xhr.responseText}`;
|
||||
} else {
|
||||
msg = `fail to post ${action} ${xhr.status}`;
|
||||
}
|
||||
|
|
|
@ -173,7 +173,7 @@ if (typeof window !== 'undefined' && window.Vue) {
|
|||
};
|
||||
|
||||
module.exports = {
|
||||
version: '2.0.3',
|
||||
version: '2.0.4',
|
||||
locale: locale.use,
|
||||
i18n: locale.i18n,
|
||||
install,
|
||||
|
|
|
@ -65,5 +65,6 @@ export default {
|
|||
break;
|
||||
}
|
||||
}
|
||||
delete el[ctx];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -41,7 +41,7 @@ describe('ajax', () => {
|
|||
});
|
||||
it('40x code should be error', done => {
|
||||
option.onError = e => {
|
||||
expect(e.toString()).to.contain('404 Not found');
|
||||
expect(e.toString()).to.contain('Not found');
|
||||
done();
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue