This commit is contained in:
maplemei
2019-04-30 11:07:58 +08:00
parent 5dd011eaec
commit f27ae9ba9f
25 changed files with 1786 additions and 78 deletions

View File

@@ -0,0 +1,114 @@
import { h, Component, render } from '@/components/preact'
//渲染类
import Tips from './tips';
import Label from './label';
import General from './model/general';
/**
* 框架渲染类, 渲染基础的外边框 + 属性变化监听
*/
class Framework extends Component{
constructor(options){
super(options);
//初始化多选数据
this.reset();
//回传子组件
this.props.onRef(this);
}
reset(){
let selected = this.props.prop.selected;
this.value(this.props.initValue ? this.props.initValue : this.props.data.filter(item => item[selected]), false);
}
value(sels, show){
let data = this.props.data;
let value = this.props.prop.value;
this.setState({
sels: sels.map(sel => typeof sel === 'object' ? sel[value] : sel).map(val => data.find(item => item[value] == val)).filter(a => a),
//下拉框是否展开
show
})
}
onClick(e){
let show = !this.state.show;
if(show){
if(this.props.show && this.props.show() == false){
return;
}
//事件互斥原则, 打开一个多选, 关闭其他所有多选
this.props.onClose(this.props.el);
}else{
if(this.props.hidn && this.props.hidn() == false){
return;
}
}
this.setState({ show })
//阻止其他绑定事件的冒泡
e && e.stopPropagation();
}
componentWillReceiveProps(props){
}
render({ tips, theme, data, prop, template, model, empty }, { sels, show }) {
const borderStyle = { borderColor: theme.color };
//最外层边框的属性
const xmSelectProps = {
style: show ? borderStyle : '',
onClick: this.onClick.bind(this)
}
//右边下拉箭头的变化class
const iconClass = show ? 'xm-icon xm-icon-expand' : 'xm-icon';
//提示信息的属性
const tipsProps = {
tips,
//没有已选择数据, 则显示提示
show: !sels.length
}
//普通多选数据
const valueProp = prop.value;
const ck = (item, selected, disabled) => {
//如果是禁用状态, 不能进行操作
if(disabled) return;
//如果现在是选中状态
if(selected){
let index = sels.findIndex(sel => sel[valueProp] == item[valueProp])
if(index != -1){
sels.splice(index, 1);
this.setState(sels);
}
}else{
this.setState({
sels: [...sels, item]
})
}
};
const labelProps = { data, prop, model, theme, sels, ck, title: sels.map(sel => sel[prop.name]).join(',') }
const bodyProps = { data, prop, template, theme, sels, ck, empty }
//控制下拉框的显示于隐藏
const bodyClass = show ? 'xm-body' : 'xm-body dis';
return (
<xm-select { ...xmSelectProps }>
<i class={ iconClass } />
<Tips { ...tipsProps } />
<Label { ...labelProps } />
<div class={ bodyClass }>
<General { ...bodyProps } />
</div>
</xm-select>
);
}
}
export default Framework;

View File

View File

@@ -0,0 +1,76 @@
import { h, Component, render } from '@/components/preact'
/**
* 标签的渲染
*/
class Label extends Component{
constructor(options){
super(options);
}
iconClick(item, selected, disabled, e){
this.props.ck(item, selected, disabled);
//阻止父组件上的事件冒泡
e.stopPropagation();
}
render({ data, prop, theme, model, sels }) {
//获取变换属性
const { name, disabled } = prop;
//获取配置项
const label = model.label;
const type = label.type;
const conf = label[type];
//渲染结果
let html = '';
if(type === 'text'){
html = sels.map(sel => `${conf.left}${sel[name]}${conf.right}`).join(conf.separator)
}else if(type === 'block'){
//已选择的数据
let arr = [...sels];
const style = { backgroundColor: theme.color }
//显示的个数
const count = conf.showCount <= 0 ? arr.length : conf.showCount;
html = arr.splice(0, count).map(sel => {
const styleProps = { width: conf.showIcon ? 'calc(100% - 20px)' : '100%', }
const className = ['xm-label-block', sel[disabled] ? 'disabled':''].join(' ');
return (
<div class={className} style={ style }>
<span style={ styleProps }>{ sel[name] }</span>
{ conf.showIcon && <i class="xm-iconfont icon-close" onClick={ this.iconClick.bind(this, sel, true, sel[disabled]) }></i> }
</div>
)
})
//剩余没显示的数据
if(arr.length){
html.push(
<div class="xm-label-block" style={ style }>
+ { arr.length }
</div>
)
}
}else{
if(sels.length && conf && conf.template){
html = conf.template(data, sels);
}else{
html = sels.map(sel => sel[name]).join(',')
}
}
return (
<div class="xm-label">
{ html }
</div>
)
}
}
export default Label;

View File

@@ -0,0 +1,51 @@
import { h, Component, render } from '@/components/preact'
/**
* 普通的多选渲染
*/
class General extends Component{
constructor(options){
super(options);
}
optionClick(item, selected, disabled, e){
this.props.ck(item, selected, disabled);
//阻止父组件上的事件冒泡
e.stopPropagation();
}
render({ data, prop, template, theme, sels, empty }) {
const { name, value, disabled } = prop;
const arr = data.map(item => {
const selected = !!sels.find(sel => sel[value] == item[value])
const iconStyle = { color: selected ? theme.color : '' }
// const className = 'xm-option' + (item.disabled ? ' disabled' : '');
const className = ['xm-option', (item[disabled] ? ' disabled' : ''), (selected ? ' selected' : '')].join(' ');
return (
<div class={className} value={ item[value] } onClick={ this.optionClick.bind(this, item, selected, item[disabled]) }>
<div class="xm-option-icon" style={ { borderColor: theme.color, } }>
<i class="xm-iconfont icon-duox" style={ iconStyle }></i>
</div>
<div class='xm-option-content' dangerouslySetInnerHTML={{ __html: template(item, sels, item[name], item[value]) }}></div>
</div>
)
})
if(!data.length){
arr.push(
<div class="xm-select-empty">{ empty }</div>
)
}
return (
<div> { arr } </div>
)
}
}
export default General;

View File

@@ -0,0 +1,20 @@
import { h, Component, render } from '@/components/preact'
/**
* 默认提示
*/
class Tips extends Component{
constructor(options){
super(options);
}
render({ tips, show }) {
const tipsClass = show ? 'xm-tips' : 'xm-tips dis';
return (
<div class={ tipsClass }>{ tips }</div>
)
}
}
export default Tips;