v1.0.10
下拉自定义
This commit is contained in:
parent
de672117e1
commit
6d23654a43
16
CHANGELOG.md
16
CHANGELOG.md
@ -1,5 +1,21 @@
|
||||
## 更新日志
|
||||
|
||||
### 1.0.10
|
||||
|
||||
*2019-10-20*
|
||||
|
||||
#### 新增
|
||||
|
||||
- 新增`content`配置, 可自定义下拉框HTML, 具体见 [下拉自定义](https://maplemei.gitee.io/xm-select/#/example-plugin/ZP01)
|
||||
- 方法`setValue`新增参数`listenOn`, 可以设置是否通过`on`监听
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
- 修复初始化渲染也会被`on`监听的bug
|
||||
- 修复分组模式下, 搜索后分组显示错误
|
||||
- 调整分组模式下也可以使用分页, 选项控制
|
||||
|
||||
|
||||
### 1.0.9
|
||||
|
||||
*2019-10-17*
|
||||
|
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
12
dist/static/docs.js
vendored
12
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
@ -232,3 +232,12 @@ button, input, select, textarea {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.demo-ZP01{
|
||||
.xm-body-custom{
|
||||
padding: 0 10px;
|
||||
}
|
||||
table{
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import VueRouter from 'vue-router';
|
||||
import routes from './router';
|
||||
import App from './App.vue';
|
||||
import demoBlock from './components/demo-block.vue';
|
||||
import './plugins'
|
||||
|
||||
Vue.use(ElementUI);
|
||||
Vue.use(VueRouter);
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
### 随便试试
|
||||
|
||||
修改一下背景色和外边距吧
|
||||
修改一下外边距, 加上圆角, 更改一下高度
|
||||
|
||||
:::demo
|
||||
```html
|
||||
@ -12,8 +12,9 @@
|
||||
var demo1 = xmSelect.render({
|
||||
el: '#demo1',
|
||||
style: {
|
||||
backgroundColor: 'red',
|
||||
marginLeft: '200px',
|
||||
borderRadius: '50px',
|
||||
height: '50px',
|
||||
},
|
||||
data: [
|
||||
{name: '张三', value: 1},
|
||||
|
@ -9,6 +9,10 @@
|
||||
```html
|
||||
<div id="demo1" class="xm-select-demo"></div>
|
||||
|
||||
<br/><br/>
|
||||
<button class="btn" id="setValue1">监听setValue(['zhangsan'], null, true)</button>
|
||||
<button class="btn" id="setValue2">不监听setValue(['zhangsan'])</button>
|
||||
|
||||
<script>
|
||||
var demo1 = xmSelect.render({
|
||||
el: '#demo1',
|
||||
@ -21,6 +25,14 @@ var demo1 = xmSelect.render({
|
||||
{name: '王五', value: 'wangwu'},
|
||||
]
|
||||
})
|
||||
|
||||
document.getElementById('setValue1').onclick = function(){
|
||||
demo1.setValue(['zhangsan'], null, true);
|
||||
}
|
||||
|
||||
document.getElementById('setValue2').onclick = function(){
|
||||
demo1.setValue(['zhangsan']);
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
@ -1,12 +1,6 @@
|
||||
## 分组
|
||||
|
||||
|
||||
|
||||
:::tip
|
||||
使用分组时, 不建议开启分页, 也不建议开启选项数量控制!!!
|
||||
:::
|
||||
|
||||
|
||||
### optgroup模式
|
||||
|
||||
:::demo 指定选项中的`optgroup`为`true`
|
||||
@ -134,3 +128,37 @@ var demo4 = xmSelect.render({
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
|
||||
### 带有分页的分组
|
||||
|
||||
:::demo
|
||||
```html
|
||||
<div id="demo5" class="xm-select-demo"></div>
|
||||
|
||||
<script>
|
||||
var demo5 = xmSelect.render({
|
||||
el: '#demo5',
|
||||
toolbar:{
|
||||
show: true,
|
||||
},
|
||||
filterable: true,
|
||||
height: '500px',
|
||||
paging: true,
|
||||
pageSize: 2,
|
||||
data: [
|
||||
{name: '销售员', children: [
|
||||
{name: '张三1', value: 1},
|
||||
{name: '李四1', value: 2},
|
||||
{name: '王五13', value: 3},
|
||||
]},
|
||||
{name: '奖品', children: [
|
||||
{name: '苹果23', value: 4},
|
||||
{name: '香蕉2', value: 5},
|
||||
{name: '葡萄2', value: 6},
|
||||
]},
|
||||
]
|
||||
})
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
53
docs/mds/ZP01.md
Normal file
53
docs/mds/ZP01.md
Normal file
@ -0,0 +1,53 @@
|
||||
## 下拉自定义
|
||||
|
||||
|
||||
|
||||
### 下拉表格
|
||||
|
||||
至于能干什么, 就看你们的想象了~~
|
||||
|
||||
:::demo
|
||||
```html
|
||||
|
||||
<div id="demo1"></div>
|
||||
|
||||
<script>
|
||||
//先渲染多选
|
||||
var demo1 = xmSelect.render({
|
||||
el: '#demo1',
|
||||
content: `
|
||||
<table class="layui-table">
|
||||
<colgroup>
|
||||
<col width="150">
|
||||
<col width="200">
|
||||
<col>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>昵称</th>
|
||||
<th>加入时间</th>
|
||||
<th>签名</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>贤心</td>
|
||||
<td>2016-11-29</td>
|
||||
<td>人生就像是一场修行</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>许闲心</td>
|
||||
<td>2016-11-28</td>
|
||||
<td>于千万人之中遇见你所遇见的人,于千万年之中,时间的无涯的荒野里…</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`,
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
:::
|
88
docs/mds/ZP02.md
Normal file
88
docs/mds/ZP02.md
Normal file
@ -0,0 +1,88 @@
|
||||
## 下拉树
|
||||
|
||||
### eleTree
|
||||
|
||||
结合 `layui` 插件中心的 `eleTree`, <a href='https://fly.layui.com/extend/eleTree/' target='_blank'>传送门</a>
|
||||
|
||||
|
||||
:::demo
|
||||
```html
|
||||
|
||||
<div id="demo1" class="xm-select-demo"></div>
|
||||
|
||||
<script>
|
||||
//先渲染多选
|
||||
var demo1 = xmSelect.render({
|
||||
el: '#demo1',
|
||||
theme: {
|
||||
color: '#5FB878',
|
||||
},
|
||||
content: '<div id="ele1" lay-filter="ele1"></div>',
|
||||
})
|
||||
|
||||
//渲染自定义内容
|
||||
var ele = layui.eleTree.render({
|
||||
elem: '#ele1',
|
||||
data: [
|
||||
{
|
||||
id: 1,
|
||||
label: "安徽省",
|
||||
children: [
|
||||
{
|
||||
id: 2,
|
||||
label: "马鞍山市",
|
||||
disabled: true,
|
||||
children: [
|
||||
{
|
||||
id: 3,
|
||||
label: "和县",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: "花山区",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
label: "河南省",
|
||||
children: [
|
||||
{
|
||||
id: 6,
|
||||
label: "郑州市"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
showCheckbox: true,
|
||||
defaultExpandAll: true,
|
||||
});
|
||||
|
||||
//监听下拉多选的选择
|
||||
demo1.update({
|
||||
on({ arr, change, isAdd }){
|
||||
if(isAdd === false){//监听取消
|
||||
ele.setChecked(arr.map(item => item.id), true);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
//监听树的选择
|
||||
layui.eleTree.on("nodeChecked(ele1)", function(d) {
|
||||
var arr = ele.getChecked(true, false)
|
||||
demo1.update({
|
||||
prop: {
|
||||
name: 'label',
|
||||
value: 'id',
|
||||
},
|
||||
data: arr,
|
||||
}).setValue(arr)
|
||||
})
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
:::
|
@ -7,28 +7,29 @@
|
||||
<div id="demo1" class="xm-select-demo"></div>
|
||||
|
||||
<script>
|
||||
//先渲染多选
|
||||
var demo1 = xmSelect.render({
|
||||
el: '#demo1',
|
||||
filterable: true,
|
||||
toolbar: {
|
||||
show: true
|
||||
},
|
||||
height: '500px',
|
||||
model: {
|
||||
icon: 'hidden',
|
||||
},
|
||||
autoRow: true,
|
||||
data: [
|
||||
{name: '城市', optgroup: true},
|
||||
{name: '北京13', value: 1},
|
||||
{name: '天津1', value: 2, selected: true, disabled: true},
|
||||
{name: '上海1', value: 3},
|
||||
{name: '销售员', children: [
|
||||
{name: '李四23', value: 4, selected: true},
|
||||
{name: '王五2', value: 5},
|
||||
]},
|
||||
],
|
||||
paging: true,
|
||||
pageSize: 2,
|
||||
data(){
|
||||
return [
|
||||
{name: '销售员', children: [
|
||||
{name: '张三1', value: 1, selected: true},
|
||||
{name: '李四1', value: 2, selected: true},
|
||||
{name: '王五1', value: 3, disabled: true},
|
||||
]},
|
||||
{name: '奖品', children: [
|
||||
{name: '苹果2', value: 4, selected: true, disabled: true},
|
||||
{name: '香蕉2', value: 5},
|
||||
{name: '葡萄2', value: 6},
|
||||
]},
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
@ -8,6 +8,7 @@
|
||||
| el | 渲染对象, css选择器 | string | - | - |
|
||||
| language | 语言选择 | string | zn / en | zn |
|
||||
| data | 显示的数据 | array | - | [ ] |
|
||||
| content | 自定义下拉框html | string | - | - |
|
||||
| initValue | 初始化选中的数据, 需要在data中存在 | array | - | null |
|
||||
| tips | 默认提示, 类似于placeholder | string | - | 请选择 |
|
||||
| empty | 空数据提示 | string | - | 暂无数据 |
|
||||
@ -38,7 +39,7 @@
|
||||
| name | 表单提交时的name | string | - | select |
|
||||
| toolbar | 工具条, 具体看下表 | object | - | - |
|
||||
| showCount | 展示在下拉框中的最多选项数量 | int | - | 0 |
|
||||
| autoRow | 是否开启自动换行(选项过多时) | boolean | - | false |
|
||||
| autoRow | 是否开启自动换行(选项过多时) | boolean | true / false | false |
|
||||
| size | 尺寸 | string | large / medium / small / mini | medium |
|
||||
|
||||
|
||||
@ -171,7 +172,7 @@ xmSelect.render()后会返回一个xmSelect对象, 可以进行方法调用
|
||||
| 事件名 | 说明 | 参数 |
|
||||
| ------ | ------------------ | -------- |
|
||||
| getValue | 获取当前选中的数据 | (type: 类型), 可选值: name, nameStr, value, valueStr |
|
||||
| setValue | 动态设置数据 | (array: 选中的数据, show: 是否展开下拉, 不传默认当前显示状态, 取值: true/false) |
|
||||
| setValue | 动态设置数据 | (array: 选中的数据, show: 是否展开下拉,不传默认当前显示状态,取值: true/false, listenOn: 是否触发on的监听, 默认false) |
|
||||
| append | 追加赋值 | (array: 追加的数据) |
|
||||
| delete | 删除赋值 | (array: 删除的数据) |
|
||||
| opened | 主动展开下拉 | - |
|
||||
|
@ -22,3 +22,8 @@
|
||||
|
||||
- 打开控制台查看是否报错
|
||||
- 加群: 660408068, 询问
|
||||
|
||||
|
||||
### 4.占位标签为什么是div
|
||||
|
||||
演示中使用的是div, 不限制标签, 但是不建议使用`select`, 因为`layui`会渲染`select`标签
|
168
docs/plugins/eleTree/eleTree.css
Executable file
168
docs/plugins/eleTree/eleTree.css
Executable file
@ -0,0 +1,168 @@
|
||||
/* #region tree */
|
||||
.eleTree{
|
||||
position: relative;
|
||||
}
|
||||
.eleTree-hide,
|
||||
.eleTree-search-hide{
|
||||
display: none;
|
||||
}
|
||||
.eleTree-loadData{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 0px;
|
||||
}
|
||||
.eleTree-loadData .layui-icon{
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
}
|
||||
.eleTree-node-content{
|
||||
cursor: pointer;
|
||||
height: 26px;
|
||||
line-height: 1.3;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.eleTree-node-content:hover,
|
||||
.eleTree-node-content.eleTree-node-content-active{
|
||||
background-color: #eee;
|
||||
}
|
||||
.eleTree-node-content-icon .layui-icon{
|
||||
padding: 6px 3px;
|
||||
color: #c0c4cc;
|
||||
font-size: 12px;
|
||||
display: inline-block;
|
||||
transform: rotate(0deg);
|
||||
transition: transform .3s ease-in-out;
|
||||
}
|
||||
.eleTree-node-content-icon .layui-icon.icon-rotate{
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
.eleTree-node-content .layui-form-checkbox[lay-skin=primary] i{
|
||||
width: 13px;
|
||||
height: 14px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.eleTree-node-content-label{
|
||||
padding-left: 5px;
|
||||
}
|
||||
.eleTree-node-content-input{
|
||||
width: 80px;
|
||||
border: 1px solid #e6e6e6;
|
||||
outline: 0;
|
||||
padding: 3px 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 线条样式 */
|
||||
.eleTree-node{
|
||||
position: relative;
|
||||
}
|
||||
.eleTree-node .eleTree-node-verticalline{
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
border: 1px dotted #ccc;
|
||||
z-index: 1;
|
||||
}
|
||||
.eleTree-node .eleTree-node-horizontalline{
|
||||
position: absolute;
|
||||
height: 0;
|
||||
top: 13px;
|
||||
border: 1px dotted #ccc;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* checkbox第三种状态 */
|
||||
input.eleTree-hideen[type=checkbox]{
|
||||
display: none;
|
||||
}
|
||||
.eleTree-checkbox {
|
||||
height: auto!important;
|
||||
line-height: normal!important;
|
||||
min-height: 12px;
|
||||
border: none!important;
|
||||
margin-right: 0;
|
||||
padding-left: 18px;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
.eleTree-checkbox i {
|
||||
left: 0;
|
||||
border: 1px solid #d2d2d2;
|
||||
font-size: 12px;
|
||||
border-radius: 2px;
|
||||
background-color: #fff;
|
||||
-webkit-transition: .1s linear;
|
||||
transition: .1s linear;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
width: 13px;
|
||||
height: 14px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.eleTree-checkbox i:hover {
|
||||
border-color: #5FB878;
|
||||
}
|
||||
.eleTree-checkbox-checked i {
|
||||
border-color: #5FB878;
|
||||
background-color: #5FB878;
|
||||
color: #fff;
|
||||
}
|
||||
.eleTree-checkbox-line:after{
|
||||
content: "";
|
||||
position: relative;
|
||||
width: 8px;
|
||||
height: 1px;
|
||||
background-color: #fff;
|
||||
display: inline-block;
|
||||
top: -4px;
|
||||
}
|
||||
|
||||
.eleTree-checkbox.eleTree-checkbox-disabled i{
|
||||
cursor: not-allowed;
|
||||
background-color: #f2f6fc;
|
||||
border-color: #dcdfe6;
|
||||
color: #c2c2c2;
|
||||
}
|
||||
.eleTree-checkbox.eleTree-checkbox-disabled i.eleTree-checkbox-line:after{
|
||||
background-color: #c2c2c2;
|
||||
}
|
||||
.eleTree-checkbox.eleTree-checkbox-disabled i:hover{
|
||||
border-color: #dcdfe6;
|
||||
}
|
||||
|
||||
#tree-menu{
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
position: absolute;
|
||||
background: #f5f5f5;
|
||||
border: 1px solid #979797;
|
||||
box-shadow: 2px 2px 2px #999;
|
||||
display: none;
|
||||
z-index: 20181205;
|
||||
}
|
||||
#tree-menu li>a{
|
||||
display: block;
|
||||
padding: 0 1em;
|
||||
text-decoration: none;
|
||||
width: auto;
|
||||
color: #000;
|
||||
white-space: nowrap;
|
||||
line-height: 2.4em;
|
||||
text-shadow: 1px 1px 0 #fff;
|
||||
border-radius: 1px;
|
||||
}
|
||||
#tree-menu li>a:hover{
|
||||
background-color: #e8eff7;
|
||||
box-shadow: 0 0 2px #0a6aa1;
|
||||
}
|
||||
.tree-menu-bg{
|
||||
background-color: #ccc;
|
||||
}
|
||||
/* #endregion */
|
1554
docs/plugins/eleTree/eleTree.js
Executable file
1554
docs/plugins/eleTree/eleTree.js
Executable file
File diff suppressed because it is too large
Load Diff
2
docs/plugins/index.js
Normal file
2
docs/plugins/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
import './eleTree/eleTree.js'
|
||||
import './eleTree/eleTree.css'
|
@ -1,4 +1,5 @@
|
||||
import Component from './components/component.vue';
|
||||
import { version } from '../package.json'
|
||||
|
||||
function importVue(path) {
|
||||
return r => require.ensure([], () => r(require(`./pages${path}.vue`)));
|
||||
@ -20,7 +21,7 @@ export default [{
|
||||
redirect: '/component',
|
||||
}, {
|
||||
path: '/changelog',
|
||||
name: '更新日志',
|
||||
name: '更新日志 v' + version,
|
||||
component: importVue('/changelog'),
|
||||
}, {
|
||||
path: '/add',
|
||||
@ -84,12 +85,25 @@ export default [{
|
||||
{ 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') },
|
||||
]
|
||||
}, {
|
||||
path: '/example-plugin',
|
||||
name: '拓展中心',
|
||||
redirect: '/example-plugin/ZP01',
|
||||
component: Component,
|
||||
children: [
|
||||
{ path: '/example-plugin/ZP01', name: '下拉自定义', component: importMd('/ZP01') },
|
||||
{ path: '/example-plugin/ZP02', name: '下拉树', component: importMd('/ZP02') },
|
||||
]
|
||||
}, {
|
||||
path: '/question',
|
||||
name: '常见问题',
|
||||
component: importMd('/question'),
|
||||
},
|
||||
}, {
|
||||
path: '/test',
|
||||
name: '测试',
|
||||
hidden: true,
|
||||
component: importMd('/ZTEST'),
|
||||
},
|
||||
|
||||
];
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xm-select",
|
||||
"version": "1.0.9",
|
||||
"version": "1.0.10",
|
||||
"description": "始于Layui的select多选解决方案",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
@ -146,50 +146,27 @@ export function IEVersion() {
|
||||
}
|
||||
}
|
||||
|
||||
export function filterGroupOption(arr, data, prop){
|
||||
const { children, optgroup } = prop;
|
||||
data.filter(item => !item[optgroup]).forEach(item => {
|
||||
let child = item[children];
|
||||
if(isArray(child)){
|
||||
filterGroupOption(arr, child, children, optgroup);
|
||||
}else{
|
||||
arr.push(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function findSelected(arr, data, prop){
|
||||
const { selected, children, optgroup } = prop;
|
||||
data.filter(item => !item[optgroup]).forEach(item => {
|
||||
let child = item[children];
|
||||
if(isArray(child)){
|
||||
findSelected(arr, child, prop);
|
||||
}else{
|
||||
item[selected] && (arr.push(item));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
export function exchangeOptionsData(arr, { prop }){
|
||||
let { disabled, children, optgroup, value } = prop;
|
||||
let newArr = [], group;
|
||||
for(let i = 0; i < arr.length; i++){
|
||||
let item = arr[i];
|
||||
newArr.push(item);
|
||||
if(item[optgroup]){
|
||||
group = item;
|
||||
item[children] = [];
|
||||
continue;
|
||||
}
|
||||
let child = item[children];
|
||||
if(isArray(child)){
|
||||
group = null;
|
||||
item[optgroup] = true;
|
||||
child.forEach(c => newArr.push(c));
|
||||
continue;
|
||||
}
|
||||
if(group){
|
||||
group[children].push(item);
|
||||
}
|
||||
}
|
||||
return newArr;
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ export default function (lan = 'zn') {
|
||||
return {
|
||||
//多选数据
|
||||
data: [],
|
||||
//自定义数据
|
||||
content: '',
|
||||
//表单提交的name
|
||||
name: 'select',
|
||||
//尺寸
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { h, Component, render } from '@/components/preact'
|
||||
import Framework from '@/components/element/framework'
|
||||
import { selector, warn, listenerClose, watch, safety, isArray, deepMerge } from '@/components/common/util'
|
||||
import { selector, warn, listenerClose, isArray, deepMerge, exchangeOptionsData } from '@/components/common/util'
|
||||
import defaultOptions from '@/components/config/options'
|
||||
|
||||
|
||||
@ -46,6 +46,18 @@ class xmOptions {
|
||||
warn(`没有找到渲染对象: ${options.el}, 请检查`)
|
||||
return ;
|
||||
}
|
||||
//判断data的数据类型
|
||||
let optionsData = this.options.data || [];
|
||||
if(typeof(optionsData) === 'function'){
|
||||
optionsData = optionsData();
|
||||
this.options.data = optionsData;
|
||||
}
|
||||
if(!isArray(optionsData)){
|
||||
warn(`data数据必须为数组类型, 不能是${ typeof(data) }类型`)
|
||||
return ;
|
||||
}
|
||||
//调整数据结构
|
||||
this.options.data = exchangeOptionsData(optionsData, this.options);
|
||||
|
||||
const onRef = (ref) => childs[this.options.el] = ref;
|
||||
|
||||
@ -93,7 +105,7 @@ class xmOptions {
|
||||
* 获取多选选中的数据
|
||||
*/
|
||||
getValue(type){
|
||||
let arr = safety(childs[this.options.el].state.sels);
|
||||
let arr = deepMerge([], childs[this.options.el].state.sels);
|
||||
|
||||
if(type === 'name'){
|
||||
return arr.map(item => item[this.options.prop.name]);
|
||||
@ -114,12 +126,12 @@ class xmOptions {
|
||||
/**
|
||||
* 设置多选数据
|
||||
*/
|
||||
setValue(sels, show){
|
||||
setValue(sels, show, listenOn = false){
|
||||
if(!isArray(sels)){
|
||||
warn('请传入数组结构...')
|
||||
return ;
|
||||
}
|
||||
childs[this.options.el].value(sels, show);
|
||||
childs[this.options.el].value(sels, show, listenOn);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -134,7 +146,7 @@ class xmOptions {
|
||||
childs[this.options.el].append(sels);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除赋值
|
||||
*/
|
||||
@ -146,7 +158,7 @@ class xmOptions {
|
||||
childs[this.options.el].del(sels);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 闪烁警告边框
|
||||
*/
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { h, Component, render } from '@/components/preact'
|
||||
import { checkUserAgent, isFunction, toNum, filterGroupOption, findSelected, mergeArr } from '@/components/common/util'
|
||||
import { checkUserAgent, isFunction, toNum, mergeArr } from '@/components/common/util'
|
||||
|
||||
//渲染类
|
||||
import Tips from './tips';
|
||||
import Label from './label';
|
||||
import General from './model/general';
|
||||
import Custom from './model/custom';
|
||||
|
||||
/**
|
||||
* 框架渲染类, 渲染基础的外边框 + 属性变化监听
|
||||
@ -28,14 +29,13 @@ class Framework extends Component{
|
||||
}
|
||||
|
||||
findValue(data){
|
||||
let list = [];
|
||||
findSelected(list, data, this.props.prop);
|
||||
return list;
|
||||
const { selected } = this.props.prop;
|
||||
return data.filter(item => item[selected] === true);
|
||||
}
|
||||
|
||||
resetSelectValue(sels = [], change = [], isAdd){
|
||||
resetSelectValue(sels = [], change = [], isAdd, listenOn = true){
|
||||
let on = this.props.on;
|
||||
if(isFunction(on)){
|
||||
if(isFunction(on) && this.prepare && listenOn){
|
||||
on({ arr: sels, change, isAdd });
|
||||
}
|
||||
this.setState({ sels });
|
||||
@ -45,20 +45,19 @@ class Framework extends Component{
|
||||
this.setState({ data });
|
||||
}
|
||||
|
||||
value(sels, show){
|
||||
value(sels, show, listenOn){
|
||||
if(show !== false && show !== true){
|
||||
show = this.state.show;
|
||||
}
|
||||
let changeData = this.exchangeValue(sels);
|
||||
this.resetSelectValue(changeData, changeData, true);
|
||||
this.resetSelectValue(changeData, changeData, true, listenOn);
|
||||
this.setState({ show })
|
||||
}
|
||||
|
||||
exchangeValue(sels){
|
||||
const { optgroup, value } = this.props.prop;
|
||||
let data = this.state.data;
|
||||
let value = this.props.prop.value;
|
||||
let list = [];
|
||||
filterGroupOption(list, data, this.props.prop);
|
||||
let list = data.filter(item => !item[optgroup]);
|
||||
return sels.map(sel => typeof sel === 'object' ? sel[value] : sel).map(val => list.find(item => item[value] == val)).filter(a => a);
|
||||
}
|
||||
|
||||
@ -82,7 +81,7 @@ class Framework extends Component{
|
||||
|
||||
auto(arr){
|
||||
let value = this.props.prop.value;
|
||||
let sels = arr.filter(v => this.state.sels.findIndex(item => item[value] === v) != -1);
|
||||
let sels = arr.filter(v => this.state.sels.findIndex(item => item[value] === v[value]) != -1);
|
||||
sels.length == arr.length ? this.del(arr) : this.append(arr);
|
||||
}
|
||||
|
||||
@ -174,6 +173,10 @@ class Framework extends Component{
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.prepare = true;
|
||||
}
|
||||
|
||||
render(config, { sels, show }) {
|
||||
const { tips, theme, prop, style, radio, repeat, clickClose, on, max, maxMethod } = config;
|
||||
const borderStyle = { borderColor: theme.color };
|
||||
@ -194,7 +197,7 @@ class Framework extends Component{
|
||||
this.updateBorderColor('')
|
||||
}, 300);
|
||||
}
|
||||
|
||||
|
||||
//右边下拉箭头的变化class
|
||||
const iconClass = show ? 'xm-icon xm-icon-expand' : 'xm-icon';
|
||||
//提示信息的属性
|
||||
@ -256,7 +259,11 @@ class Framework extends Component{
|
||||
<Tips { ...tipsProps } />
|
||||
<Label { ...labelProps } />
|
||||
<div class={ bodyClass } ref={ ref => this.bodyView = ref}>
|
||||
<General { ...bodyProps } />
|
||||
{ config.content ? (
|
||||
<Custom content={ config.content } />
|
||||
) : (
|
||||
<General { ...bodyProps } />
|
||||
) }
|
||||
</div>
|
||||
</xm-select>
|
||||
);
|
||||
|
30
src/components/element/model/custom.js
Normal file
30
src/components/element/model/custom.js
Normal file
@ -0,0 +1,30 @@
|
||||
import { h, Component, render } from '@/components/preact'
|
||||
|
||||
/**
|
||||
* 默认提示
|
||||
*/
|
||||
class Custom extends Component{
|
||||
|
||||
constructor(options){
|
||||
super(options);
|
||||
}
|
||||
|
||||
blockClick(e){
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
shouldComponentUpdate(){
|
||||
return !this.already;
|
||||
}
|
||||
|
||||
render(config) {
|
||||
this.already = true;
|
||||
return (
|
||||
<div onClick={ this.blockClick } class="xm-body-custom" dangerouslySetInnerHTML={{ __html: config.content }}>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Custom;
|
@ -1,5 +1,5 @@
|
||||
import { h, Component, render } from '@/components/preact'
|
||||
import { isFunction, isArray, safety, deepMerge, mergeArr, IEVersion, filterGroupOption, addGroupLabel } from '@/components/common/util'
|
||||
import { isFunction, isArray, safety, deepMerge, mergeArr, IEVersion } from '@/components/common/util'
|
||||
|
||||
/**
|
||||
* 普通的多选渲染
|
||||
@ -29,13 +29,15 @@ class General extends Component{
|
||||
}
|
||||
|
||||
groupClick(item, e){
|
||||
let m = item[this.props.prop.click];
|
||||
const { click, children, disabled } = this.props.prop;
|
||||
let m = item[click], arr = item[children].filter(opt => !opt[disabled]);
|
||||
|
||||
if(m === 'SELECT'){
|
||||
this.props.onReset(item.__value, 'append');
|
||||
this.props.onReset(arr, 'append');
|
||||
}else if(m === 'CLEAR'){
|
||||
this.props.onReset(item.__value, 'delete');
|
||||
this.props.onReset(arr, 'delete');
|
||||
}else if(m === 'AUTO'){
|
||||
this.props.onReset(item.__value, 'auto');
|
||||
this.props.onReset(arr, 'auto');
|
||||
}else if(isFunction(m)){
|
||||
m(item);
|
||||
}
|
||||
@ -161,13 +163,9 @@ class General extends Component{
|
||||
const filterData = (item, index) => {
|
||||
const isGroup = item[optgroup];
|
||||
if(isGroup){
|
||||
delete item.__del;
|
||||
return true;
|
||||
}
|
||||
const child = item[children];
|
||||
if(isArray(child) && child.length > 0){//分组模式
|
||||
item[children] = child.filter(filterData);
|
||||
return item[children].length != 0;
|
||||
}
|
||||
return filterMethod(this.state.filterValue, item, index, prop);
|
||||
}
|
||||
arr = arr.filter(filterData);
|
||||
@ -175,7 +173,7 @@ class General extends Component{
|
||||
for(let i = 0; i < arr.length - 1; i++){
|
||||
let a = arr[i];
|
||||
let b = arr[i + 1];
|
||||
if(a[optgroup] && (b[optgroup] || isArray(b[children]))){
|
||||
if(a[optgroup] && b[optgroup]){
|
||||
arr[i].__del = true;
|
||||
}
|
||||
}
|
||||
@ -200,11 +198,15 @@ class General extends Component{
|
||||
</div>
|
||||
);
|
||||
|
||||
//如果是分组模式, 要分页先去除分组, 然后在计算分页, 最后再加上分组
|
||||
let groups = [], groupInfo = {};
|
||||
groups = arr.filter(item => item[optgroup]).forEach(g => {
|
||||
g[children].forEach(item => groupInfo[item[value]] = g);
|
||||
});
|
||||
arr = arr.filter(item => !item[optgroup]);
|
||||
|
||||
let paging = '';
|
||||
|
||||
if(config.paging){
|
||||
|
||||
//计算当前分页的总页码
|
||||
const size = Math.floor((arr.length - 1) / config.pageSize) + 1;
|
||||
|
||||
@ -260,6 +262,17 @@ class General extends Component{
|
||||
}
|
||||
}
|
||||
|
||||
let newArr = [], group;
|
||||
arr.forEach(item => {
|
||||
let g = groupInfo[item[value]];
|
||||
if(g != group){
|
||||
group = g;
|
||||
newArr.push(group);
|
||||
}
|
||||
newArr.push(item);
|
||||
});
|
||||
arr = newArr;
|
||||
|
||||
let safetyArr = deepMerge([], arr);
|
||||
this.tempData = safetyArr;
|
||||
|
||||
@ -272,9 +285,9 @@ class General extends Component{
|
||||
let info;
|
||||
if(tool === 'ALL'){
|
||||
info = { icon: 'xm-iconfont xm-icon-quanxuan', name: '全选', method: (pageData) => {
|
||||
const list = [];
|
||||
filterGroupOption(list, pageData, prop);
|
||||
this.props.onReset(mergeArr(list.filter(item => !item[prop.disabled]), sels, prop), 'sels');
|
||||
const { optgroup, disabled } = prop;
|
||||
const list = pageData.filter(item => !item[optgroup]).filter(item => !item[disabled])
|
||||
this.props.onReset(mergeArr(list, sels, prop), 'sels');
|
||||
} };
|
||||
}else if(tool === 'CLEAR'){
|
||||
info = { icon: 'xm-iconfont xm-icon-qingkong', name: '清空', method: (pageData) => {
|
||||
@ -333,18 +346,10 @@ class General extends Component{
|
||||
</div>
|
||||
)
|
||||
}
|
||||
const child = item[children];
|
||||
if(isArray(child) && child.length > 0){//分组模式
|
||||
return (
|
||||
<div class="xm-group">
|
||||
<div class="xm-group-item" onClick={ this.groupClick.bind(this, item) }>{ item[name] }</div>
|
||||
{ child.map(renderItem) }
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return renderItem(item);
|
||||
}
|
||||
arr = addGroupLabel(arr, prop).map(renderGroup);
|
||||
|
||||
arr = arr.map(renderGroup);
|
||||
|
||||
if(!arr.length){
|
||||
arr.push(
|
||||
|
@ -60,11 +60,13 @@ xm-select{
|
||||
border-color: #C0C4CC;
|
||||
}
|
||||
|
||||
|
||||
& > .xm-tips{
|
||||
color: #999999;
|
||||
padding: 0 10px;
|
||||
position: absolute;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
& > .xm-icon{
|
||||
@ -337,6 +339,15 @@ xm-select{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.xm-body-custom{
|
||||
line-height: initial;
|
||||
cursor: default;
|
||||
|
||||
*{
|
||||
box-sizing: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.xm-input{
|
||||
|
Loading…
Reference in New Issue
Block a user