修复tree模式的节点显示异常

This commit is contained in:
maplemei 2020-11-27 19:19:22 +08:00
parent 1175612369
commit ca9453469e
13 changed files with 169 additions and 76 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
.DS_Store .DS_Store
node_modules/* node_modules/*
yarn.lock yarn.lock
*.zip

View File

@ -1,5 +1,20 @@
## 更新日志 ## 更新日志
### 1.2.1
*2020-11-27*
#### 新增
- 新增配置`enableKeyboard`, 用于控制是否使用键盘操作, 用于取消因为键盘事件带来的性能影响
- tree模式新增配置`clickExpand`, 是否点击节点即展开节点
- tree模式新增配置`clickCheck`, 是否点击节点即选中节点
#### Bug fixes
- [紧急修复]tree模式下节点超过2层, 父节点半选状态异常
### 1.2.0 ### 1.2.0
*2020-11-26* *2020-11-26*

2
dist/static/2.js vendored

File diff suppressed because one or more lines are too long

2
dist/static/3.js vendored

File diff suppressed because one or more lines are too long

2
dist/xm-select.js vendored

File diff suppressed because one or more lines are too long

View File

@ -20,6 +20,10 @@ tree: {
strict: true, strict: true,
//是否开启极简模式 //是否开启极简模式
simple: false, simple: false,
//点击节点是否展开
clickExpand: true,
//点击节点是否选中
clickCheck: true,
}, },
``` ```
@ -42,6 +46,11 @@ tree: {
<input type="checkbox" name="all" lay-filter="all" lay-skin="primary" title="展开所有节点"> <input type="checkbox" name="all" lay-filter="all" lay-skin="primary" title="展开所有节点">
<input type="checkbox" name="close" lay-filter="close" lay-skin="primary" title="闭合所有节点"> <input type="checkbox" name="close" lay-filter="close" lay-skin="primary" title="闭合所有节点">
<input type="checkbox" name="key3" lay-filter="key3" lay-skin="primary" title="展开指定节点"> <input type="checkbox" name="key3" lay-filter="key3" lay-skin="primary" title="展开指定节点">
<br/><br/>
<input type="checkbox" name="clickExpand" lay-filter="clickExpand" lay-skin="primary" title="clickExpand" checked>
<input type="checkbox" name="clickCheck" lay-filter="clickCheck" lay-skin="primary" title="clickExpand" checked>
</div> </div>
<div style="margin-top: 20px">间距</div> <div style="margin-top: 20px">间距</div>
@ -110,6 +119,22 @@ layui.form.on('checkbox(key3)', function(data){
} }
}); });
layui.form.on('checkbox(clickExpand)', function(data){
demo1.update({
tree: {
clickExpand: data.elem.checked
}
})
});
layui.form.on('checkbox(clickCheck)', function(data){
demo1.update({
tree: {
clickCheck: data.elem.checked
}
})
});
layui.slider.render({ layui.slider.render({
elem: '#slideTest1', elem: '#slideTest1',
min: 10, min: 10,

View File

@ -16,6 +16,8 @@ var demo1 = xmSelect.render({
indent: 20, indent: 20,
expandedKeys: [ -3 ], expandedKeys: [ -3 ],
simple: true, simple: true,
clickExpand: false,
clickCheck: false,
}, },
toolbar: { toolbar: {
show: true, show: true,

View File

@ -45,6 +45,7 @@
| layReqText | 表单验证, 同layui的lay-reqText | string | - | '' | | layReqText | 表单验证, 同layui的lay-reqText | string | - | '' |
| toolbar | 工具条, 具体看下表 | object | - | - | | toolbar | 工具条, 具体看下表 | object | - | - |
| showCount | 展示在下拉框中的最多选项数量 | int | - | 0 | | showCount | 展示在下拉框中的最多选项数量 | int | - | 0 |
| enableKeyboard | 是否启用键盘操作选项 | boolean | true / false | true |
| autoRow | 是否开启自动换行(选项过多时) | boolean | true / false | false | | autoRow | 是否开启自动换行(选项过多时) | boolean | true / false | false |
| size | 尺寸 | string | large / medium / small / mini | medium | | size | 尺寸 | string | large / medium / small / mini | medium |
| disabled | 是否禁用多选 | boolean | true / false | false | | disabled | 是否禁用多选 | boolean | true / false | false |
@ -189,6 +190,8 @@ list: [ "ALL", "CLEAR",
| strict | 是否遵循严格父子结构 | boolean | true / false | true | | strict | 是否遵循严格父子结构 | boolean | true / false | true |
| simple | 是否开启极简模式 | boolean | true / false | false | | simple | 是否开启极简模式 | boolean | true / false | false |
| nodeType | 标注节点类型的key | string | leaf: 叶子节点, parent: 父节点, half: 半选节点 | __node_type | | nodeType | 标注节点类型的key | string | leaf: 叶子节点, parent: 父节点, half: 半选节点 | __node_type |
| clickExpand | 点击节点是否展开, false时点击三角箭头进行展开操作| boolean | true / false | true |
| clickCheck | 点击节点是否选中, false时点击复选框进行选中操作 | boolean | true / false | true |
### cascader ### cascader

View File

@ -193,7 +193,7 @@ class Framework extends Component{
let child = parent[children]; let child = parent[children];
child.filter(item => !(item[disabled] || item.__node.disabled)).forEach(item => { child.filter(item => !(item[disabled] || item.__node.disabled)).forEach(item => {
if(item[optgroup]){ if(item[optgroup]){
this.treeHandler(sels, item, change, type); this.treeHandler(sels, item, change, type, changeStatus);
}else{ }else{
let index = sels.findIndex(sel => sel[value] == item[value]) let index = sels.findIndex(sel => sel[value] == item[value])
if(type === 'del'){ if(type === 'del'){
@ -255,9 +255,11 @@ class Framework extends Component{
}else{ }else{
handlerType = 'add'; handlerType = 'add';
} }
if(handlerType != 'half'){ if(handlerType != 'half'){
this.treeHandler(sels, item, change, handlerType); this.treeHandler(sels, item, change, handlerType);
} }
if(this.checkMax(change, change)){ if(this.checkMax(change, change)){
return ; return ;
} }

View File

@ -117,6 +117,8 @@ class Label extends Component{
this.props.onReset(e, 'labelSearch') this.props.onReset(e, 'labelSearch')
}} compositionend={ e => { }} compositionend={ e => {
this.props.onReset(e, 'labelSearch') this.props.onReset(e, 'labelSearch')
}} onClick={ e => {
e.stopPropagation();
}}></input> }}></input>
) )
}else{ }else{

View File

@ -165,45 +165,47 @@ class General extends Component{
} }
} }
const { value, optgroup, disabled } = this.props.prop; if(this.props.enableKeyboard){
let data = this.tempData.filter(item => !item[optgroup] && !item[disabled]); const { value, optgroup, disabled } = this.props.prop;
let len = data.length - 1; let data = this.tempData.filter(item => !item[optgroup] && !item[disabled]);
if(len === -1){ let len = data.length - 1;
return ; if(len === -1){
} return ;
}
let index = data.findIndex(item => item[value] === this.state.val); let index = data.findIndex(item => item[value] === this.state.val);
//Up 键 //Up 键
if(keyCode === 38){ if(keyCode === 38){
if(index <= 0){ if(index <= 0){
index = len index = len
}else if(index > 0){ }else if(index > 0){
index -= 1; index -= 1;
} }
let val = data[index][value]; let val = data[index][value];
this.setState({ val }) this.setState({ val })
//键盘选中时滚动到可视范围内 //键盘选中时滚动到可视范围内
let opt = this.base.querySelector(`.xm-option[value="${ val }"]`); let opt = this.base.querySelector(`.xm-option[value="${ val }"]`);
opt && opt.scrollIntoView(false) opt && opt.scrollIntoView(false)
}else }else
//Down 键 //Down 键
if(keyCode === 40){ if(keyCode === 40){
if(index === -1 || index === len){ if(index === -1 || index === len){
index = 0 index = 0
}else if(index < len){ }else if(index < len){
index += 1; index += 1;
} }
let val = data[index][value]; let val = data[index][value];
this.setState({ val }) this.setState({ val })
//键盘选中时滚动到可视范围内 //键盘选中时滚动到可视范围内
let opt = this.base.querySelector(`.xm-option[value="${ val }"]`); let opt = this.base.querySelector(`.xm-option[value="${ val }"]`);
opt && opt.scrollIntoView(false) opt && opt.scrollIntoView(false)
}else }else
//Enter 键 //Enter 键
if(keyCode === 13){ if(keyCode === 13){
if(this.state.val != emptyVal){ if(this.state.val != emptyVal){
let option = data[index]; let option = data[index];
this.optionClick(option, this.props.sels.findIndex(item => item[value] === this.state.val) != -1, option[disabled], e) this.optionClick(option, this.props.sels.findIndex(item => item[value] === this.state.val) != -1, option[disabled], e)
}
} }
} }
@ -237,7 +239,7 @@ class General extends Component{
} }
render(config) { render(config) {
let { data, flatData, prop, template, theme, radio, sels, empty, filterable, filterMethod, remoteSearch, remoteMethod, delay, searchTips, create, pageRemote, max } = config let { data, flatData, prop, template, theme, radio, sels, empty, filterable, filterMethod, remoteSearch, remoteMethod, delay, searchTips, create, pageRemote, max, enableKeyboard } = config
const { name, value, disabled, children, optgroup } = prop; const { name, value, disabled, children, optgroup } = prop;
@ -451,7 +453,7 @@ class General extends Component{
const itemStyle = {} const itemStyle = {}
//处理键盘的选择背景色 //处理键盘的选择背景色
if(item[value] === this.state.val){ if(enableKeyboard && item[value] === this.state.val){
itemStyle.backgroundColor = theme.hover itemStyle.backgroundColor = theme.hover
} }
//不显示图标时候的背景色处理 //不显示图标时候的背景色处理
@ -473,7 +475,19 @@ class General extends Component{
const hoverChange = e => { const hoverChange = e => {
if(e.type === 'mouseenter'){ if(e.type === 'mouseenter'){
if(!item[disabled]){ if(!item[disabled]){
this.setState({ val: item[value] }) if(enableKeyboard){
this.setState({ val: item[value] })
}else{
e.target.style.backgroundColor = theme.hover;
}
}
}else if(e.type === 'mouseleave'){
if(!item[disabled]){
if(enableKeyboard){
}else{
e.target.style.backgroundColor = '';
}
} }
} }
} }

View File

@ -58,31 +58,43 @@ class Tree extends Component{
} }
const { tree, prop, sels } = this.props; const { tree, prop, sels } = this.props;
const { clickExpand, clickCheck } = tree;
//不是父节点的不需要处理 //检测点击的是不是三角箭头
if(!tree.lazy && !item[prop.optgroup]){ let isExpand = e.target && isFunction(e.target.getAttribute) && e.target.getAttribute('type') === 'expand'
this.props.ck(item, selected, disabled); //如果点击即展开
return if(clickExpand || isExpand){
//不是父节点的不需要处理
if(!tree.lazy && !item[prop.optgroup]){
this.props.ck(item, selected, disabled);
return
}
let val = item[this.props.prop.value];
let expandedKeys = this.state.expandedKeys;
let index = expandedKeys.findIndex(v => v === val);
index === -1 ? expandedKeys.push(val) : expandedKeys.splice(index, 1);
this.setState({ expandedKeys });
//是否需要懒加载
let child = item[prop.children];
if(tree.lazy && child && child.length === 0 && item.__node.loading !== false){
item.__node.loading = true;
tree.load(item, (result) => {
item.__node.loading = false;
item[prop.children] = this.handlerData(result, prop.children);
item[prop.selected] = sels.findIndex(i => i[prop.value] === item[prop.value]) != -1
this.props.onReset(sels, 'treeData');
});
}
}else{
if(clickCheck){
type = 'checkbox'
}
} }
}
let val = item[this.props.prop.value]; if(type === 'checkbox'){
let expandedKeys = this.state.expandedKeys;
let index = expandedKeys.findIndex(v => v === val);
index === -1 ? expandedKeys.push(val) : expandedKeys.splice(index, 1);
this.setState({ expandedKeys });
//是否需要懒加载
let child = item[prop.children];
if(tree.lazy && child && child.length === 0 && item.__node.loading !== false){
item.__node.loading = true;
tree.load(item, (result) => {
item.__node.loading = false;
item[prop.children] = this.handlerData(result, prop.children);
item[prop.selected] = sels.findIndex(i => i[prop.value] === item[prop.value]) != -1
this.props.onReset(sels, 'treeData');
});
}
}else if(type === 'checkbox'){
this.props.ck(item, selected, disabled); this.props.ck(item, selected, disabled);
} }
//阻止父组件上的事件冒泡 //阻止父组件上的事件冒泡
@ -218,7 +230,7 @@ class Tree extends Component{
} }
render(config, { expandedKeys }) { render(config, { expandedKeys }) {
let { prop, empty, sels, theme, radio, template, data, tree, filterable, remoteSearch, searchTips, iconfont } = config; let { prop, empty, sels, theme, radio, template, data, tree, filterable, remoteSearch, searchTips, iconfont, enableKeyboard } = config;
let { name, value, disabled, children, optgroup } = prop; let { name, value, disabled, children, optgroup } = prop;
let showIcon = config.model.icon != 'hidden'; let showIcon = config.model.icon != 'hidden';
@ -246,7 +258,7 @@ class Tree extends Component{
const itemStyle = { paddingLeft: indent + 'px' } const itemStyle = { paddingLeft: indent + 'px' }
//处理键盘的选择背景色 //处理键盘的选择背景色
if(item[value] === this.state.val){ if(enableKeyboard && item[value] === this.state.val){
itemStyle.backgroundColor = theme.hover itemStyle.backgroundColor = theme.hover
} }
@ -279,7 +291,7 @@ class Tree extends Component{
const iconArray = []; const iconArray = [];
if(tree.showFolderIcon){ if(tree.showFolderIcon){
iconArray.push(<i class={ treeIconClass }></i>); iconArray.push(<i class={ treeIconClass } type="expand"></i>);
if(tree.showLine){ if(tree.showLine){
if(expand){ if(expand){
iconArray.push(<i class='left-line' style={ {left: indent - tree.indent + 3 + 'px'} }></i>) iconArray.push(<i class='left-line' style={ {left: indent - tree.indent + 3 + 'px'} }></i>)
@ -293,7 +305,19 @@ class Tree extends Component{
const hoverChange = e => { const hoverChange = e => {
if(e.type === 'mouseenter'){ if(e.type === 'mouseenter'){
if(!item[disabled]){ if(!item[disabled]){
this.setState({ val: item[value] }) if(enableKeyboard){
this.setState({ val: item[value] })
}else{
e.target.style.backgroundColor = theme.hover;
}
}
}else if(e.type === 'mouseleave'){
if(!item[disabled]){
if(enableKeyboard){
}else{
e.target.style.backgroundColor = '';
}
} }
} }
} }
@ -349,7 +373,6 @@ class Tree extends Component{
//工具条操作 //工具条操作
function flat(list, array){ function flat(list, array){
//array.forEach(item => item[optgroup] ? (!tree.strict && list.push(item), flat(list, item[children])) : list.push(item))
array.forEach(item => { array.forEach(item => {
if(item[optgroup]){ if(item[optgroup]){
//非严格模式, 如果隐藏父节点, 证明不可选 //非严格模式, 如果隐藏父节点, 证明不可选

View File

@ -79,6 +79,8 @@ export default function (lan = 'zn') {
maxMethod: function(sels, item){}, maxMethod: function(sels, item){},
//选项显示数量 //选项显示数量
showCount: 0, showCount: 0,
//是否开启键盘操作
enableKeyboard: true,
//工具条 //工具条
toolbar: { toolbar: {
show: false, show: false,
@ -107,6 +109,10 @@ export default function (lan = 'zn') {
simple: false, simple: false,
//标注节点类型的key //标注节点类型的key
nodeType: '__node_type', nodeType: '__node_type',
//点击节点是否展开
clickExpand: true,
//点击节点是否选中
clickCheck: true,
}, },
//级联结构 //级联结构
cascader: { cascader: {