This commit is contained in:
maplemei 2019-11-25 15:17:08 +08:00
parent 57a0ab9f15
commit 3fcd41969c
12 changed files with 187 additions and 17 deletions

View File

@ -1,7 +1,39 @@
## 更新日志 ## 更新日志
### 1.1.0
*2019-11-25*
- 经过了将近一周的测试, 树形结构也趋向于完善阶段, 当然现有的功能并不能满足所有的需求, xm-select将会继续前行
#### 新增
- 树形组件
- 懒加载
- 严格/非严格父子结构
- 搜索模式
- 新增参数`layVerify`和`layVerType`, 用于表单验证
- `el`配置可以指定dom对象
- 解决`on`监听时无法使用`setValue`, 增加return处理
- 新增远程分页配置`pageRemote`
- label也可以自定义渲染
- label新增title提示
#### 调整
- 移除分组中的optgroup模式
- 调整代码文件夹结构
- 调整preact版本
### 1.1.0.Beta ### 1.1.0.Beta
#### 2019-11-25
#### 新增
- 树形组件
- [新增]搜索模式
#### 2019-11-23 #### 2019-11-23
#### 新增 #### 新增

2
dist/static/2.js vendored

File diff suppressed because one or more lines are too long

2
dist/static/3.js vendored

File diff suppressed because one or more lines are too long

4
dist/static/docs.js vendored

File diff suppressed because one or more lines are too long

2
dist/xm-select.js vendored

File diff suppressed because one or more lines are too long

View File

@ -68,11 +68,14 @@ button, input, select, textarea {
font-family: Menlo, Monaco, Consolas, Courier, monospace; font-family: Menlo, Monaco, Consolas, Courier, monospace;
font-size: 12px; font-size: 12px;
padding: 18px 24px; padding: 18px 24px;
background-color: #fafafa; // background-color: #fafafa;
border: solid 1px #eaeefb; border: solid 1px #eaeefb;
margin-bottom: 25px; margin-bottom: 25px;
border-radius: 4px; border-radius: 4px;
-webkit-font-smoothing: auto; -webkit-font-smoothing: auto;
.hljs-tag{
white-space: nowrap;
}
} }
.main-cnt { .main-cnt {
@ -261,3 +264,7 @@ button, input, select, textarea {
overflow: hidden; overflow: hidden;
} }
} }
.tool_bar{
display: none;
}

View File

@ -1,9 +1,12 @@
import "babel-polyfill" import "babel-polyfill"
import Vue from 'vue'; import Vue from 'vue';
import ElementUI from 'element-ui'; import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css'; import 'element-ui/lib/theme-chalk/index.css';
import hljs from 'highlight.js'; import hljs from 'highlight.js';
import 'highlight.js/styles/color-brewer.css' // import 'highlight.js/styles/color-brewer.css'
import 'highlight.js/styles/monokai-sublime.css'
import VueRouter from 'vue-router'; import VueRouter from 'vue-router';
import routes from './router'; import routes from './router';
import App from './App.vue'; import App from './App.vue';

View File

@ -71,6 +71,7 @@ layui.slider.render({
var demo1 = xmSelect.render({ var demo1 = xmSelect.render({
el: '#demo1', el: '#demo1',
autoRow: true, autoRow: true,
filterable: true,
tree: { tree: {
show: true, show: true,
showFolderIcon: true, showFolderIcon: true,
@ -78,6 +79,7 @@ var demo1 = xmSelect.render({
indent: 20, indent: 20,
expandedKeys: [ -3 ], expandedKeys: [ -3 ],
}, },
filterable: true,
height: 'auto', height: 'auto',
data(){ data(){
return [ return [

View File

@ -8,7 +8,9 @@
var demo1 = xmSelect.render({ var demo1 = xmSelect.render({
el: '#demo1', el: '#demo1',
autoRow: true, autoRow: true,
filterable: true,
tree: { tree: {
strict: false,
show: true, show: true,
showFolderIcon: true, showFolderIcon: true,
showLine: true, showLine: true,

View File

@ -20,7 +20,6 @@ class General extends Component{
this.searchCid = 0; this.searchCid = 0;
this.inputOver = true; this.inputOver = true;
this.__value = ''; this.__value = '';
this.dynamicInput = false;
} }
optionClick(item, selected, disabled, e){ optionClick(item, selected, disabled, e){

View File

@ -7,7 +7,12 @@ class Tree extends Component{
this.state = { this.state = {
expandedKeys: [], expandedKeys: [],
filterValue: '',
} }
this.searchCid = 0;
this.inputOver = true;
this.__value = '';
} }
init(props){ init(props){
@ -34,10 +39,18 @@ class Tree extends Component{
optionClick(item, selected, disabled, type, e){ optionClick(item, selected, disabled, type, e){
if(type === 'line'){ if(type === 'line'){
//加载中的不需要进行处理
if(item.__node.loading === true){ if(item.__node.loading === true){
return; return;
} }
const { tree, prop, sels } = this.props;
//不是父节点的不需要处理
if(!tree.lazy && !item[prop.optgroup]){
return
}
let val = item[this.props.prop.value]; let val = item[this.props.prop.value];
let expandedKeys = this.state.expandedKeys; let expandedKeys = this.state.expandedKeys;
let index = expandedKeys.findIndex(v => v === val); let index = expandedKeys.findIndex(v => v === val);
@ -45,13 +58,12 @@ class Tree extends Component{
this.setState({ expandedKeys }); this.setState({ expandedKeys });
//是否需要懒加载 //是否需要懒加载
const { tree, prop, sels } = this.props;
let child = item[prop.children]; let child = item[prop.children];
if(tree.lazy && child && child.length === 0 && item.__node.loading !== false){ if(tree.lazy && child && child.length === 0 && item.__node.loading !== false){
item.__node.loading = true; item.__node.loading = true;
tree.load(item, (result) => { tree.load(item, (result) => {
item.__node.loading = false; item.__node.loading = false;
item[prop.children] = result; item[prop.children] = this.handlerData(result, prop.children);
item[prop.selected] = sels.findIndex(i => i[prop.value] === item[prop.value]) != -1 item[prop.selected] = sels.findIndex(i => i[prop.value] === item[prop.value]) != -1
this.props.onReset(item, 'treeData'); this.props.onReset(item, 'treeData');
}); });
@ -63,9 +75,93 @@ class Tree extends Component{
this.blockClick(e); this.blockClick(e);
} }
handlerData(data, children){
return data.map(item => {
item.__node = {};
if(item[children]){
item[children] = this.handlerData(item[children], children);
}
return item;
})
}
searchInput(e){
let v = e.target.value;
if(v === this.__value){
return ;
}
clearTimeout(this.searchCid);
if(this.inputOver){
//保证输入框内的值是实时的
this.__value = v;
//让搜索变成异步的
this.searchCid = setTimeout(() => {
this.callback = true;
this.setState({ filterValue: this.__value })
}, this.props.delay);
}
}
focus(){
this.searchInputRef && this.searchInputRef.focus();
}
blur(){
this.searchInputRef && this.searchInputRef.blur();
}
handleComposition(e){
let type = e.type;
if(type === 'compositionstart'){
this.inputOver = false;
clearTimeout(this.searchCid);
}else if(type === 'compositionend'){
this.inputOver = true;
this.searchInput(e);
}
}
filterData(data, val){
const { prop, filterMethod, tree } = this.props;
const { children, optgroup, name, value } = prop;
data.forEach((item, index) => {
if(item[optgroup]){
let child = this.filterData(item[children], val);
item.__node.hidn = val ? child.filter(c => !c.__node.hidn).length === 0 : false;
if(!item.__node.hidn){
let keys = this.state.expandedKeys;
if(val && keys.findIndex(key => key === item[value]) === -1){
keys.push(item[value]);
this.setState({ expandedKeys: keys })
}
return
}
if(tree.strict){
return
}
}
item.__node.hidn = val ? !filterMethod(val, item, index, prop) : false;
});
return data;
}
//组件将要接收新属性 //组件将要接收新属性
componentWillReceiveProps(props){ componentWillReceiveProps(props){
// this.init(props); if(this.props.show != props.show){
if(!props.show){
//清空输入框的值
this.setState({ filterValue: '' });
this.__value = '';
this.searchInputRef && (this.searchInputRef.value = '');
}else{
//聚焦输入框
setTimeout(() => this.focus(), 0);
}
}
} }
//组件将要被挂载 //组件将要被挂载
@ -74,7 +170,7 @@ class Tree extends Component{
} }
render(config, { expandedKeys }) { render(config, { expandedKeys }) {
let { prop, empty, sels, theme, radio, template, data, tree } = config; let { prop, empty, sels, theme, radio, template, data, tree, filterable, searchTips } = config;
let { name, value, disabled, children } = prop; let { name, value, disabled, children } = prop;
const showIcon = config.model.icon != 'hidden'; const showIcon = config.model.icon != 'hidden';
@ -120,6 +216,10 @@ class Tree extends Component{
} }
const renderGroup = (item, indent) => { const renderGroup = (item, indent) => {
if(item.__node.hidn){
return;
}
const child = item[children]; const child = item[children];
indent = indent + tree.indent indent = indent + tree.indent
if(child){//分组模式 if(child){//分组模式
@ -136,19 +236,45 @@ class Tree extends Component{
return renderItem(item, indent, 0); return renderItem(item, indent, 0);
} }
let arr = data.map(item => renderGroup(item, 10 - tree.indent)); //这里处理过滤数据
if(filterable){
this.filterData(data, this.state.filterValue);
}
let arr = data.map(item => renderGroup(item, 10 - tree.indent)).filter(a => a);
if(!arr.length){ if(!arr.length){
//查看无数据情况下是否显示分页 //查看无数据情况下是否显示分页
arr.push(<div class="xm-select-empty">{ empty }</div>) arr.push(<div class="xm-select-empty">{ empty }</div>)
} }
const search = (
<div class='xm-search'>
<i class="xm-iconfont xm-icon-sousuo"></i>
<input class="xm-input xm-search-input" placeholder={ searchTips } />
</div>
);
return ( return (
<div onClick={ this.blockClick } class="xm-body-tree" > <div onClick={ this.blockClick } class="xm-body-tree" >
{ filterable && search }
<div class="scroll-body" style={ {maxHeight: config.height} }>{ arr }</div> <div class="scroll-body" style={ {maxHeight: config.height} }>{ arr }</div>
</div> </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;
}
}
} }
export default Tree; export default Tree;

View File

@ -3,7 +3,7 @@ import { datas, optionData, childData } from '@/index.js';
import { selector, warn, listenerClose, isArray, deepMerge, exchangeOptionsData } from '@/common/util' import { selector, warn, listenerClose, isArray, deepMerge, exchangeOptionsData } from '@/common/util'
import Framework from '@/components/framework' import Framework from '@/components/framework'
import defaultOptions from '@/config/options' import defaultOptions from '@/config/options'
class xmOptions { class xmOptions {
constructor(options) { constructor(options) {
@ -156,7 +156,6 @@ class xmOptions {
return this; return this;
} }
} }
export default xmOptions; export default xmOptions;