下拉自定义
This commit is contained in:
maplemei
2019-10-20 18:01:27 +08:00
parent de672117e1
commit 6d23654a43
27 changed files with 2136 additions and 133 deletions

View File

@@ -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;
}

View File

@@ -9,6 +9,8 @@ export default function (lan = 'zn') {
return {
//多选数据
data: [],
//自定义数据
content: '',
//表单提交的name
name: 'select',
//尺寸

View File

@@ -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;
}
/**
* 闪烁警告边框
*/

View File

@@ -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>
);

View 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;

View File

@@ -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(

View File

@@ -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{