diff --git a/CHANGELOG.md b/CHANGELOG.md
index b0e9cc3..a09ca60 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,28 @@
## 更新日志
+### 1.0.8
+
+*2019-10-16*
+
+#### 兼容提示
+
+- 此版本的on方法结构调整, 升级请注意
+
+#### 新增
+
+- 新增分组单击事件 click, 可选值 `SELECT`, `CLEAR`, `AUTO`, `自定义`
+- 新增`append`方法追加赋值, `delete`方法删除赋值
+- 新增搜索完成回调`filterDone`
+
+#### Bug fixes
+
+- 修复全选和请空不走on监听的问题
+- 修复`autoRow`模式下, 无选项时的css样式错误
+- 修复`update`后, 下拉框显示状态被重置为隐藏
+- 优化`setValue`方法, 可自行判断下拉框的显示状态
+- 修复文档错误, 实例没有`render`方法
+
+
### 1.0.7
*2019-10-16*
diff --git a/dist/static/2.js b/dist/static/2.js
index 2d5063a..d0fa844 100644
--- a/dist/static/2.js
+++ b/dist/static/2.js
@@ -1 +1 @@
-(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{361:function(e,t,n){e.exports=n.p+"static/wx.f391ad4.jpg"},363:function(e,t,n){"use strict";n.r(t);var a=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("section",{staticClass:"content element-doc"},[e._m(0),e._m(1),n("demo-block",[n("template",{slot:"source"},[n("element-demo0")],1),n("template",{slot:"highlight"},[n("pre",{pre:!0},[n("code",{pre:!0,attrs:{class:"html"}},[e._v("
\n\n
```
:::
+
+
+### 搜索完成回调
+
+:::demo
+```html
+
+
+
+```
+:::
diff --git a/docs/mds/XM16.md b/docs/mds/XM16.md
index fefe105..ca7ff65 100644
--- a/docs/mds/XM16.md
+++ b/docs/mds/XM16.md
@@ -12,8 +12,8 @@
```
:::
+
+
+### 分组的单击事件
+
+:::demo
+```html
+
+
+
+```
+:::
diff --git a/docs/mds/ZM01.md b/docs/mds/ZM01.md
index 8d5f485..5f5be95 100644
--- a/docs/mds/ZM01.md
+++ b/docs/mds/ZM01.md
@@ -8,9 +8,13 @@
:::demo
```html
+
-
+
+
+
+
+```
+:::
diff --git a/docs/mds/ZM05.md b/docs/mds/ZM05.md
new file mode 100644
index 0000000..41d1a35
--- /dev/null
+++ b/docs/mds/ZM05.md
@@ -0,0 +1,56 @@
+## 动态数据
+
+
+### 本地数据动态赋值
+
+:::demo
+```html
+
+
+
+```
+:::
+
+
+### 远程数据动态赋值
+
+:::demo
+```html
+
+
+
+```
+:::
diff --git a/docs/mds/ZM06.md b/docs/mds/ZM06.md
new file mode 100644
index 0000000..c82ea3b
--- /dev/null
+++ b/docs/mds/ZM06.md
@@ -0,0 +1,33 @@
+## 远程搜索
+
+
+### layer弹出框
+
+:::demo
+```html
+
+
+
+```
+:::
diff --git a/docs/mds/options.md b/docs/mds/options.md
index 5605159..d8aabbe 100644
--- a/docs/mds/options.md
+++ b/docs/mds/options.md
@@ -15,6 +15,7 @@
| searchTips | 搜索提示 | string | - | 请选择 |
| delay | 搜索延迟 ms | int | - | 500 |
| filterMethod | 搜索回调函数 | function(val, item, index, prop) val: 当前搜索值, item: 每个option选项, index: 位置数据中的下标, prop: 定义key | - | - |
+| filterDone | 搜索完成函数 | function(val) val: 当前搜索值 | - | - |
| remoteSearch | 是否开启自定义搜索 (远程搜索)| boolean | true / false | false |
| remoteMethod | 自定义搜索回调函数 | function(val, cb, show) val: 当前搜索值, cb: 回调函数, 需要回调一个数组, 结构同data, show: 下拉框显示状态 | - | - |
| direction | 下拉方向| string | auto / up / down | auto |
@@ -31,7 +32,7 @@
| show | 展开下拉的回调 | function | - | - |
| hide | 隐藏下拉的回调 | function | - | - |
| template | 自定义渲染选项 | function({ item, sels, name, value }) | - | - |
-| on | 监听选中变化 | function({ arr, item, selected }) | - | - |
+| on | 监听选中变化 | function({ arr, change, isAdd }) | - | - |
| max | 设置多选选中上限 | int | - | 0 |
| maxMethod | 达到选中上限的回到 | function(sels, item), sels: 已选中数据, item: 当前选中的值 | - | - |
| name | 表单提交时的name | string | - | select |
@@ -45,13 +46,41 @@
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------------- | ------------------------------ | --------------- | ------ | ------ |
| name | 显示名称 | string | - | name |
-| value | 选中值 | string | - | value |
+| value | 选中值, 当前多选唯一 | string | - | value |
| selected | 是否选中 | string | - | selected |
| disabled | 是否禁用 | string | - | disabled |
| children | 分组children | string | - | children |
| optgroup | 分组optgroup | string | - | optgroup |
+### 分组说明
+
+如果children属性为数组, 或者optgroup=true的时候开启分组模式
+
+```
+//平级结构下面的数据为一组
+{name: '城市', optgroup: true},
+
+//children下的数组为一组
+{name: '销售员', children: [
+ {name: '李四', value: 4, selected: true},
+ {name: '王五', value: 5},
+]},
+
+//可在分组上定义click属性, 来定义点击事件
+//这里以optgroup模式为例, children模式同理
+{name: '选中', optgroup: true, click: 'SELECT'},
+{name: '清空', optgroup: true, click: 'CLEAR'},
+{name: '自动', optgroup: true, click: 'AUTO'},
+{name: '自定义', optgroup: true, click: function(item){
+ alert('自定义的, 想干嘛干嘛');
+}},
+
+
+
+```
+
+
### theme
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
@@ -109,7 +138,7 @@ model: {
| showIcon | 是否显示工具图标 | boolean | true / false | true |
| list | 工具条数组 (默认有 全选/清空, 可以自定义) | array | - | [ "ALL", "CLEAR" ] |
-- 自定义方式
+> 自定义方式
```
@@ -141,9 +170,10 @@ xmSelect.render()后会返回一个xmSelect对象, 可以进行方法调用
| 事件名 | 说明 | 参数 |
| ------ | ------------------ | -------- |
| getValue | 获取当前选中的数据 | (type: 类型), 可选值: name, nameStr, value, valueStr |
-| setValue | 动态设置数据 | (array: 选中的数据, show: 是否展开下拉) |
+| setValue | 动态设置数据 | (array: 选中的数据, show: 是否展开下拉, 不传默认当前显示状态, 取值: true/false) |
+| append | 追加赋值 | (array: 追加的数据) |
+| delete | 删除赋值 | (array: 删除的数据) |
| opened | 主动展开下拉 | - |
| closed | 主动关闭下拉 | - |
-| render | 重新渲染多选 | (options: 见配置项) |
| reset | 重置为上一次的render状态 | - |
-| update | 更新多选选中, reset不保留 | - |
+| update | 更新多选选中, reset不保留 | (options: 见配置项) |
diff --git a/docs/router.js b/docs/router.js
index 5d426d7..874d702 100644
--- a/docs/router.js
+++ b/docs/router.js
@@ -78,7 +78,10 @@ export default [{
children: [
{ path: '/example-custom/ZM01', name: '赋值与取值', component: importMd('/ZM01') },
{ path: '/example-custom/ZM02', name: '表单提交', component: importMd('/ZM02') },
- // { path: '/example-custom/ZM03', name: '表格中多选', component: importMd('/ZM03') },
+ { path: '/example-custom/ZM03', name: '表格中多选', component: importMd('/ZM03') },
+ { path: '/example-custom/ZM04', name: '远程搜索', component: importMd('/ZM04') },
+ { path: '/example-custom/ZM05', name: '动态数据', component: importMd('/ZM05') },
+ { path: '/example-custom/ZM06', name: '弹框中的多选', component: importMd('/ZM06') },
// { path: '/example-custom/ZTEST', name: '测试', component: importMd('/ZTEST') },
]
}, {
diff --git a/src/components/common/util.js b/src/components/common/util.js
index ffebe3c..2707ad0 100644
--- a/src/components/common/util.js
+++ b/src/components/common/util.js
@@ -169,3 +169,27 @@ export function findSelected(arr, data, prop){
}
});
}
+
+export function addGroupLabel(arr, prop){
+ const { disabled, children, optgroup, value } = prop;
+ let group;
+ for(let i = 0; i < arr.length; i++){
+ let item = arr[i];
+ if(item[optgroup]){
+ group = item;
+ group.__value = [];
+ continue;
+ }
+ let child = item[children];
+ if(child && child.length > 0){
+ group = null;
+ item.__value = child.filter(c => !c[disabled]).map(c => c[value]);
+ continue;
+ }
+ if(!group || item[disabled]){
+ continue;
+ }
+ group.__value.push(item[value]);
+ }
+ return arr;
+}
diff --git a/src/components/config/options.js b/src/components/config/options.js
index 3c32f05..e1e5824 100644
--- a/src/components/config/options.js
+++ b/src/components/config/options.js
@@ -71,6 +71,7 @@ export default function (lan = 'zn') {
disabled: 'disabled',
children: 'children',
optgroup: 'optgroup',
+ click: 'click',
},
//主题配置
theme: {
diff --git a/src/components/core/index.js b/src/components/core/index.js
index d9a3bb6..4b76439 100644
--- a/src/components/core/index.js
+++ b/src/components/core/index.js
@@ -94,7 +94,7 @@ class xmOptions {
*/
getValue(type){
let arr = safety(childs[this.options.el].state.sels);
-
+
if(type === 'name'){
return arr.map(item => item[this.options.prop.name]);
}else
@@ -107,7 +107,7 @@ class xmOptions {
if(type === 'valueStr'){
return arr.map(item => item[this.options.prop.value]).join(',');
}
-
+
return arr;
}
@@ -119,10 +119,33 @@ class xmOptions {
warn('请传入数组结构...')
return ;
}
- childs[this.options.el].value(sels, !!show);
+ childs[this.options.el].value(sels, show);
return this;
}
-
+
+ /**
+ * 追加赋值
+ */
+ append(sels){
+ if(!isArray(sels)){
+ warn('请传入数组结构...')
+ return ;
+ }
+ childs[this.options.el].append(sels);
+ return this;
+ }
+
+ /**
+ * 删除赋值
+ */
+ delete(sels){
+ if(!isArray(sels)){
+ warn('请传入数组结构...')
+ return ;
+ }
+ childs[this.options.el].del(sels);
+ return this;
+ }
}
diff --git a/src/components/element/framework.js b/src/components/element/framework.js
index 8f24fff..c915c05 100644
--- a/src/components/element/framework.js
+++ b/src/components/element/framework.js
@@ -24,7 +24,7 @@ class Framework extends Component{
//用于多选上限的边框颜色变化
this.updateBorderColor('');
this.resetDate(props.data);
- this.value(props.initValue ? props.initValue : this.findValue(this.state.data), false);
+ this.value(props.initValue ? props.initValue : this.findValue(this.state.data), !!this.state.show);
}
findValue(data){
@@ -33,22 +33,58 @@ class Framework extends Component{
return list;
}
+ resetSelectValue(sels = [], change = [], isAdd){
+ let on = this.props.on;
+ if(isFunction(on)){
+ on({ arr: sels, change, isAdd });
+ }
+ this.setState({ sels });
+ }
+
resetDate(data = []){
this.setState({ data });
}
value(sels, show){
- let data = this.state.data;
- let value = this.props.prop.value;
+ if(show !== false && show !== true){
+ show = this.state.show;
+ }
+ let changeData = this.exchangeValue(sels);
+ this.resetSelectValue(changeData, changeData, true);
+ this.setState({ show })
+ }
+ exchangeValue(sels){
+ let data = this.state.data;
+ let value = this.props.prop.value;
let list = [];
filterGroupOption(list, data, this.props.prop);
- this.setState({
- sels: sels.map(sel => typeof sel === 'object' ? sel[value] : sel).map(val => list.find(item => item[value] == val)).filter(a => a),
- //下拉框是否展开
- show,
- })
- }
+ return sels.map(sel => typeof sel === 'object' ? sel[value] : sel).map(val => list.find(item => item[value] == val)).filter(a => a);
+ }
+
+ append(arr){
+ let changeData = this.exchangeValue(arr);
+ this.resetSelectValue(mergeArr(changeData, this.state.sels, this.props.prop), changeData, true);
+ }
+
+ del(arr){
+ let value = this.props.prop.value;
+ let sels = this.state.sels;
+ arr = this.exchangeValue(arr);
+ arr.forEach(v => {
+ let index = sels.findIndex(item => item[value] === v[value]);
+ if(index != -1){
+ sels.splice(index, 1);
+ }
+ });
+ this.resetSelectValue(sels, arr, false);
+ }
+
+ auto(arr){
+ let value = this.props.prop.value;
+ let sels = arr.filter(v => this.state.sels.findIndex(item => item[value] === v) != -1);
+ sels.length == arr.length ? this.del(arr) : this.append(arr);
+ }
updateBorderColor(tmpColor){
this.setState({ tmpColor });
@@ -57,11 +93,25 @@ class Framework extends Component{
onReset(data, type){
//重置数据
if(type === 'data'){
- this.setState({ sels: mergeArr(this.findValue(data), this.state.sels, this.props.prop), data });
+ let changeData = this.findValue(data);
+ this.resetSelectValue(mergeArr(changeData, this.state.sels, this.props.prop), changeData, true);
+ this.setState({ data });
}else
//重置选中数据
if(type === 'sels'){
- this.setState({ sels: data });
+ this.resetSelectValue(data, data, true);
+ }else
+ //追加数据
+ if(type === 'append'){
+ this.append(data);
+ }else
+ //清理数据
+ if(type === 'delete'){
+ this.del(data);
+ }else
+ //自动判断模式
+ if(type === 'auto'){
+ this.auto(data);
}
}
@@ -157,7 +207,7 @@ class Framework extends Component{
let index = sels.findIndex(sel => sel[valueProp] == item[valueProp])
if(index != -1){
sels.splice(index, 1);
- this.setState({ sels });
+ this.resetSelectValue(sels, [item], !selected);
}
}else{
//查看是否设置了多选上限
@@ -173,14 +223,12 @@ class Framework extends Component{
//如果是单选模式
if(radio){
- this.setState({ sels: [item] });
+ this.resetSelectValue([item], [item], !selected);
}else{
- this.setState({ sels: [...sels, item] });
+ this.resetSelectValue([...sels, item], [item], !selected);
}
}
- on && on({ arr: this.state.sels, item, selected: !selected });
-
//检查是否为选择即关闭状态, 强制删除情况下不做处理
clickClose && !mandatoryDelete && this.onClick();
};
diff --git a/src/components/element/model/general.js b/src/components/element/model/general.js
index cc999a2..98d634d 100644
--- a/src/components/element/model/general.js
+++ b/src/components/element/model/general.js
@@ -1,5 +1,5 @@
import { h, Component, render } from '@/components/preact'
-import { isFunction, isArray, safety, mergeArr, IEVersion, filterGroupOption } from '@/components/common/util'
+import { isFunction, isArray, safety, deepMerge, mergeArr, IEVersion, filterGroupOption, addGroupLabel } from '@/components/common/util'
/**
* 普通的多选渲染
@@ -28,6 +28,21 @@ class General extends Component{
this.blockClick(e);
}
+ groupClick(item, e){
+ let m = item[this.props.prop.click];
+ if(m === 'SELECT'){
+ this.props.onReset(item.__value, 'append');
+ }else if(m === 'CLEAR'){
+ this.props.onReset(item.__value, 'delete');
+ }else if(m === 'AUTO'){
+ this.props.onReset(item.__value, 'auto');
+ }else if(isFunction(m)){
+ m(item);
+ }
+ //阻止父组件上的事件冒泡
+ this.blockClick(e);
+ }
+
blockClick(e){
e.stopPropagation();
}
@@ -69,6 +84,7 @@ class General extends Component{
this.searchCid = setTimeout(() => this.setState({
filterValue: this.__value,
remote: true,
+ callback: true,
}), this.props.delay);
}
}
@@ -107,13 +123,24 @@ class General extends Component{
}
}
+ componentDidUpdate(){
+ if(this.state.callback){
+ this.setState({ callback: false });
+
+ let done = this.props.filterDone;
+ if(isFunction(done)){
+ done(this.state.filterValue);
+ }
+ }
+ }
+
render(config) {
let { data, prop, template, theme, radio, sels, empty, filterable, filterMethod, remoteSearch, remoteMethod, delay, searchTips } = config
const { name, value, disabled, children, optgroup } = prop;
- let arr = safety(data);
+ let arr = deepMerge([], data);
//是否开启了搜索
if(filterable){
if(remoteSearch){//是否进行远程搜索
@@ -232,7 +259,8 @@ class General extends Component{
}
}
- let safetyArr = safety(arr);
+ let safetyArr = deepMerge([], arr);
+
//工具条操作
const toolbar = (
@@ -294,28 +322,28 @@ class General extends Component{
)
}
+
const renderGroup = item => {
const isGroup = item[optgroup];
if(isGroup){//分组模式
return (
-
{ item[name] }
+
{ item[name] }
)
}
-
const child = item[children];
if(isArray(child) && child.length > 0){//分组模式
return (
-
{ item[name] }
+
{ item[name] }
{ child.map(renderItem) }
)
}
return renderItem(item);
}
- arr = arr.map(renderGroup);
+ arr = addGroupLabel(arr, prop).map(renderGroup);
if(!arr.length){
arr.push(
diff --git a/src/style/index.less b/src/style/index.less
index d27686c..f86b7e7 100644
--- a/src/style/index.less
+++ b/src/style/index.less
@@ -68,7 +68,7 @@ xm-select{
& > .xm-tips{
color: #999999;
padding: 0 10px;
- height: 100%;
+ position: absolute;
}
& > .xm-icon{
@@ -116,16 +116,9 @@ xm-select{
.scroll{
.label-content{
- line-height: @heightLabel;
- height: calc(100% - 20px);
display: flex;
- align-items: baseline;
- white-space: pre;
+ line-height: @heightLabel;
padding: 3px 30px 3px 10px;
- &:after{
- content: '-';
- opacity: 0;
- }
}
}