v1.1.0.Beta+
This commit is contained in:
parent
db6fdae5cd
commit
b14cbaa913
@ -7,17 +7,21 @@
|
||||
#### 新增
|
||||
|
||||
- label也可以自定义渲染
|
||||
- label新增title提示
|
||||
- 新增远程分页配置`pageRemote`
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
- 树形组件
|
||||
- [新增]`strict`严格父子结构
|
||||
- [新增]`lazy`懒加载模式
|
||||
- [修改]树状结构使用`setValue`数据错误
|
||||
- [修改]树状结构中`children`属性为空数组时无法操作节点的问题
|
||||
- [修改]半选状态下如无可选子项则变更操作为取消
|
||||
- 修改`initValue`失效的问题
|
||||
- 修改`getValue()`方法无法序列化的问题
|
||||
- 调整拓展中心下拉日期多选的样式
|
||||
- 修改搜索模式下输入中文的bug
|
||||
|
||||
|
||||
### 1.1.0.Beta
|
||||
|
2
dist/static/2.js
vendored
2
dist/static/2.js
vendored
File diff suppressed because one or more lines are too long
2
dist/static/3.js
vendored
2
dist/static/3.js
vendored
File diff suppressed because one or more lines are too long
2
dist/static/docs.js
vendored
2
dist/static/docs.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xm-select.js
vendored
2
dist/xm-select.js
vendored
File diff suppressed because one or more lines are too long
102
docs/mds/XM08.md
102
docs/mds/XM08.md
@ -174,3 +174,105 @@ var demo4 = xmSelect.render({
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
|
||||
### 远程分页
|
||||
|
||||
```
|
||||
xmSelect.render({
|
||||
//...
|
||||
//开启分页
|
||||
paging: true,
|
||||
//远程分页
|
||||
pageRemote: true,
|
||||
//实现方法
|
||||
remoteMethod: function(val, cb, show, pageIndex),
|
||||
})
|
||||
```
|
||||
|
||||
:::demo `render`后, 就会进行一次回调, 用于渲染第一次数据
|
||||
```html
|
||||
<div id="demo5" class="xm-select-demo"></div>
|
||||
|
||||
<script>
|
||||
var demo5 = xmSelect.render({
|
||||
el: '#demo5',
|
||||
paging: true,
|
||||
pageRemote: true,
|
||||
remoteMethod: function(val, cb, show, pageIndex){
|
||||
//val: 搜索框的内容, 不开启搜索默认为空, cb: 回调函数, show: 当前下拉框是否展开, pageIndex: 当前第几页
|
||||
|
||||
//这里的axios类似于ajax
|
||||
axios({
|
||||
method: 'get',
|
||||
url: 'https://www.fastmock.site/mock/98228b1f16b7e5112d6c0c87921eabc1/xmSelect/search',
|
||||
params: {
|
||||
keyword: val + '_' + pageIndex,
|
||||
}
|
||||
}).then(response => {
|
||||
//这里是success的处理
|
||||
var res = response.data;
|
||||
//回调需要两个参数, 第一个: 数据数组, 第二个: 总页码
|
||||
cb(res.data, 10)
|
||||
}).catch(err => {
|
||||
//这里是error的处理
|
||||
cb([], 0);
|
||||
});
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
|
||||
### 搜索 + 远程分页
|
||||
|
||||
```
|
||||
xmSelect.render({
|
||||
//...
|
||||
//开启分页
|
||||
paging: true,
|
||||
//远程分页
|
||||
pageRemote: true,
|
||||
//实现方法
|
||||
remoteMethod: function(val, cb, show, pageIndex),
|
||||
})
|
||||
```
|
||||
|
||||
:::demo `render`后, 就会进行一次回调, 用于渲染第一次数据
|
||||
```html
|
||||
<div id="demo6" class="xm-select-demo"></div>
|
||||
|
||||
<script>
|
||||
var demo6 = xmSelect.render({
|
||||
el: '#demo6',
|
||||
//配置搜索
|
||||
filterable: true,
|
||||
//配置远程分页
|
||||
paging: true,
|
||||
pageRemote: true,
|
||||
//数据处理
|
||||
remoteMethod: function(val, cb, show, pageIndex){
|
||||
//val: 搜索框的内容, 不开启搜索默认为空, cb: 回调函数, show: 当前下拉框是否展开, pageIndex: 当前第几页
|
||||
|
||||
//这里的axios类似于ajax
|
||||
axios({
|
||||
method: 'get',
|
||||
url: 'https://www.fastmock.site/mock/98228b1f16b7e5112d6c0c87921eabc1/xmSelect/search',
|
||||
params: {
|
||||
keyword: val + '_' + pageIndex,
|
||||
}
|
||||
}).then(response => {
|
||||
//这里是success的处理
|
||||
var res = response.data;
|
||||
//回调需要两个参数, 第一个: 数据数组, 第二个: 总页码
|
||||
cb(res.data, 10)
|
||||
}).catch(err => {
|
||||
//这里是error的处理
|
||||
cb([], 0);
|
||||
});
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
@ -1,4 +1,4 @@
|
||||
## 远程搜索
|
||||
## 弹框中的多选
|
||||
|
||||
|
||||
### layer弹出框
|
||||
|
@ -102,3 +102,76 @@ var demo1 = xmSelect.render({
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
|
||||
### 懒加载的树
|
||||
|
||||
```
|
||||
tree: {
|
||||
show: true,
|
||||
expandedKeys: [ -1 ],
|
||||
//开启懒加载
|
||||
lazy: true,
|
||||
//加载方法
|
||||
load: function(item, cb){
|
||||
//item: 点击的节点, cb: 回调函数
|
||||
//这里模拟ajax
|
||||
setTimeout(function(){
|
||||
var name = item.name + 1;
|
||||
cb([
|
||||
{name: item.name + 1, value: item.value + '1', children: [] },
|
||||
{name: item.name + 2, value: item.value + '2' },
|
||||
])
|
||||
}, 500)
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
:::demo
|
||||
```html
|
||||
<div id="demo2" class="xm-select-demo"></div>
|
||||
|
||||
<script>
|
||||
var demo2 = xmSelect.render({
|
||||
el: '#demo2',
|
||||
autoRow: true,
|
||||
tree: {
|
||||
show: true,
|
||||
showFolderIcon: true,
|
||||
showLine: true,
|
||||
indent: 20,
|
||||
expandedKeys: [ -1 ],
|
||||
lazy: true,
|
||||
load: function(item, cb){
|
||||
setTimeout(function(){
|
||||
cb([
|
||||
{name: item.name + 1, value: item.value + '1', children: [] },
|
||||
{name: item.name + 2, value: item.value + '2' },
|
||||
])
|
||||
}, 500)
|
||||
}
|
||||
},
|
||||
height: 'auto',
|
||||
data(){
|
||||
return [
|
||||
{name: '销售员', value: -1, children: [
|
||||
{name: '张三1', value: 100, selected: true, children: []},
|
||||
{name: '李四1', value: 2, selected: true},
|
||||
{name: '王五1', value: 3, disabled: true},
|
||||
]},
|
||||
{name: '奖品', value: -2, 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: 5},
|
||||
{name: '葡萄2', value: 6},
|
||||
]},
|
||||
]
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
@ -1,34 +1,41 @@
|
||||
## 测试
|
||||
|
||||
|
||||
:::demo
|
||||
```html
|
||||
|
||||
<div id="demo1" class="xm-select-demo"></div>
|
||||
|
||||
<script>
|
||||
//先渲染多选
|
||||
var demo1 = xmSelect.render({
|
||||
el: '#demo1',
|
||||
autoRow: true,
|
||||
tree: {
|
||||
show: true,
|
||||
expandedKeys: [-3],
|
||||
showFolderIcon: true,
|
||||
showLine: true,
|
||||
indent: 20,
|
||||
expandedKeys: [ -1 ],
|
||||
lazy: true,
|
||||
load: function(item, cb){
|
||||
setTimeout(function(){
|
||||
var name = item.name + 1;
|
||||
cb([
|
||||
{name: item.name + 1, value: item.value + '1', children: [] },
|
||||
{name: item.name + 2, value: item.value + '2' },
|
||||
])
|
||||
}, 500)
|
||||
}
|
||||
},
|
||||
height: 'auto',
|
||||
on({ arr, change, isAdd }){
|
||||
console.log(arr, change, isAdd)
|
||||
},
|
||||
data(){
|
||||
return [
|
||||
{name: '销售员', value: -1, disabled: true, children: [
|
||||
{name: '张三1', value: 1, selected: true},
|
||||
{name: '销售员', value: -1, children: [
|
||||
{name: '张三1', value: 100, selected: true, children: []},
|
||||
{name: '李四1', value: 2, selected: true},
|
||||
{name: '王五1', value: 3, disabled: true},
|
||||
]},
|
||||
{name: '奖品', value: -2, children: [
|
||||
{name: '奖品3', value: -3, children: [
|
||||
{name: '苹果3', value: 14, selected: true, disabled: true},
|
||||
{name: '苹果3', value: 14, selected: true},
|
||||
{name: '香蕉3', value: 15},
|
||||
{name: '葡萄3', value: 16},
|
||||
]},
|
||||
|
@ -18,13 +18,14 @@
|
||||
| filterMethod | 搜索回调函数 | function(val, item, index, prop) val: 当前搜索值, item: 每个option选项, index: 位置数据中的下标, prop: 定义key | - | - |
|
||||
| filterDone | 搜索完成函数 | function(val, list) val: 当前搜索值, list: 过滤后的数据 | - | - |
|
||||
| remoteSearch | 是否开启自定义搜索 (远程搜索)| boolean | true / false | false |
|
||||
| remoteMethod | 自定义搜索回调函数 | function(val, cb, show) val: 当前搜索值, cb: 回调函数, 需要回调一个数组, 结构同data, show: 下拉框显示状态 | - | - |
|
||||
| remoteMethod | 自定义搜索回调函数 | function(val, cb, show, pageIndex) val: 当前搜索值, cb(arr, totalPage): 回调函数, 需要回调一个数组, 结构同data, 远程分页需要第二个参数: 总页码, show: 下拉框显示状态, pageIndex: 分页下当前页码 | - | - |
|
||||
| direction | 下拉方向| string | auto / up / down | auto |
|
||||
| style | 自定义样式| object | - | { } |
|
||||
| height | 默认最大高度| string | - | 200px |
|
||||
| paging | 是否开启自定义分页 | boolean | true / false | false |
|
||||
| pageSize | 分页条数 | int | - | 10 |
|
||||
| pageEmptyShow | 分页无数据是否显示 | boolean | true / false | true |
|
||||
| pageRemote | 是否开启远程分页 | boolean | true / false | true |
|
||||
| radio | 是否开启单选模式 | boolean | true / false | false |
|
||||
| repeat | 是否开启重复性模式 | boolean | true / false | false |
|
||||
| clickClose | 是否点击选项后自动关闭下拉框 | boolean | true / false | false |
|
||||
|
@ -113,8 +113,8 @@ export default [{
|
||||
}, {
|
||||
path: '/test',
|
||||
name: '测试',
|
||||
hidden: true,
|
||||
// hidden: false,
|
||||
// hidden: true,
|
||||
hidden: false,
|
||||
component: importMd('/ZTEST'),
|
||||
},
|
||||
|
||||
|
@ -33,13 +33,13 @@ class Framework extends Component{
|
||||
}
|
||||
|
||||
init(props, refresh){
|
||||
let { data } = props, sels;
|
||||
let { data, prop, initValue } = props, sels;
|
||||
//如果新数据和旧数据不同 或者 强制刷新 才进行数据处理
|
||||
if(refresh){
|
||||
let dataObj = {};
|
||||
let flatData = [];
|
||||
this.load(data, dataObj, flatData);
|
||||
sels = props.initValue ? this.exchangeValue(props.initValue, true, dataObj) : Object.values(dataObj).filter(item => item[props.prop.selected] === true).filter(item => item[this.props.prop.optgroup] !== true)
|
||||
sels = initValue ? this.exchangeValue(initValue, true, dataObj) : Object.values(dataObj).filter(item => item[prop.selected] === true).filter(item => item[prop.optgroup] !== true)
|
||||
this.setState({ sels, dataObj, flatData });
|
||||
}
|
||||
|
||||
@ -85,7 +85,8 @@ class Framework extends Component{
|
||||
const { children, optgroup, value, selected, disabled } = prop;
|
||||
data.forEach(item => {
|
||||
//数据提取/处理
|
||||
item.__node = { parent }
|
||||
item.__node = { parent, loading: item.__node && item.__node.loading }
|
||||
|
||||
dataObj[item[value]] = item;
|
||||
flatData.push(item);
|
||||
//遍历子级数据
|
||||
@ -212,20 +213,19 @@ class Framework extends Component{
|
||||
}
|
||||
this.resetSelectValue(sels, [item], !itemSelected);
|
||||
}
|
||||
let parent = item.__node.parent;
|
||||
if(parent){
|
||||
while(parent){
|
||||
let child = parent[children], len = child.length;
|
||||
let slen = child.filter(i => sels.findIndex(sel => sel[value] === i[value]) !== -1 || i.__node.selected === true).length;
|
||||
parent.__node.selected = slen === len;
|
||||
parent.__node.half = slen > 0 && slen < len;
|
||||
parent = parent.__node.parent;
|
||||
}
|
||||
this.setState({ data: this.state.data })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let parent = item.__node.parent;
|
||||
if(parent){
|
||||
while(parent){
|
||||
let child = parent[children], len = child.length;
|
||||
let slen = child.filter(i => sels.findIndex(sel => sel[value] === i[value]) !== -1 || i.__node.selected === true).length;
|
||||
parent.__node.selected = slen === len;
|
||||
parent.__node.half = (slen > 0 && slen < len) || child.filter(i => i.__node.half === true).length > 0;
|
||||
parent = parent.__node.parent;
|
||||
}
|
||||
this.setState({ data: this.state.data })
|
||||
}
|
||||
|
||||
//检查是否为选择即关闭状态, 强制删除情况下不做处理
|
||||
clickClose && !mandatoryDelete && this.onClick();
|
||||
@ -265,8 +265,7 @@ class Framework extends Component{
|
||||
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 = {};
|
||||
let flatData = [];
|
||||
let dataObj = {}, flatData = [];
|
||||
this.load(data, dataObj, flatData);
|
||||
this.setState({ data, flatData });
|
||||
}else
|
||||
@ -285,6 +284,10 @@ class Framework extends Component{
|
||||
//自动判断模式
|
||||
if(type === 'auto'){
|
||||
this.auto(data);
|
||||
}else
|
||||
//树状结构数据更新
|
||||
if(type === 'treeData'){
|
||||
this.value(this.state.sels, null, true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -323,7 +326,6 @@ class Framework extends Component{
|
||||
}
|
||||
|
||||
render(config, state) {
|
||||
|
||||
const { theme, prop, radio, repeat, clickClose, on, max, maxMethod, content, disabled, tree } = config;
|
||||
const borderStyle = { borderColor: theme.color };
|
||||
let { data, dataObj, flatData, sels, show, tmpColor } = state;
|
||||
@ -356,7 +358,6 @@ class Framework extends Component{
|
||||
//渲染组件
|
||||
let Body = content ? <Custom { ...bodyProps } /> : tree.show ? <Tree { ...bodyProps } /> : <General { ...bodyProps } />;
|
||||
|
||||
|
||||
return (
|
||||
<xm-select { ...xmSelectProps } >
|
||||
<input class="xm-select-default" name={ config.name } value={ sels.map(item => item[prop.value]).join(',') }></input>
|
||||
|
@ -52,8 +52,9 @@ class Label extends Component{
|
||||
const conf = label[type];
|
||||
|
||||
//渲染结果
|
||||
let html = '';
|
||||
let innerHTML = true;
|
||||
let html = '', innerHTML = true;
|
||||
//悬浮显示已选择
|
||||
let title = sels.map(item => item[name]).join(',')
|
||||
|
||||
if(type === 'text'){
|
||||
html = sels.map(sel => `${conf.left}${sel[name]}${conf.right}`).join(conf.separator)
|
||||
@ -103,7 +104,7 @@ class Label extends Component{
|
||||
<div class="scroll" ref={ ref => this.labelRef = ref }>
|
||||
{ innerHTML ?
|
||||
<div class="label-content" dangerouslySetInnerHTML={{__html: html}}></div> :
|
||||
<div class="label-content">{ html }</div>
|
||||
<div class="label-content" title={ title }>{ html }</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -14,7 +14,7 @@ class General extends Component{
|
||||
remote: true,
|
||||
loading: false,
|
||||
pageIndex: 1,
|
||||
pageSize: 10,
|
||||
totalSize: 0,
|
||||
});
|
||||
|
||||
this.searchCid = 0;
|
||||
@ -56,6 +56,7 @@ class General extends Component{
|
||||
return ;
|
||||
}
|
||||
this.changePageIndex(index - 1);
|
||||
this.props.pageRemote && this.postData(index - 1, true);
|
||||
}
|
||||
pageNextClick(e, size){
|
||||
let index = this.state.pageIndex;
|
||||
@ -63,6 +64,7 @@ class General extends Component{
|
||||
return ;
|
||||
}
|
||||
this.changePageIndex(index + 1);
|
||||
this.props.pageRemote && this.postData(index + 1, true);
|
||||
}
|
||||
|
||||
changePageIndex(index){
|
||||
@ -111,6 +113,24 @@ class General extends Component{
|
||||
}
|
||||
}
|
||||
|
||||
postData(pageIndex = this.state.pageIndex, mandatory = false){
|
||||
if(this.state.remote || mandatory){
|
||||
this.callback = false;
|
||||
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.show, pageIndex);
|
||||
}
|
||||
}
|
||||
|
||||
//组件将要接收新属性
|
||||
componentWillReceiveProps(props){
|
||||
if(this.props.show != props.show){
|
||||
if(!props.show){
|
||||
@ -125,20 +145,8 @@ class General extends Component{
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(){
|
||||
if(this.callback){
|
||||
this.callback = false;
|
||||
|
||||
let done = this.props.filterDone;
|
||||
if(isFunction(done)){
|
||||
done(this.state.filterValue, this.tempData || []);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render(config) {
|
||||
|
||||
let { data, flatData, prop, template, theme, radio, sels, empty, filterable, filterMethod, remoteSearch, remoteMethod, delay, searchTips, create } = config
|
||||
let { data, flatData, prop, template, theme, radio, sels, empty, filterable, filterMethod, remoteSearch, remoteMethod, delay, searchTips, create, pageRemote } = config
|
||||
|
||||
const { name, value, disabled, children, optgroup } = prop;
|
||||
|
||||
@ -146,20 +154,7 @@ class General extends Component{
|
||||
//是否开启了搜索
|
||||
if(filterable){
|
||||
if(remoteSearch){//是否进行远程搜索
|
||||
if(this.state.remote){
|
||||
this.callback = false;
|
||||
this.setState({ loading: true, remote: false });
|
||||
//让输入框失去焦点
|
||||
this.blur();
|
||||
remoteMethod(this.state.filterValue, result => {
|
||||
//回调后可以重新聚焦
|
||||
this.focus();
|
||||
|
||||
this.callback = true;
|
||||
this.setState({ loading: false });
|
||||
this.props.onReset(result, 'data');
|
||||
}, this.props.show);
|
||||
}
|
||||
this.postData();
|
||||
}else{
|
||||
const filterData = (item, index) => {
|
||||
const isGroup = item[optgroup];
|
||||
@ -187,17 +182,15 @@ class General extends Component{
|
||||
}
|
||||
}
|
||||
|
||||
//远程分页
|
||||
if(pageRemote){
|
||||
this.postData();
|
||||
}
|
||||
|
||||
const search = (
|
||||
<div class='xm-search'>
|
||||
<i class="xm-iconfont xm-icon-sousuo"></i>
|
||||
<input type="text" class="xm-input xm-search-input" placeholder={ searchTips }
|
||||
ref={ input => this.searchInputRef = input }
|
||||
onClick={ this.blockClick.bind(this) }
|
||||
onInput={ this.searchInput.bind(this) }
|
||||
onCompositionStart={ this.handleComposition.bind(this) }
|
||||
onCompositionUpdate={ this.handleComposition.bind(this) }
|
||||
onCompositionEnd={ this.handleComposition.bind(this) }
|
||||
/>
|
||||
<input class="xm-input xm-search-input" placeholder={ searchTips } />
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -211,7 +204,7 @@ class General extends Component{
|
||||
let paging = '';
|
||||
if(config.paging){
|
||||
//计算当前分页的总页码
|
||||
let size = Math.floor((arr.length - 1) / config.pageSize) + 1;
|
||||
let size = pageRemote ? this.state.totalSize : Math.floor((arr.length - 1) / config.pageSize) + 1;
|
||||
size <= 0 && (size = 1);
|
||||
|
||||
let pageIndex = this.state.pageIndex;
|
||||
@ -226,10 +219,12 @@ class General extends Component{
|
||||
pageIndex = 1;
|
||||
}
|
||||
|
||||
//实现简单的物理分页
|
||||
let start = (pageIndex - 1) * config.pageSize;
|
||||
let end = start + config.pageSize;
|
||||
arr = arr.slice(start, end);
|
||||
if(!pageRemote){
|
||||
//实现简单的物理分页
|
||||
let start = (pageIndex - 1) * config.pageSize;
|
||||
let end = start + config.pageSize;
|
||||
arr = arr.slice(start, end);
|
||||
}
|
||||
|
||||
const disabledStyle = {cursor: 'no-drop', color: '#d2d2d2'};
|
||||
|
||||
@ -237,23 +232,6 @@ class General extends Component{
|
||||
pageIndex <= 1 && (prevStyle = disabledStyle);
|
||||
pageIndex == size && (nextStyle = disabledStyle);
|
||||
|
||||
// const defaultCurrClass = {
|
||||
// position: 'relative',
|
||||
// borderRadius: '1px',
|
||||
// }
|
||||
// {
|
||||
// ''.padEnd(size, ' ').split('').map((s, i) => (
|
||||
// <span style={
|
||||
// this.state.pageIndex == i + 1 ? {
|
||||
// ...defaultCurrClass,
|
||||
// backgroundColor: theme.color,
|
||||
// borderColor: theme.color,
|
||||
// color: '#FFF',
|
||||
// } : defaultCurrClass
|
||||
// }>{ i + 1 }</span>
|
||||
// ))
|
||||
// }
|
||||
|
||||
this.state.pageIndex !== pageIndex && this.changePageIndex(pageIndex);
|
||||
|
||||
paging = (
|
||||
@ -324,11 +302,6 @@ class General extends Component{
|
||||
})
|
||||
this.props.onReset(mergeArr(list, selectedList, prop), 'sels');
|
||||
} };
|
||||
}else if(tool === 'SEARCH'){
|
||||
toolStyle.color = theme.color;
|
||||
info = { icon: 'xm-iconfont xm-icon-sousuo', name, method: (pageData) => {
|
||||
|
||||
} };
|
||||
}else {
|
||||
info = tool
|
||||
}
|
||||
@ -407,6 +380,31 @@ class General extends Component{
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
//组件完成挂载
|
||||
componentDidMount(){
|
||||
let input = this.base.querySelector('.xm-search-input');
|
||||
if(input){
|
||||
input.addEventListener('compositionstart', this.handleComposition.bind(this));
|
||||
input.addEventListener('compositionupdate', this.handleComposition.bind(this));
|
||||
input.addEventListener('compositionend', this.handleComposition.bind(this));
|
||||
input.addEventListener('input', this.searchInput.bind(this));
|
||||
this.searchInputRef = input;
|
||||
}
|
||||
}
|
||||
|
||||
//此时页面又被重新渲染了
|
||||
componentDidUpdate(){
|
||||
if(this.callback){
|
||||
this.callback = false;
|
||||
|
||||
let done = this.props.filterDone;
|
||||
if(isFunction(done)){
|
||||
done(this.state.filterValue, this.tempData || []);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default General;
|
||||
|
@ -34,11 +34,28 @@ class Tree extends Component{
|
||||
|
||||
optionClick(item, selected, disabled, type, e){
|
||||
if(type === 'line'){
|
||||
if(item.__node.loading === true){
|
||||
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 });
|
||||
|
||||
//是否需要懒加载
|
||||
const { tree, prop, sels } = this.props;
|
||||
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] = result;
|
||||
item[prop.selected] = sels.findIndex(i => i[prop.value] === item[prop.value]) != -1
|
||||
this.props.onReset(item, 'treeData');
|
||||
});
|
||||
}
|
||||
}else if(type === 'checkbox'){
|
||||
this.props.ck(item, selected, disabled);
|
||||
}
|
||||
@ -88,12 +105,14 @@ class Tree extends Component{
|
||||
}
|
||||
const className = ['xm-option', (dis ? ' disabled' : ''), (selected ? ' selected' : ''), (showIcon ? 'show-icon' : 'hide-icon') ].join(' ');
|
||||
const iconClass = ['xm-option-icon xm-iconfont', radio ? 'xm-icon-danx' : tree.strict && half ? 'xm-icon-banxuan' : 'xm-icon-duox'].join(' ');
|
||||
const treeIconClass = ['xm-tree-icon', expand ? 'expand':'', item[children] && item[children].length > 0 ? 'visible':'hidden'].join(' ');
|
||||
const treeIconClass = ['xm-tree-icon', expand ? 'expand':'', item[children] && (item[children].length > 0 || tree.lazy) ? 'visible':'hidden'].join(' ');
|
||||
|
||||
return (
|
||||
<div class={ className } style={ itemStyle } value={ item[value] } onClick={ this.optionClick.bind(this, item, selected, item[disabled], 'line') }>
|
||||
{ tree.showFolderIcon && <i class={ treeIconClass }></i> }
|
||||
{ tree.showFolderIcon && tree.showLine && <i class={ expand ? 'top-line expand' : 'top-line' } style={ { left: indent - tree.indent + 3 + 'px', width: tree.indent + (expand === 0 ? 10 : -2) + 'px' } }></i> }
|
||||
{ tree.showFolderIcon && tree.showLine && <i class={ expand ? 'left-line expand' : 'left-line' } style={ {left: indent - tree.indent + 3 + 'px'} }></i> }
|
||||
{ item.__node.loading && <span class="loader"></span> }
|
||||
{ showIcon && <i class={ iconClass } style={ iconStyle } onClick={ this.optionClick.bind(this, item, selected, item[disabled], 'checkbox') }></i> }
|
||||
<div class='xm-option-content' dangerouslySetInnerHTML={{ __html: template({ data, item, arr: sels, name: item[name], value: item[value] }) }}></div>
|
||||
</div>
|
||||
@ -103,11 +122,12 @@ class Tree extends Component{
|
||||
const renderGroup = (item, indent) => {
|
||||
const child = item[children];
|
||||
indent = indent + tree.indent
|
||||
if(child && child.length > 0){//分组模式
|
||||
if(child){//分组模式
|
||||
let expand = this.state.expandedKeys.findIndex(k => item[value] === k) !== -1;
|
||||
child.length === 0 && (expand = false)
|
||||
return (
|
||||
<div class="xm-tree">
|
||||
{ tree.showFolderIcon && tree.showLine && <i class={ expand ? 'left-line expand' : 'left-line' } style={ {left: indent + 3 + 'px'} }></i> }
|
||||
{ tree.showFolderIcon && tree.showLine && expand && <i class='left-line left-line-group' style={ {left: indent + 3 + 'px'} }></i> }
|
||||
{ renderItem(item, indent, expand) }
|
||||
{ expand && <div class="xm-tree-box">{ child.map(c => renderGroup(c, indent)) }</div> }
|
||||
</div>
|
||||
|
@ -60,6 +60,8 @@ export default function (lan = 'zn') {
|
||||
pageSize: 10,
|
||||
//分页无数据是否展示分页
|
||||
pageEmptyShow: true,
|
||||
//是否开启远程分页
|
||||
pageRemote: false,
|
||||
//是否开启单选模式
|
||||
radio: false,
|
||||
//是否开启重复选模式
|
||||
@ -91,6 +93,10 @@ export default function (lan = 'zn') {
|
||||
expandedKeys: [],
|
||||
//是否严格遵守父子模式
|
||||
strict: true,
|
||||
//是否懒加载
|
||||
lazy: false,
|
||||
//懒加载回调
|
||||
load: null,
|
||||
},
|
||||
//自定义属性名称
|
||||
prop: {
|
||||
|
@ -243,6 +243,13 @@ xm-select{
|
||||
&.selected.hide-icon .xm-option-content{
|
||||
color: #FFF !important;
|
||||
}
|
||||
|
||||
.loader{
|
||||
width: 0.8em;
|
||||
height: 0.8em;
|
||||
margin-right: 6px;
|
||||
color: #C2C2C2;
|
||||
}
|
||||
}
|
||||
|
||||
.xm-select-empty{
|
||||
@ -392,10 +399,8 @@ xm-select{
|
||||
z-index: 1;
|
||||
border-top: 1px dotted #c0c4cc !important;
|
||||
}
|
||||
&-box{
|
||||
&.dis{
|
||||
|
||||
}
|
||||
.xm-tree-icon+.top-line{
|
||||
margin-left: 1px;
|
||||
}
|
||||
}
|
||||
.scroll-body>.xm-tree>.xm-option>.top-line{
|
||||
@ -434,22 +439,20 @@ xm-select{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.loader{
|
||||
border: .2em dotted currentcolor;
|
||||
border-radius: 50%;
|
||||
-webkit-animation: 1s loader linear infinite;
|
||||
animation: 1s loader linear infinite;
|
||||
|
||||
|
||||
.loader{
|
||||
border: .2em dotted currentcolor;
|
||||
border-radius: 50%;
|
||||
-webkit-animation: 1s loader linear infinite;
|
||||
animation: 1s loader linear infinite;
|
||||
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
color: inherit;
|
||||
vertical-align: middle;
|
||||
pointer-events: none;
|
||||
}
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
color: inherit;
|
||||
vertical-align: middle;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.xm-select-default{
|
||||
@ -502,25 +505,15 @@ xm-select{
|
||||
}
|
||||
.xm-tree{
|
||||
.left-line{
|
||||
height: calc(100% - @size);
|
||||
top: @size / 2;
|
||||
height: 100%;
|
||||
bottom: @size / 2;
|
||||
&.expand{
|
||||
height: 100%;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
&:last-child{
|
||||
.left-line{
|
||||
height: calc(100% - @size);
|
||||
}
|
||||
.left-line-group{
|
||||
height: calc(100% - @size);
|
||||
}
|
||||
.xm-tree-icon.hidden+.top-line{
|
||||
top: @size / 2 - 1px;
|
||||
}
|
||||
.xm-tree-icon+.top-line{
|
||||
margin-left: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
xm-select[size='large']{
|
||||
|
Loading…
Reference in New Issue
Block a user