This commit is contained in:
maplemei 2020-05-04 18:56:31 +08:00
parent 308e0b64e1
commit 1ae32b8ed1
15 changed files with 176 additions and 98 deletions

View File

@ -1,5 +1,22 @@
## 更新日志
### 1.1.9
*2020-05-04*
#### 新增
- tree新增配置`simple`, 代表极简模式, 子级全部被选中后只会显示父级
#### Bug fixes
- 设置远程模式`totalSize`默认为1
- 修复普通多选模式下设置`max`配置后, 工具条的全选和反选 选中数据错误
- 修复`getValue`方法获取到的部分数据中携带`__node`参数无法进行序列化
- 修复同时开启远程搜索和远程分页的时候会出发两次`remoteMethod`
- 优化`remoteMethod`的内部回调机制
### 1.1.8
*2020-02-10*

4
dist/static/2.js vendored

File diff suppressed because one or more lines are too long

4
dist/static/3.js vendored

File diff suppressed because one or more lines are too long

4
dist/static/docs.js vendored

File diff suppressed because one or more lines are too long

4
dist/xm-select.js vendored

File diff suppressed because one or more lines are too long

View File

@ -18,6 +18,8 @@ tree: {
expandedKeys: [],
//是否严格遵守父子模式
strict: true,
//是否开启极简模式
simple: false,
},
```
@ -32,6 +34,7 @@ tree: {
<input type="checkbox" name="showFolderIcon" lay-filter="showFolderIcon" lay-skin="primary" title="是否展示三角图标" checked>
<input type="checkbox" name="showLine" lay-filter="showLine" lay-skin="primary" title="是否显示虚线" checked>
<input type="checkbox" name="strict" lay-filter="strict" lay-skin="primary" title="严格父子结构" checked>
<input type="checkbox" name="simple" lay-filter="simple" lay-skin="primary" title="极简模式">
</div>
<div style="margin-top: 20px">间距</div>
@ -41,7 +44,7 @@ tree: {
<script>
layui.form.render();
['showFolderIcon', 'showLine', 'strict'].forEach(function(key){
['showFolderIcon', 'showLine', 'strict', 'simple'].forEach(function(key){
layui.form.on('checkbox('+key+')', function(data){
var treeConfig = {};
treeConfig[key] = data.elem.checked;
@ -366,4 +369,4 @@ var demo5 = xmSelect.render({
</script>
```
:::
:::

View File

@ -8,35 +8,29 @@
var demo1 = xmSelect.render({
el: '#demo1',
autoRow: true,
filterable: true,
cascader: {
show: true,
indent: 100,
height: '300px',
tree: {
show: false,
simple: true,
expandedKeys: [-1],
},
height: '100px',
toolbar: {
show: true,
list: ['ALL', 'REVERSE', 'CLEAR']
},
filterable: true,
paging: true,
pageRemote: true,
remoteSearch: true,
remoteMethod(val, cb, show, pageIndex){
cb([
{name: '张三11111111111', value: 1, selected: true, children: []},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3, disabled: false},
])
},
data(){
return [
{name: '销售员', value: -1, disabled: true, children: [
{name: '张三11111111111', value: 1, selected: true, children: []},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3, disabled: true},
]},
{name: '奖品', value: -2, children: [
{name: '奖品3333333333', value: -3, children: [
{name: '苹果3', value: 14, selected: true},
{name: '香蕉3', value: 15},
{name: '葡萄3', value: 16},
]},
{name: '苹果2', value: 4, selected: true, disabled: true},
{name: '香蕉2', value: 5},
{name: '葡萄2', value: 6},
]},
]
return []
}
})

View File

@ -172,8 +172,9 @@ list: [ "ALL", "CLEAR",
| showFolderIcon | 是否显示节点前的三角图标 | boolean | true / false | true |
| showLine | 是否显示虚线 | boolean | true / false | true |
| indent | 间距 | int | - | 20 |
| expandedKeys | 默认展开的节点数组, 为true时展开所有节点 | array / boolean | - | [ ] |
| strict | 是否遵循严格父子结构 | boolean | true / false | true |
| expandedKeys | 默认展开的节点数组, 为true时展开所有节点 | array / boolean | - | [ ] |
| strict | 是否遵循严格父子结构 | boolean | true / false | true |
| simple | 是否开启极简模式 | boolean | true / false | false |
### cascader

View File

@ -1,6 +1,6 @@
{
"name": "xm-select",
"version": "1.1.8",
"version": "1.1.9",
"description": "始于Layui的select多选解决方案",
"main": "index.js",
"scripts": {

View File

@ -163,4 +163,31 @@ export function exchangeOptionsData(arr, { prop }){
}
}
return newArr;
}
export function toSimple(data, sels, list, prop){
if(!data || !isArray(data)){
return;
}
let { children, selected, value } = prop;
data.forEach(item => {
if(item.__node[selected] || sels.find(i => i[value] === item[value])){
list.push(item);
}else{
toSimple(item[children], sels, list, prop);
}
})
}
export function delProp(data, children, props){
if(!data || !isArray(data)){
return;
}
return data.map(item => {
item = { ...item };
props.forEach(prop => delete item[prop]);
item[children] = delProp(item[children], children, props);
return item;
})
}

View File

@ -283,7 +283,6 @@ class Framework extends Component{
if(type === 'data'){
let changeData = data.filter(item => item[this.props.prop.selected] === true);
this.resetSelectValue(mergeArr(changeData, this.state.sels, this.props.prop), changeData, true);
let dataObj = {}, flatData = [];
this.load(data, dataObj, flatData);
this.setState({ data, flatData });

View File

@ -1,5 +1,5 @@
import { h, Component, render } from 'preact'
import { isFunction } from '@/common/util'
import { isFunction, toSimple } from '@/common/util'
/**
* 标签的渲染
@ -30,7 +30,7 @@ class Label extends Component{
left > max && (left = max);
this.labelRef.scrollLeft = left;
}
}
}
componentDidMount(){
if (this.labelRef.addEventListener) {
@ -43,25 +43,32 @@ class Label extends Component{
}
render(config) {
const { data, prop, theme, model, sels, autoRow } = config;
const { data, prop, theme, model, sels, autoRow, tree } = config;
const { name, disabled } = prop;
//获取配置项
const label = model.label;
const type = label.type;
const conf = label[type];
const conf = label[type];
let list = sels;
//树结构开启极简显示
if(tree.show && tree.strict && tree.simple){
list = []
toSimple(data, sels, list, prop);
}
//渲染结果
let html = '', innerHTML = true;
//悬浮显示已选择
let title = sels.map(item => item[name]).join(',')
let title = list.map(item => item[name]).join(',')
if(type === 'text'){
html = sels.map(sel => `${conf.left}${sel[name]}${conf.right}`).join(conf.separator)
html = list.map(sel => `${conf.left}${sel[name]}${conf.right}`).join(conf.separator)
}else if(type === 'block'){
innerHTML = false;
//已选择的数据
let arr = [...sels];
let arr = [...list];
const style = { backgroundColor: theme.color }
//显示的个数
@ -91,10 +98,10 @@ class Label extends Component{
)
}
}else{
if(sels.length && conf && conf.template){
html = conf.template(data, sels);
if(list.length && conf && conf.template){
html = conf.template(data, list);
}else{
html = sels.map(sel => sel[name]).join(',')
html = list.map(sel => sel[name]).join(',')
}
}

View File

@ -125,13 +125,15 @@ class General extends Component{
this.setState({ loading: true, remote: false });
//让输入框失去焦点
this.blur();
this.props.remoteMethod(this.state.filterValue, (result, totalSize) => {
//回调后可以重新聚焦
this.focus();
this.callback = true;
this.setState({ loading: false, totalSize });
this.props.onReset(result, 'data');
this.props.remoteMethod(this.state.filterValue, (result, totalSize = 1) => {
//这里同步修改为异步
setTimeout(() => {
//回调后可以重新聚焦
this.focus();
this.callback = true;
this.setState({ loading: false, totalSize });
this.props.onReset(result, 'data');
}, 10);
}, this.props.show, pageIndex);
}
}
@ -215,46 +217,42 @@ class General extends Component{
}
render(config) {
let { data, flatData, prop, template, theme, radio, sels, empty, filterable, filterMethod, remoteSearch, remoteMethod, delay, searchTips, create, pageRemote } = config
let { data, flatData, prop, template, theme, radio, sels, empty, filterable, filterMethod, remoteSearch, remoteMethod, delay, searchTips, create, pageRemote, max } = config
const { name, value, disabled, children, optgroup } = prop;
let arr = deepMerge([], flatData), creator;
//是否开启了搜索
if(filterable){
if(remoteSearch){//是否进行远程搜索
this.postData();
}else{
const filterData = (item, index) => {
const isGroup = item[optgroup];
if(isGroup){
delete item.__del;
return true;
}
return filterMethod(this.state.filterValue, item, index, prop);
}
arr = arr.filter(filterData);
for(let i = 0; i < arr.length - 1; i++){
let a = arr[i];
let b = arr[i + 1];
if(a[optgroup] && b[optgroup]){
arr[i].__del = true;
}
}
if(arr.length && arr[arr.length - 1][optgroup]){
arr[arr.length - 1].__del = true;
}
arr = arr.filter(item => !item.__del);
//创建条目
creator = this.state.filterValue && isFunction(create);
}
//远程分页 或者 远程搜索
if(pageRemote || filterable && remoteSearch){
this.postData();
}
//远程分页
if(pageRemote){
this.postData();
//本地搜索
if(filterable && !remoteSearch){
const filterData = (item, index) => {
const isGroup = item[optgroup];
if(isGroup){
delete item.__del;
return true;
}
return filterMethod(this.state.filterValue, item, index, prop);
}
arr = arr.filter(filterData);
for(let i = 0; i < arr.length - 1; i++){
let a = arr[i];
let b = arr[i + 1];
if(a[optgroup] && b[optgroup]){
arr[i].__del = true;
}
}
if(arr.length && arr[arr.length - 1][optgroup]){
arr[arr.length - 1].__del = true;
}
arr = arr.filter(item => !item.__del);
//创建条目
creator = this.state.filterValue && isFunction(create);
}
const search = (
@ -354,8 +352,20 @@ class General extends Component{
if(tool === 'ALL'){
info = { icon: 'xm-iconfont xm-icon-quanxuan', name, method: (pageData) => {
const { optgroup, disabled } = prop;
const list = pageData.filter(item => !item[optgroup]).filter(item => !item[disabled])
this.props.onReset(radio ? list.slice(0, 1) : mergeArr(list, sels, prop), 'sels');
const list = pageData.filter(item => !item[optgroup]).filter(item => !item[disabled])
const disSels = sels.filter(item => item[prop.disabled]);
let result = [];
//单选的处理
if(radio){
result = disSels.length ? disSels : list.slice(0, 1)
}else if(max > 0){
result = disSels.length >= max ? disSels : mergeArr(list.slice(0, max - disSels.length), disSels, prop)
}else{
result = mergeArr(list, sels, prop)
}
this.props.onReset(result, 'sels');
} };
}else if(tool === 'CLEAR'){
info = { icon: 'xm-iconfont xm-icon-qingkong', name, method: (pageData) => {
@ -374,8 +384,20 @@ class General extends Component{
}else{
list.splice(index, 1);
}
})
this.props.onReset(radio ? selectedList.slice(0, 1) : mergeArr(list, selectedList, prop), 'sels');
})
const disSels = selectedList.filter(item => item[prop.disabled]);
let result = [];
//单选的处理
if(radio){
result = disSels.length ? disSels : list.slice(0, 1)
}else if(max > 0){
result = disSels.length >= max ? disSels : mergeArr(list.slice(0, max - disSels.length), disSels, prop)
}else{
result = mergeArr(list, selectedList, prop)
}
this.props.onReset(result, 'sels');
} };
}else {
info = tool

View File

@ -1,6 +1,6 @@
import { h, Component, render } from 'preact'
import { datas, optionData, childData } from '@/index.js';
import { warn, listenerClose, isArray, deepMerge, exchangeOptionsData } from '@/common/util'
import { warn, listenerClose, isArray, deepMerge, exchangeOptionsData, toSimple, delProp } from '@/common/util'
import Framework from '@/components/framework'
import defaultOptions from '@/config/options'
@ -83,12 +83,18 @@ class xmOptions {
/**
* 获取多选选中的数据
*/
getValue(type){
let arr = childData[this.options.el].state.sels.map(item => {
item = { ...item };
delete item.__node;
return item;
});
getValue(type){
const { tree, prop, data } = this.options;
let sels = childData[this.options.el].state.sels;
let list = sels;
//树结构开启极简显示
if(tree.show && tree.strict && tree.simple){
list = []
toSimple(data, sels, list, prop);
}
let arr = delProp(list, prop.children, [ '__node' ]);;
if(type === 'name'){
return arr.map(item => item[this.options.prop.name]);

View File

@ -100,7 +100,9 @@ export default function (lan = 'zn') {
//是否懒加载
lazy: false,
//懒加载回调
load: null,
load: null,
//是否开启极简模式
simple: false,
},
//级联结构
cascader: {