Compare commits

...

10 Commits

Author SHA1 Message Date
e7e9ee2a65 修改定位方式为固定定位,修正定位位置 2023-08-18 16:54:10 +08:00
maplemei
05dc278d28
update README.md.
Signed-off-by: maplemei <hnzzmsf@126.com>
2023-04-08 08:25:17 +00:00
maplemei
170d8ab0d1 bug fixed 2021-07-22 13:16:36 +08:00
maplemei
8774b1f79c 修正版本号 2021-06-30 14:00:28 +08:00
maplemei
479b26fa7f v1.2.3 2021-06-30 13:56:07 +08:00
ruanlinxin
eb4e6fa66e <rlx>
1.添加节流方法
2.滚动监听添加节流
2021-05-31 22:22:34 +08:00
ruanlinxin
12b7f0ce0e <rlx>
1. 优化arr2tree
2021-05-31 22:04:11 +08:00
maplemei
f8fa44c94c u 2021-05-28 18:30:08 +08:00
maplemei
e928c6a038 新增fixed布局 2021-01-19 16:28:25 +08:00
maplemei
b47c8cfcb9 修复渲染失败页面监听错误的问题 2020-12-04 16:39:55 +08:00
27 changed files with 151308 additions and 370 deletions

View File

@ -1,5 +1,59 @@
## 更新日志 ## 更新日志
### 1.2.4
*2021-07-22*
#### 新增
- 新增渲染完成的回调`done`
- `create`支持一次性创建多个, 返回一个数组即可 [#I40MU0](https://gitee.com/maplemei/xm-select/issues/I40MU0)
- 增加预选配置`enableHoverFirst`, 默认选中第一项可选中数据 [#I3ZCRX](https://gitee.com/maplemei/xm-select/issues/I3ZCRX)
- 新增focus后的样式提醒
- 新增自定义设置选中键盘KeyCode配置`selectedKeyCode`, 可选 `xmSelect.KeyCode.Enter`, `xmSelect.KeyCode.Space`, 也可自行定义数值 [#I41NNI](https://gitee.com/maplemei/xm-select/issues/I41NNI)
- 表单验证失败后 滚动到可视范围内 ##灰度##
#### Bug fixes
- 修复`tree`非严格模式下, 无法选中父节点
- 修复`tree`模式下搜索后无法折叠的问题 [#I3XBF1](https://gitee.com/maplemei/xm-select/issues/I3XBF1)
### 1.2.3
*2021-06-30*
#### 新增
- 新增`submitConversion`配置方法, 用于拓展表单提交数据, 默认是value数组
#### Bug fixes
- 修复级联模式下第一组数据过多时不显示滚动条
- 修复级联模式下隐藏图标背景色透明的bug
- 修复级联模式下如果子节点是空数组也显示右箭头的bug
- 修复级联/树模式下,如果子节点是空数组,然后操作选中状态异常
- 修复工具条点击清空, `on`监听到的`isAdd``true`的bug [#I3T2KE](https://gitee.com/maplemei/xm-select/issues/I3T2KE)
- 修复setValue时对多选上限的判断异常 [#I3SABO](https://gitee.com/maplemei/xm-select/issues/I3SABO)
### 1.2.2
*2021-01-19*
#### 新增
- 新增配置 `model.type: fixed`, 切换为`fixed`布局模式 [体验传送门](https://maplemei.gitee.io/xm-select/#/senior/table)
- 新增实例方法`calcPosition`, fixed布局模式下重新计算位置
#### Bug fixes
- 修改直接设置父节点无法选中的问题
- 修改非严格模式下设置父节点, 子节点受影响
- 修复渲染失败页面监听错误的问题
- 修改数据重复时分组错乱的问题
### 1.2.1 ### 1.2.1
*2020-11-27* *2020-11-27*

View File

@ -26,11 +26,14 @@
> 联系方式 > 联系方式
![输入图片说明](add.png)
- xm-select技术群①: `660408068` (500人) - xm-select技术群①: `660408068` (500人)
- xm-select技术群②: `938624691` (500人) - xm-select技术群②: `938624691` (500人)
- xm-select技术群③: `1145047250` (500人) - xm-select技术群③: `1145047250` (500人)
[issues 需求记录](https://gitee.com/maplemei/xm-select/issues/I1NSO7) [issues 需求记录](https://gitee.com/maplemei/xm-select/issues)
[更新日志](CHANGELOG.md) [更新日志](CHANGELOG.md)

BIN
add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

View File

@ -94,9 +94,12 @@ const webpackConfig = {
new webpack.BannerPlugin(banner), new webpack.BannerPlugin(banner),
new VueLoaderPlugin(), new VueLoaderPlugin(),
], ],
optimization: {
minimize: false,//可以自行配置是否压缩
},
devServer: { devServer: {
host: '0.0.0.0', host: '0.0.0.0',
port: 9000, port: 9001,
publicPath: '/', publicPath: '/',
hot: true hot: true
}, },

13471
dist/static/2.js vendored

File diff suppressed because one or more lines are too long

1128
dist/static/3.js vendored

File diff suppressed because one or more lines are too long

120377
dist/static/docs.js vendored

File diff suppressed because one or more lines are too long

8
dist/xm-select.js vendored

File diff suppressed because one or more lines are too long

View File

@ -38,6 +38,8 @@
this.fixedControl = bottom > document.documentElement.clientHeight && this.fixedControl = bottom > document.documentElement.clientHeight &&
top + 44 <= document.documentElement.clientHeight; top + 44 <= document.documentElement.clientHeight;
this.$refs.control.style.left = this.fixedControl ? `${ left }px` : '0'; this.$refs.control.style.left = this.fixedControl ? `${ left }px` : '0';
xmSelect.get().forEach(xs => xs.calcPosition());
}, },
removeScrollHandler() { removeScrollHandler() {
this.scrollParent && this.scrollParent.removeEventListener('scroll', this.scrollHandler); this.scrollParent && this.scrollParent.removeEventListener('scroll', this.scrollHandler);

View File

@ -4,10 +4,7 @@
<div class="container"> <div class="container">
<h1> <h1>
<router-link :to="`/`"> <router-link :to="`/`">
<!-- logo -->
<slot> <slot>
<!-- <img src="../assets/images/element-logo.svg" alt="element-logo" class="nav-logo"> -->
<!-- <img src="../assets/images/element-logo-small.svg" alt="element-logo" class="nav-logo-small"> -->
xm-select xm-select
</slot> </slot>
</router-link> </router-link>
@ -19,7 +16,7 @@
<router-link active-class="active" :to="`/`">使用手册</router-link> <router-link active-class="active" :to="`/`">使用手册</router-link>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a href='https://gitee.com/maplemei/xm-select/issues/I1NSO7' target="_blank" style="opacity: 1;">提新需求</a> <a href='https://gitee.com/maplemei/xm-select/issues' target="_blank" style="opacity: 1;">提新需求</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">

View File

@ -48,7 +48,7 @@ layui.use('table', function() {
//修改一些css样式, 这里虽然能够使用, 但是还是不太友好, 努力中... //修改一些css样式, 这里虽然能够使用, 但是还是不太友好, 努力中...
var cells = document.querySelectorAll('div[lay-id="demo"] .layui-table-cell'); var cells = document.querySelectorAll('div[lay-id="demo"] .layui-table-cell');
for(var i = 0 ; i < cells.length ; i++ ){ for(var i = 0 ; i < cells.length ; i++ ){
cells[i].style.overflow = 'unset'; //cells[i].style.overflow = 'unset';
cells[i].style.height = 'auto'; cells[i].style.height = 'auto';
} }
//渲染多选 //渲染多选
@ -56,6 +56,7 @@ layui.use('table', function() {
var xm = xmSelect.render({ var xm = xmSelect.render({
el: '#XM-' + item.id, el: '#XM-' + item.id,
autoRow: true, autoRow: true,
model: { type: 'fixed' },
data: [ data: [
{name: '张三', value: 1}, {name: '张三', value: 1},
{name: '李四', value: 2}, {name: '李四', value: 2},
@ -70,6 +71,13 @@ layui.use('table', function() {
}); });
//表格滚动时 重新计算位置
document.querySelector('.layui-table-body').addEventListener('scroll', () => {
xmSelect.get().forEach(function(item){
item.calcPosition();
})
})
</script> </script>
``` ```

View File

@ -5,46 +5,55 @@
<div id="demo1" class="xm-select-demo"></div> <div id="demo1" class="xm-select-demo"></div>
<script> <script>
var demo1 = xmSelect.render({ xmSelect.render({
el: '#demo1', el: '#demo1',
autoRow: true, autoRow: true,
filterable: true,
tree: { tree: {
show: true, show: true,
showFolderIcon: true,
showLine: true,
indent: 20,
expandedKeys: [ -3 ],
simple: true,
clickExpand: false,
clickCheck: false,
strict: false
}, },
toolbar: { height: '200px',
show: true, maxMethod(a, item){
list: ['ALL', 'REVERSE', 'CLEAR'] console.log(item)
},
submitConversion(sels, prop){
return sels.map(item => item[prop.name]).join(',')
}, },
filterable: true, filterable: true,
height: 'auto',
data(){ data(){
return [ return [
{name: '销售员', value: -1, disabled: true, children: [ {name: '销售员', value: -1, disabled: false, children: [
{name: '张三1', value: 1, selected: true, children: []}, {name: '张三1', value: 1, selected: true, children: []},
{name: '李四1', value: 2, selected: true}, {name: '王五1', value: 13, disabled: true},
{name: '王五1', value: 3, disabled: true}, {name: '王五1', value: 131, disabled: true},
{name: '王五1', value: 132, disabled: true},
{name: '王五1', value: 133, disabled: true},
{name: '王五1', value: 134, disabled: true},
{name: '王五1', value: 135, disabled: true},
{name: '王五1', value: 136, disabled: true},
{name: '王五1', value: 137, disabled: true},
{name: '王五1', value: 138, disabled: true},
]}, ]},
{name: '奖品', value: -2, disabled: true, children: [ {name: '奖品', value: -2, children: [
{name: '奖品3', value: -3, children: [ {name: '奖品3', 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: 4, disabled: true},
{name: '香蕉2', value: 5}, {name: '香蕉2', value: 5},
{name: '葡萄2', value: 6}, {name: '葡萄2', value: 6},
]}, ]},
{name: '李四1', value: 2},
{name: '王五1', value: 3, disabled: true},
{name: '王五1', value: 31, disabled: true},
{name: '王五1', value: 32, disabled: true},
{name: '王五1', value: 33, disabled: true},
{name: '王五1', value: 34, disabled: true},
{name: '王五1', value: 35, disabled: true},
{name: '王五1', value: 36, disabled: true},
{name: '王五1', value: 37, disabled: true},
{name: '王五1', value: 38, disabled: true},
] ]
}, }
}) })
</script> </script>

View File

@ -46,12 +46,16 @@
| toolbar | 工具条, 具体看下表 | object | - | - | | toolbar | 工具条, 具体看下表 | object | - | - |
| showCount | 展示在下拉框中的最多选项数量 | int | - | 0 | | showCount | 展示在下拉框中的最多选项数量 | int | - | 0 |
| enableKeyboard | 是否启用键盘操作选项 | boolean | true / false | true | | enableKeyboard | 是否启用键盘操作选项 | boolean | true / false | true |
| enableHoverFirst | 是否默认选中第一项 | boolean | true / false | true |
| selectedKeyCode | 选中的键盘KeyCode | int | 全部KeyCode, 也可xmSelect.KeyCode.Enter,xmSelect.KeyCode.Space | 13 |
| 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 |
| create | 创建条目 | function(val, data), val: 搜索的数据, data: 当前下拉数据 | - | null | | create | 创建条目 | function(val, data), val: 搜索的数据, data: 当前下拉数据 | - | null |
| tree | 树形结构, 具体看下表 | object | - | - | | tree | 树形结构, 具体看下表 | object | - | - |
| cascader | 级联结构, 具体看下表 | object | - | - | | cascader | 级联结构, 具体看下表 | object | - | - |
| submitConversion | 配置表单提交数据 | function(sels, prop), sels: 已选中数据, prop: 自定义的prop | - | - |
| done | 渲染完成回调 | function | - | - |
### prop ### prop
@ -134,7 +138,7 @@ model: {
} }
}, },
}, },
//展示类型, 下拉框形式: absolute, 直接显示模式: relative //展示类型, 下拉框形式: absolute, 直接显示模式: relative, 浮动布局: fixed
type: 'absolute', type: 'absolute',
}, },
``` ```
@ -211,7 +215,7 @@ list: [ "ALL", "CLEAR",
| render | 渲染多选 | (options: 配置项) | 实例对象 | | render | 渲染多选 | (options: 配置项) | 实例对象 |
| get | 获取页面中已经渲染的多选 | (filter: 过滤`el`, single: 是否返回单实例) | 符合条件的实例数组 | | get | 获取页面中已经渲染的多选 | (filter: 过滤`el`, single: 是否返回单实例) | 符合条件的实例数组 |
| batch | 批量操作已渲染的多选 | (filter: 过滤`el`, method: 方法, ...方法参数) | 符合条件的实例数组 | | batch | 批量操作已渲染的多选 | (filter: 过滤`el`, method: 方法, ...方法参数) | 符合条件的实例数组 |
| arrr2tree | 把列表数据转化为树状结构 | (arr: 数据, pid: 父节点ID的key, id: 对应key, children: 对应key, topParentId: 顶级节点的ID) | 符合条件的数组 | | arr2tree | 把列表数据转化为树状结构 | (arr: 数据, pid: 父节点ID的key, id: 对应key, children: 对应key, topParentId: 顶级节点的ID) | 符合条件的数组 |
``` ```
//render 使用方式 //render 使用方式
@ -258,3 +262,4 @@ xmSelect.render()后会返回一个xmSelect对象, 可以进行方法调用
| changeExpandedKeys | 树模式下更新节点展开状态, v1.2.0 新增 | (keys: true-全部展开, false-全部关闭, 数组-展开的节点值) | | changeExpandedKeys | 树模式下更新节点展开状态, v1.2.0 新增 | (keys: true-全部展开, false-全部关闭, 数组-展开的节点值) |
| enable | 启用选项, disabled=false, v1.2.0 新增 | (array: 想要启用的选项数组) | | enable | 启用选项, disabled=false, v1.2.0 新增 | (array: 想要启用的选项数组) |
| disable | 禁用用选项, disabled=true, v1.2.0 新增 | (array: 想要禁用的选项数组) | | disable | 禁用用选项, disabled=true, v1.2.0 新增 | (array: 想要禁用的选项数组) |
| calcPosition | fixed布局模式下重新计算位置, v1.2.2 新增 | - |

9070
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,45 +1,46 @@
{ {
"name": "xm-select", "name": "xm-select",
"version": "1.2.1", "version": "1.2.4",
"description": "始于Layui的select多选解决方案", "description": "始于Layui的select多选解决方案",
"website": "https://maplemei.gitee.io/xm-select",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"dev": "cross-env NODE_ENV=dev node_modules/.bin/webpack-dev-server --config build/webpack.config.js", "dev": "cross-env NODE_ENV=dev node_modules/.bin/webpack-dev-server --config build/webpack.config.js",
"build": "cross-env NODE_ENV=prod webpack --config build/webpack.config.js" "build": "cross-env NODE_ENV=prod webpack --config build/webpack.config.js"
}, },
"author": "", "author": "maplemei",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"babel-polyfill": "^6.26.0",
"clean-webpack-plugin": "^3.0.0",
"element-ui": "^2.12.0",
"highlight.js": "^9.15.10",
"preact": "^10.4.6",
"vue": "^2.6.14",
"vue-router": "^3.1.3"
},
"devDependencies": {
"@babel/core": "^7.4.0", "@babel/core": "^7.4.0",
"@babel/preset-env": "^7.4.2", "@babel/preset-env": "^7.4.2",
"babel-loader": "^8.0.5", "babel-loader": "^8.0.5",
"babel-plugin-transform-react-jsx": "^6.24.1", "babel-plugin-transform-react-jsx": "^6.24.1",
"babel-polyfill": "^6.26.0",
"clean-webpack-plugin": "^3.0.0",
"cross-env": "^6.0.0", "cross-env": "^6.0.0",
"css-loader": "^3.0.0", "css-loader": "^3.0.0",
"element-ui": "^2.12.0",
"file-loader": "^4.2.0", "file-loader": "^4.2.0",
"highlight.js": "^9.15.10", "html-webpack-plugin": "^3.2.0",
"less": "^3.9.0", "less": "^3.9.0",
"less-loader": "^4.1.0", "less-loader": "^4.1.0",
"markdown-it": "^10.0.0", "markdown-it": "^10.0.0",
"markdown-it-anchor": "^5.2.4", "markdown-it-anchor": "^5.2.4",
"markdown-it-chain": "^1.3.0", "markdown-it-chain": "^1.3.0",
"markdown-it-container": "^2.0.0", "markdown-it-container": "^2.0.0",
"preact": "^10.4.6",
"style-loader": "^0.23.1", "style-loader": "^0.23.1",
"transliteration": "^2.1.7", "transliteration": "^2.1.7",
"url-loader": "^2.1.0", "url-loader": "^2.1.0",
"vue": "^2.6.10",
"vue-loader": "^15.7.1", "vue-loader": "^15.7.1",
"vue-router": "^3.1.3", "vue-template-compiler": "^2.6.11",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.29.6", "webpack": "^4.29.6",
"webpack-cli": "^3.3.0", "webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1" "webpack-dev-server": "^3.2.1"
},
"devDependencies": {
"html-webpack-plugin": "^3.2.0"
} }
} }

6638
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -191,3 +191,21 @@ export function delProp(data, children, props){
return item; return item;
}) })
} }
export function throttle(cb, time = 100 ,wait = true) {
// cb => 回调函数
// time => 定时
// wait => 是否等待 false 立即生效 true 时间到了再执行
const self = this // 保存this指向
let disable = false // 节流标志
return function (...data) {
if(disable)return // 如果是禁止状态那么直接跳出
disable = true // 如果不是禁止状态那么立即设置为禁止
!wait && cb.call(self,...data) // 如果不等待那么立即执行
setTimeout(()=>{
wait && cb.call(self,...data) // 如果要等待那么到时间后再执行
disable = false // 关闭禁止状态
},time)
}
}

View File

@ -31,11 +31,12 @@ class Framework extends Component{
show: false, show: false,
tmpColor: '', tmpColor: '',
bodyClass: '', bodyClass: '',
time: 0,
} }
} }
init(props, refresh){ init(props, refresh){
let { data, prop, initValue, radio } = props, sels; let { data, prop, initValue, radio, tree, cascader } = props, sels;
//如果新数据和旧数据不同 或者 强制刷新 才进行数据处理 //如果新数据和旧数据不同 或者 强制刷新 才进行数据处理
if(refresh){ if(refresh){
let dataObj = {}; let dataObj = {};
@ -47,6 +48,9 @@ class Framework extends Component{
}), dataObj) }), dataObj)
if(radio && sels.length > 1){ if(radio && sels.length > 1){
sels = sels.slice(0, 1) sels = sels.slice(0, 1)
if(tree.show && tree.strict || cascader.show && cascader.strict){
this.clearAndReset(data, sels, false);
}
} }
this.setState({ sels, dataObj, flatData }); this.setState({ sels, dataObj, flatData });
} }
@ -116,7 +120,7 @@ class Framework extends Component{
return cgList; return cgList;
} }
value(sels, show, listenOn, jsChangeData){ value(sels, show, listenOn, jsChangeData, isAdd = true){
if(show !== false && show !== true){ if(show !== false && show !== true){
show = this.state.show; show = this.state.show;
} }
@ -125,7 +129,7 @@ class Framework extends Component{
let changeData = this.exchangeValue(sels); let changeData = this.exchangeValue(sels);
//检测是否超选了 //检测是否超选了
if(this.checkMax(changeData, changeData)){ if(this.checkMax(changeData, changeData, true)){
return ; return ;
} }
@ -134,19 +138,28 @@ class Framework extends Component{
this.clearAndReset(data, changeData, false); this.clearAndReset(data, changeData, false);
changeData = this.init({ data, prop }, true); changeData = this.init({ data, prop }, true);
} }
this.resetSelectValue(changeData, jsChangeData ? jsChangeData : changeData, true, listenOn); this.resetSelectValue(changeData, jsChangeData ? jsChangeData : changeData, isAdd, listenOn);
this.setState({ show }) this.setState({ show })
} }
clearAndReset(data, changeData, parentCK){ clearAndReset(data, changeData, parentCK){
const { selected, children, value } = this.props.prop; const { selected, disabled, children, value } = this.props.prop;
data.forEach(item => { data.forEach(item => {
item[selected] = changeData.findIndex(c => c[value] === item[value]) != -1 || parentCK; item[selected] = changeData.findIndex(c => c[value] === item[value]) != -1 || parentCK;
let child = item[children]; let child = item[children];
child && isArray(child) && this.clearAndReset(child, changeData, item[selected]) if(child && isArray(child) && child.length > 0){
this.clearAndReset(child, changeData, item[selected])
let len = child.length;
let slen = child.filter(i => i[selected] === true || i.__node.selected === true).length;
item.__node.selected = slen === len;
item.__node.half = slen > 0 && slen < len || child.filter(i => i.__node.half === true).length > 0;
item.__node.disabled = child.filter(i => i[disabled] === true || i.__node.disabled === true).length === len;
}
}) })
} }
load(data, dataObj, flatData, parent, level = 0, initValue){ load(data, dataObj, flatData, parent, level = 0, initValue){
const { prop, tree, cascader } = this.props; const { prop, tree, cascader } = this.props;
const { children, optgroup, value, selected, disabled } = prop; const { children, optgroup, value, selected, disabled } = prop;
@ -237,11 +250,12 @@ class Framework extends Component{
} }
} }
checkMax(item, sels){ checkMax(item, sels, contains){
const { max, maxMethod, theme } = this.props const { max, maxMethod, theme } = this.props
//查看是否设置了多选上限 //查看是否设置了多选上限
let maxCount = toNum(max); let maxCount = toNum(max);
if(maxCount > 0 && sels.length >= maxCount){ let flag = (contains ? sels.length : (isArray(item) ? item.length : 1) + sels.length) > maxCount;
if(maxCount > 0 && flag){
this.updateBorderColor(theme.maxColor); this.updateBorderColor(theme.maxColor);
//查看是否需要回调 //查看是否需要回调
maxMethod && isFunction(maxMethod) && maxMethod(sels, item); maxMethod && isFunction(maxMethod) && maxMethod(sels, item);
@ -252,14 +266,14 @@ class Framework extends Component{
//选项, 选中状态, 禁用状态, 是否强制删除:在label上点击删除 //选项, 选中状态, 禁用状态, 是否强制删除:在label上点击删除
itemClick(item, itemSelected, itemDisabled, mandatoryDelete){ itemClick(item, itemSelected, itemDisabled, mandatoryDelete){
const { theme, prop, radio, repeat, clickClose, max, maxMethod, tree } = this.props const { theme, prop, radio, repeat, clickClose, max, maxMethod, tree, cascader, data } = this.props
let sels = [ ...this.state.sels ] let sels = [ ...this.state.sels ]
const { value, selected, disabled, children, optgroup } = prop const { value, selected, disabled, children, optgroup } = prop
//如果是禁用状态, 不能进行操作 //如果是禁用状态, 不能进行操作
if(itemDisabled) return; if(itemDisabled) return;
if(item[optgroup] && tree.strict){ if(item[optgroup] && (tree.show && tree.strict || cascader.show && cascader.strict)){
let child = item[children], change = [], isAdd = true, handlerType; let child = item[children], change = [], isAdd = true, handlerType;
if(item.__node.selected){ if(item.__node.selected){
handlerType = 'del'; handlerType = 'del';
@ -280,7 +294,7 @@ class Framework extends Component{
this.treeHandler(sels, item, change, handlerType); this.treeHandler(sels, item, change, handlerType);
} }
if(this.checkMax(change, change)){ if(this.checkMax(change, sels)){//TODO 这里还是有问题, 如果是取消的
return ; return ;
} }
sels = [ ...this.state.sels ], change = []; sels = [ ...this.state.sels ], change = [];
@ -308,6 +322,7 @@ class Framework extends Component{
}else{ }else{
sels = [...sels, item] sels = [...sels, item]
} }
this.clearAndReset(data, sels, itemSelected)
this.resetSelectValue(sels, [item], !itemSelected); this.resetSelectValue(sels, [item], !itemSelected);
} }
} }
@ -387,7 +402,7 @@ class Framework extends Component{
}else }else
//树状结构数据更新 //树状结构数据更新
if(type === 'treeData'){ if(type === 'treeData'){
this.value(data, null, true) this.value(data, null, true, false, false)
}else }else
//树状结构数据更新 //树状结构数据更新
if(type === 'close'){ if(type === 'close'){
@ -399,7 +414,7 @@ class Framework extends Component{
}else }else
//聚焦label搜索框 //聚焦label搜索框
if(type === 'labelSearchBlur'){ if(type === 'labelSearchBlur'){
this.labelRef.blur(data); this.labelRef && this.labelRef.blur(data);
}else }else
//聚焦label搜索框 //聚焦label搜索框
if(type === 'labelSearch'){ if(type === 'labelSearch'){
@ -422,7 +437,7 @@ class Framework extends Component{
sels.splice(index, 1); sels.splice(index, 1);
} }
}); });
this.value(sels, this.props.show, true, changeData) this.value(sels, this.props.show, true, changeData, false)
} }
auto(arr){ auto(arr){
@ -439,6 +454,21 @@ class Framework extends Component{
} }
} }
calcPosition(){
if(!this.base || !this.state.show){
return {}
}
let rect = this.base.getBoundingClientRect();
(Date.now() - this.state.time > 10) && this.setState({ time: Date.now() })
return {
position: 'fixed',
left: rect.x,
top: rect.y + rect.height + 4,
width: rect.width,
}
return {};
}
//组件将要接收新属性 //组件将要接收新属性
componentWillReceiveProps(props){ componentWillReceiveProps(props){
this.init(props, props.updateData); this.init(props, props.updateData);
@ -450,7 +480,7 @@ class Framework extends Component{
} }
render(config, state) { render(config, state) {
const { theme, prop, radio, repeat, clickClose, on, max, maxMethod, content, disabled, tree } = config; const { theme, prop, radio, repeat, clickClose, on, max, maxMethod, content, disabled, tree, submitConversion } = config;
const borderStyle = { borderColor: theme.color }; const borderStyle = { borderColor: theme.color };
let { data, dataObj, flatData, sels, show, tmpColor, bodyClass } = state; let { data, dataObj, flatData, sels, show, tmpColor, bodyClass } = state;
@ -482,6 +512,7 @@ class Framework extends Component{
//渲染组件 //渲染组件
let Body = content ? <Custom { ...bodyProps } /> : tree.show ? <Tree { ...bodyProps } ref={ ref => this.treeRef = ref } /> : config.cascader.show ? <Cascader { ...bodyProps } /> : <General { ...bodyProps } ref={ ref => this.generalRef = ref } />; let Body = content ? <Custom { ...bodyProps } /> : tree.show ? <Tree { ...bodyProps } ref={ ref => this.treeRef = ref } /> : config.cascader.show ? <Cascader { ...bodyProps } /> : <General { ...bodyProps } ref={ ref => this.generalRef = ref } />;
let bodyStyle = this.calcPosition();
return ( return (
<xm-select { ...xmSelectProps } > <xm-select { ...xmSelectProps } >
@ -490,12 +521,12 @@ class Framework extends Component{
lay-verType={ config.layVerType } lay-verType={ config.layVerType }
lay-reqText={ config.layReqText } lay-reqText={ config.layReqText }
name={ config.name } name={ config.name }
value={ sels.map(item => item[prop.value]).join(',') } value={ submitConversion(sels, prop) }
></input> ></input>
<i class={ show ? 'xm-icon xm-icon-expand' : 'xm-icon' } /> <i class={ show ? 'xm-icon xm-icon-expand' : 'xm-icon' } />
{ sels.length === 0 && <div class="xm-tips">{ config.tips }</div> } { sels.length === 0 && <div class="xm-tips">{ config.tips }</div> }
<Label { ...labelProps } ref={ ref => this.labelRef = ref } /> <Label { ...labelProps } ref={ ref => this.labelRef = ref } />
<div class={ ['xm-body', bodyClass, config.model.type, show ? '':'dis', ].join(' ') } ref={ ref => this.bodyView = ref}> <div class={ ['xm-body', bodyClass, config.model.type, show ? '':'dis', ].join(' ') } style={ bodyStyle } ref={ ref => this.bodyView = ref}>
{ Body } { Body }
</div> </div>
{ disabled && <div class="xm-select-disabled"></div> } { disabled && <div class="xm-select-disabled"></div> }
@ -510,11 +541,16 @@ class Framework extends Component{
//监听键盘事件 //监听键盘事件
this.base.addEventListener('keydown', e => { this.base.addEventListener('keydown', e => {
let keyCode = e.keyCode; let keyCode = e.keyCode;
//ENTER
if(keyCode === 13){ if(keyCode === 13){
this.onClick() this.onClick(e)
} }
}); });
// focus 可以监听tab切换
// this.base.addEventListener('focus', e => {
// })
//表单验证 //表单验证
this.input = this.base.querySelector('.xm-select-default'); this.input = this.base.querySelector('.xm-select-default');
//监听class的变化, 然后进行边框变色处理, 或者更多的处理 //监听class的变化, 然后进行边框变色处理, 或者更多的处理
@ -528,7 +564,7 @@ class Framework extends Component{
this.input.className = 'xm-select-default'; this.input.className = 'xm-select-default';
this.base.style.borderColor = this.props.theme.maxColor; this.base.style.borderColor = this.props.theme.maxColor;
//这里可以自己新增一个回调, 也许看到源码的你能够看到 //这里可以自己新增一个回调, 也许看到源码的你能够看到
// this.base.scrollIntoView({ behavior: "smooth" }); this.base.scrollIntoView && this.base.scrollIntoView({ behavior: "smooth" });
} }
} }
} }
@ -548,6 +584,8 @@ class Framework extends Component{
dom = dom.parentElement; dom = dom.parentElement;
} }
let { done } = this.props;
done && done();
} }
//此时页面又被重新渲染了 //此时页面又被重新渲染了
@ -558,7 +596,12 @@ class Framework extends Component{
return ; return ;
} }
if(model.type === 'fixed'){
return ;
}
let rect = this.base.getBoundingClientRect(); let rect = this.base.getBoundingClientRect();
let bodyViewHeight;
if(direction === 'auto'){ if(direction === 'auto'){
//用于控制js获取下拉框的高度 //用于控制js获取下拉框的高度
this.bodyView.style.display = 'block'; this.bodyView.style.display = 'block';
@ -566,7 +609,7 @@ class Framework extends Component{
//获取下拉元素的高度 //获取下拉元素的高度
let bodyViewRect = this.bodyView.getBoundingClientRect(); let bodyViewRect = this.bodyView.getBoundingClientRect();
let bodyViewHeight = bodyViewRect.height; bodyViewHeight = bodyViewRect.height;
//还原控制效果 //还原控制效果
this.bodyView.style.display = ''; this.bodyView.style.display = '';
@ -578,13 +621,12 @@ class Framework extends Component{
let diff = clientHeight - y - rect.height - 20; let diff = clientHeight - y - rect.height - 20;
direction = diff > bodyViewHeight || y < diff ? 'down' : 'up'; direction = diff > bodyViewHeight || y < diff ? 'down' : 'up';
} }
if(direction == 'down'){ if(direction == 'down'){
this.bodyView.style.top = rect.height + 4 + 'px'; this.bodyView.style.top = (rect.height + 4 + rect.y )+ 'px';
this.bodyView.style.bottom = 'auto'; this.bodyView.style.bottom = 'auto';
}else{ }else{
this.bodyView.style.top = 'auto'; this.bodyView.style.top = (4 +rect.y - bodyViewHeight )+ 'px';
this.bodyView.style.bottom = rect.height + 4 + 'px'; this.bodyView.style.bottom = 'auto';
} }
} }

View File

@ -37,6 +37,65 @@ class Label extends Component{
input && input.blur(); input && input.blur();
} }
labelDrag(item, e){
let type = e.type;
let node = e.target;
while(true){
if(!node || node.tagName === 'I'){
return ;
}
if(node.tagName === 'DIV' && node.style.position !== 'fixed'){
break;
}
node = node.parentNode;
}
console.log(e)
if(type === 'mousedown'){
let dragNode = node.cloneNode(true);
let { pageX, pageY, offsetX, offsetY } = e;//鼠标当前位置
console.log(pageX, pageY, offsetX, offsetY)
dragNode.style.position = 'fixed';
dragNode.style.left = (pageX - offsetX) + 'px';
dragNode.style.top = (pageY - offsetY) + 'px';
node.appendChild(dragNode);
console.log(dragNode)
dragNode.onmousemove = (ev) => {
dragNode.style.left = (ev.pageX - offsetX) + 'px';
dragNode.style.top = (ev.pageY - offsetY) + 'px';
}
dragNode.mouseup = () => {
dragNode.parentNode.removeChild(dragNode);
dragNode.onmousemove = null;
dragNode.mouseup = null;
dragNode.mouseleave = null;
}
dragNode.mouseleave = () => {
console.log('mouseleave')
}
}else if(type === 'mouseup'){
let childs = node.childNodes;
for(let i = 0; i < childs.length; i++) {
let f = childs[i];
if(f.tagName === 'DIV'){
node.removeChild(f);
f.onmousemove = null;
break;
}
}
}
e.stopPropagation();
}
componentDidMount(){ componentDidMount(){
if (this.labelRef.addEventListener) { if (this.labelRef.addEventListener) {
this.labelRef.addEventListener('DOMMouseScroll', this.scrollFunc.bind(this), false); this.labelRef.addEventListener('DOMMouseScroll', this.scrollFunc.bind(this), false);
@ -82,8 +141,12 @@ class Label extends Component{
html = arr.splice(0, count).map(sel => { html = arr.splice(0, count).map(sel => {
const styleProps = { width: conf.showIcon ? 'calc(100% - 20px)' : '100%', } const styleProps = { width: conf.showIcon ? 'calc(100% - 20px)' : '100%', }
const className = ['xm-label-block', sel[disabled] ? 'disabled':''].join(' '); const className = ['xm-label-block', sel[disabled] ? 'disabled':''].join(' ');
// onMouseDown = { this.labelDrag.bind(this, sel) }
// onMouseUp = { this.labelDrag.bind(this, sel) }
return ( return (
<div class={className} style={ style }> <div class={className} style={ style }
>
{ conf.template && isFunction(conf.template) ? ( { conf.template && isFunction(conf.template) ? (
<span style={ styleProps } dangerouslySetInnerHTML={{ __html: conf.template(sel, arr) }}></span> <span style={ styleProps } dangerouslySetInnerHTML={{ __html: conf.template(sel, arr) }}></span>
) : ( ) : (
@ -104,7 +167,10 @@ class Label extends Component{
} }
}else if(type == 'search'){ }else if(type == 'search'){
innerHTML = false; innerHTML = false;
let one = list[0][name]; let one = '';
if(list.length){
one = list[0][name]
}
html = ( html = (
<input class="label-search-input" type="text" placeholder={ config.searchTips } style={{ width: '100%', border: 'none' }} value={ <input class="label-search-input" type="text" placeholder={ config.searchTips } style={{ width: '100%', border: 'none' }} value={

View File

@ -18,7 +18,7 @@ class Cascader extends Component{
optionClick(item, selected, disabled, type, index, e){ optionClick(item, selected, disabled, type, index, e){
if(type === 'line'){ if(type === 'line'){
if(disabled){ if(!item.optgroup && disabled){
return ; return ;
} }
//加载中的不需要进行处理 //加载中的不需要进行处理
@ -57,7 +57,7 @@ class Cascader extends Component{
render(config, state) { render(config, state) {
const { prop, empty, sels, theme, radio, template, data, cascader } = config; const { prop, empty, sels, theme, radio, template, data, cascader } = config;
let { name, value, disabled, children } = prop; let { name, value, disabled, children, optgroup } = prop;
const showIcon = config.model.icon != 'hidden'; const showIcon = config.model.icon != 'hidden';
const renderItem = (item, indent, index, checked) => { const renderItem = (item, indent, index, checked) => {
@ -108,6 +108,12 @@ class Cascader extends Component{
itemStyle.backgroundColor = theme.hover itemStyle.backgroundColor = theme.hover
} }
//隐藏图标的处理
if(!showIcon && selected){
itemStyle.backgroundColor = theme.color;
dis && (itemStyle.backgroundColor = '#C2C2C2');
}
const contentStyle = {}, checkedStyle = {}; const contentStyle = {}, checkedStyle = {};
if(checked){ if(checked){
contentStyle.color = theme.color contentStyle.color = theme.color
@ -133,7 +139,7 @@ class Cascader extends Component{
} onMouseEnter={ hoverChange } onMouseLeave={ hoverChange }> } onMouseEnter={ hoverChange } onMouseLeave={ hoverChange }>
{ showIcon && <i class={ iconClass } style={ iconStyle } onClick={ this.optionClick.bind(this, item, selected, dis, 'checkbox', index) }></i> } { showIcon && <i class={ iconClass } style={ iconStyle } onClick={ this.optionClick.bind(this, item, selected, dis, 'checkbox', index) }></i> }
<div class='xm-option-content' style={ contentStyle } dangerouslySetInnerHTML={{ __html: template({ data, item, arr: sels, name: item[name], value: item[value] }) }}></div> <div class='xm-option-content' style={ contentStyle } dangerouslySetInnerHTML={{ __html: template({ data, item, arr: sels, name: item[name], value: item[value] }) }}></div>
{ item[children] && <div class={ checkedClass } style={ checkedStyle }></div> } { item[optgroup] && <div class={ checkedClass } style={ checkedStyle }></div> }
</div> </div>
) )
} }
@ -146,7 +152,7 @@ class Cascader extends Component{
const checked = child && this.state.expand[index] === item[value]; const checked = child && this.state.expand[index] === item[value];
checked && boxArr.push( checked && boxArr.push(
<div class="xm-cascader-box" index={ index % 4 } style={{ left: indent + 'px', width: cascader.indent + 'px'}}> <div class="xm-cascader-box" index={ index % 4 } style={{ left: indent + 'px', width: cascader.indent + 'px'}}>
<div class="xm-cascader-scroll">{ child.map(c => renderGroup(c, indent, index + 1)) }</div> <div class="xm-cascader-scroll scroll-body">{ child.map(c => renderGroup(c, indent, index + 1)) }</div>
</div> </div>
) )
return renderItem(item, indent, index, checked) return renderItem(item, indent, index, checked)
@ -161,7 +167,7 @@ class Cascader extends Component{
} }
return ( return (
<div onClick={ this.blockClick } class="xm-body-cascader" style={{ width: cascader.indent + 'px', maxHeight: config.height }}> <div onClick={ this.blockClick } class="xm-body-cascader scroll-body" style={{ width: cascader.indent + 'px', maxHeight: config.height }}>
{ arr } { arr }
</div> </div>
) )

View File

@ -183,9 +183,7 @@ class General extends Component{
} }
let val = data[index][value]; let val = data[index][value];
this.setState({ val }) this.setState({ val })
//键盘选中时滚动到可视范围内 this.viewTo(val);
let opt = this.base.querySelector(`.xm-option[value="${ val }"]`);
opt && opt.scrollIntoView(false)
}else }else
//Down 键 //Down 键
if(keyCode === 40){ if(keyCode === 40){
@ -196,19 +194,24 @@ class General extends Component{
} }
let val = data[index][value]; let val = data[index][value];
this.setState({ val }) this.setState({ val })
//键盘选中时滚动到可视范围内 this.viewTo(val);
let opt = this.base.querySelector(`.xm-option[value="${ val }"]`);
opt && opt.scrollIntoView(false)
}else }else
//Enter 键 //Enter 键
if(keyCode === 13){ if(keyCode === this.props.selectedKeyCode){
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)
} }
} }
} }
}
viewTo(val){
//键盘选中时滚动到可视范围内
if(void 0 != this.base){
let opt = this.base.querySelector(`.xm-option[value="${ val }"]`);
opt && opt.scrollIntoView(false)
}
} }
//组件将要接收新属性 //组件将要接收新属性
@ -239,7 +242,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, enableKeyboard } = config let { data, flatData, prop, template, theme, radio, sels, empty, filterable, filterMethod, remoteSearch, remoteMethod, delay, searchTips, create, pageRemote, max, enableKeyboard, enableHoverFirst } = config
const { name, value, disabled, children, optgroup } = prop; const { name, value, disabled, children, optgroup } = prop;
@ -286,8 +289,9 @@ class General extends Component{
//如果是分组模式, 要分页先去除分组, 然后在计算分页, 最后再加上分组 //如果是分组模式, 要分页先去除分组, 然后在计算分页, 最后再加上分组
let groupInfo = {}; let groupInfo = {};
arr.filter(item => item[optgroup]).forEach(g => { arr.filter(item => item[optgroup]).forEach((g, groupIndex) => {
g[children].forEach(item => groupInfo[item[value]] = g); groupInfo[groupIndex] = g;
g[children].forEach(item => item.__group__index = groupIndex);
}); });
arr = arr.filter(item => !item[optgroup]); arr = arr.filter(item => !item[optgroup]);
@ -342,7 +346,8 @@ class General extends Component{
let newArr = [], group, tmpGroup = { __tmp: true }; let newArr = [], group, tmpGroup = { __tmp: true };
tmpGroup[optgroup] = true; tmpGroup[optgroup] = true;
arr.forEach(item => { arr.forEach(item => {
let g = groupInfo[item[value]]; let g = groupInfo[item.__group__index];
delete item.__group__index;
if(group && !g){ if(group && !g){
g = tmpGroup g = tmpGroup
} }
@ -357,7 +362,9 @@ class General extends Component{
//查看是否创建了条目 //查看是否创建了条目
if(creator){ if(creator){
creator = create(this.state.filterValue, deepMerge([], arr)); creator = create(this.state.filterValue, deepMerge([], arr));
creator && arr.splice(0, 0, {...creator, __node: {}}); if(void 0 != creator){
arr.splice(0, 0, ...(isArray(creator) ? creator : [creator]).map(i => ({ ...i, __node: {} })));
}
} }
let safetyArr = deepMerge([], arr); let safetyArr = deepMerge([], arr);
@ -519,7 +526,11 @@ class General extends Component{
arr = arr.map(renderGroup); arr = arr.map(renderGroup);
if(!arr.length){ if(arr.length){
if(enableHoverFirst && this.state.val == emptyVal){
this.keydown('div', { keyCode: 40 })
}
}else{
//查看无数据情况下是否显示分页 //查看无数据情况下是否显示分页
!config.pageEmptyShow && (paging = ''); !config.pageEmptyShow && (paging = '');
arr.push(<div class="xm-select-empty">{ empty }</div>) arr.push(<div class="xm-select-empty">{ empty }</div>)

View File

@ -20,6 +20,7 @@ class Tree extends Component{
this.inputOver = true; this.inputOver = true;
this.__value = ''; this.__value = '';
this.tempData = []; this.tempData = [];
this.__skipAutoExpand = '';
} }
init(props){ init(props){
@ -180,11 +181,14 @@ class Tree extends Component{
} }
if(!hiddenStatus){//如果是显示状态 if(!hiddenStatus){//如果是显示状态
if(this.__skipAutoExpand != val){//第一次搜索默认展开过滤后的数据
let keys = this.state.expandedKeys; let keys = this.state.expandedKeys;
if(val && keys.findIndex(key => key === item[value]) === -1){ if(val && keys.findIndex(key => key === item[value]) === -1){
keys.push(item[value]); keys.push(item[value]);
this.setState({ expandedKeys: keys }) this.setState({ expandedKeys: keys })
} }
this.__skipAutoExpand = val;
}
} }
} }
item.__node.hidn = hiddenStatus; item.__node.hidn = hiddenStatus;
@ -216,6 +220,7 @@ class Tree extends Component{
//清空输入框的值 //清空输入框的值
this.setState({ filterValue: '', val: emptyVal }); this.setState({ filterValue: '', val: emptyVal });
this.__value = ''; this.__value = '';
this.__skipAutoExpand = '';
this.searchInputRef && (this.searchInputRef.value = ''); this.searchInputRef && (this.searchInputRef.value = '');
}else{ }else{
//聚焦输入框 //聚焦输入框

View File

@ -26,6 +26,7 @@ class xmOptions {
//记录最新的配置项 //记录最新的配置项
this.options = deepMerge(this.options, options); this.options = deepMerge(this.options, options);
this.options.__render_success = false;
//如果dom不存在, 则不进行渲染事项 //如果dom不存在, 则不进行渲染事项
let { dom } = this.options; let { dom } = this.options;
@ -46,6 +47,8 @@ class xmOptions {
render(<Framework { ...this.options } __update={ Date.now() } updateData={ updateData } />, dom); render(<Framework { ...this.options } __update={ Date.now() } updateData={ updateData } />, dom);
this.options.__render_success = true;
//返回多选对象 //返回多选对象
return this; return this;
} }
@ -252,6 +255,23 @@ class xmOptions {
return this; return this;
} }
/**
* 滚动到某个选项
*/
scroll(val){
let opt = this.options.dom.querySelector(`.xm-option[value="${ val }"]`);
opt && opt.scrollIntoView(false)
return this;
}
/**
* 重新计算下拉的位置
*/
calcPosition(){
childData[this.options.el].calcPosition()
return this;
}
} }
export default xmOptions; export default xmOptions;

View File

@ -81,6 +81,10 @@ export default function (lan = 'zn') {
showCount: 0, showCount: 0,
//是否开启键盘操作 //是否开启键盘操作
enableKeyboard: true, enableKeyboard: true,
//开启键盘操作后是否默认选中第一条
enableHoverFirst: true,
//键盘选中的KeyCode, 默认是Enter
selectedKeyCode: 13,
//工具条 //工具条
toolbar: { toolbar: {
show: false, show: false,
@ -160,7 +164,7 @@ export default function (lan = 'zn') {
}, },
}, },
icon: 'show', icon: 'show',
type: 'absolute', type: 'absolute',//可选值, relative fixed
}, },
//自定义选中的图标 //自定义选中的图标
iconfont: { iconfont: {
@ -184,6 +188,12 @@ export default function (lan = 'zn') {
//监听选中事件 //监听选中事件
on({ arr, item, selected }){ on({ arr, item, selected }){
},
submitConversion(sels, prop){
return sels.map(item => item[prop.value]).join(',')
},
done(){
} }
} }
} }

View File

@ -1,4 +1,4 @@
import { name, version } from '../package.json' import { name, version, website } from '../package.json'
import { selector, warn } from '@/common/util' import { selector, warn } from '@/common/util'
import Select from '@/components/xm-select' import Select from '@/components/xm-select'
@ -9,6 +9,11 @@ export const childData = {};
export default { export default {
name, name,
version, version,
doc: website,
KeyCode: {
Enter: 13,
Space: 32,
},
render(options) { render(options) {
let { el } = options; let { el } = options;
options.dom = selector(el); options.dom = selector(el);
@ -23,7 +28,7 @@ export default {
let instance = new Select(options); let instance = new Select(options);
//已经渲染 //已经渲染
if (instance) { if (instance && instance.options.__render_success) {
datas[el] = instance; datas[el] = instance;
} }
return instance; return instance;
@ -54,18 +59,25 @@ export default {
args.splice(0, 2); args.splice(0, 2);
return this.get(filter).map(instance => instance[method](...args)); return this.get(filter).map(instance => instance[method](...args));
}, },
arr2tree(arr, pid, id, children, topParentId){ arr2tree(arr=[], pid='pid', id='id', children='children', topParentId=0){
arr.forEach(item => { const datas = {} // 数据缓存
if(item[pid] != topParentId){ return safety(arr).filter(item =>{
let parent = arr.find(i => i[id] === item[pid]) const _id = item[id] // 提取自身id 必须唯一
if(parent){ const _pid = item[pid] // 提取父级id
if(!parent[children]){ const self = datas[_id] // 读取数据缓存中的数据
parent[children] = []; let parent = datas[_pid] // 读取父级数据
if(self){ // 如果缓存中有数据
item[children] = self[children] // 把缓存的数据保存到自身
} }
parent[children].push(item) datas[_id] = item // 替换缓存中的数据
if(!parent){ // 如果没有找到父级数据
parent = { // 创建一个全新的父级数据
[children]:[]
} }
datas[_pid] = parent // 记录到缓存
} }
parent.push(item) // 推送自身到父级
return id == topParentId // 这里用 == 防止出现 字符串不等于数字类型的情况
}) })
return arr.filter(i => i[pid] == topParentId)
} }
} }

View File

@ -1,7 +1,8 @@
import '@/common/expand' import '@/common/expand'
import '@/style/index.less'
import '@/style/iconfont.less' import '@/style/iconfont.less'
import '@/style/index.less'
import { default as xmSelect, datas } from './index.js'; import { default as xmSelect, datas } from './index.js';
import {throttle} from '@/common/util'
const moduleName = 'xmSelect'; const moduleName = 'xmSelect';
@ -15,6 +16,16 @@ window.addEventListener('click', () => {
}) })
}) })
/**
* 监听页面滚动事件
*/
window.addEventListener('scroll', throttle(() => {
Object.keys(datas).forEach(key => {
let item = datas[key]
item && item.calcPosition && item.calcPosition()
})
}))
if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') { if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
module.exports = xmSelect; module.exports = xmSelect;

View File

@ -61,7 +61,7 @@ xm-select{
cursor: pointer; cursor: pointer;
outline: none; outline: none;
&:hover{ &:hover,&:focus{
border-color: #C0C4CC; border-color: #C0C4CC;
} }
@ -109,11 +109,13 @@ xm-select{
} }
.label-content{ .label-content{
flex-wrap: nowrap; flex-wrap: nowrap;
white-space: nowrap;
} }
} }
&.auto-row{ &.auto-row{
.label-content{ .label-content{
flex-wrap: wrap; flex-wrap: wrap;
padding-right: 30px !important;
} }
.xm-label-block > span{ .xm-label-block > span{
white-space: unset; white-space: unset;
@ -124,7 +126,7 @@ xm-select{
.scroll{ .scroll{
.label-content{ .label-content{
display: flex; display: flex;
padding: 3px 30px 3px 10px; padding: 3px 10px;
} }
} }
@ -486,6 +488,9 @@ xm-select{
.disabled .xm-right-arrow{ .disabled .xm-right-arrow{
color: #C2C2C2 !important; color: #C2C2C2 !important;
} }
.hide-icon.disabled .xm-right-arrow{
color: #999 !important;
}
} }
} }