新增fixed布局
This commit is contained in:
parent
b47c8cfcb9
commit
e928c6a038
18
CHANGELOG.md
18
CHANGELOG.md
@ -1,5 +1,23 @@
|
||||
## 更新日志
|
||||
|
||||
|
||||
### 1.2.2
|
||||
|
||||
*2021-01-19*
|
||||
|
||||
#### 新增
|
||||
|
||||
- 新增配置 `model.type: fixed`, 切换为`fixed`布局模式 [体验传送门](https://maplemei.gitee.io/xm-select/#/senior/table)
|
||||
- 新增实例方法`calcPosition`, fixed布局模式下重新计算位置
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
- 修改直接设置父节点无法选中的问题
|
||||
- 修改非严格模式下设置父节点, 子节点受影响
|
||||
- 修复渲染失败页面监听错误的问题
|
||||
- 修改数据重复时分组错乱的问题
|
||||
|
||||
|
||||
### 1.2.1
|
||||
|
||||
*2020-11-27*
|
||||
|
@ -96,7 +96,7 @@ const webpackConfig = {
|
||||
],
|
||||
devServer: {
|
||||
host: '0.0.0.0',
|
||||
port: 9000,
|
||||
port: 9001,
|
||||
publicPath: '/',
|
||||
hot: true
|
||||
},
|
||||
|
4
dist/static/2.js
vendored
4
dist/static/2.js
vendored
File diff suppressed because one or more lines are too long
4
dist/static/3.js
vendored
4
dist/static/3.js
vendored
File diff suppressed because one or more lines are too long
10
dist/static/docs.js
vendored
10
dist/static/docs.js
vendored
File diff suppressed because one or more lines are too long
4
dist/xm-select.js
vendored
4
dist/xm-select.js
vendored
File diff suppressed because one or more lines are too long
@ -38,6 +38,8 @@
|
||||
this.fixedControl = bottom > document.documentElement.clientHeight &&
|
||||
top + 44 <= document.documentElement.clientHeight;
|
||||
this.$refs.control.style.left = this.fixedControl ? `${ left }px` : '0';
|
||||
|
||||
xmSelect.get().forEach(xs => xs.calcPosition());
|
||||
},
|
||||
removeScrollHandler() {
|
||||
this.scrollParent && this.scrollParent.removeEventListener('scroll', this.scrollHandler);
|
||||
|
@ -48,7 +48,7 @@ layui.use('table', function() {
|
||||
//修改一些css样式, 这里虽然能够使用, 但是还是不太友好, 努力中...
|
||||
var cells = document.querySelectorAll('div[lay-id="demo"] .layui-table-cell');
|
||||
for(var i = 0 ; i < cells.length ; i++ ){
|
||||
cells[i].style.overflow = 'unset';
|
||||
//cells[i].style.overflow = 'unset';
|
||||
cells[i].style.height = 'auto';
|
||||
}
|
||||
//渲染多选
|
||||
@ -56,6 +56,7 @@ layui.use('table', function() {
|
||||
var xm = xmSelect.render({
|
||||
el: '#XM-' + item.id,
|
||||
autoRow: true,
|
||||
model: { type: 'fixed' },
|
||||
data: [
|
||||
{name: '张三', value: 1},
|
||||
{name: '李四', value: 2},
|
||||
@ -70,6 +71,13 @@ layui.use('table', function() {
|
||||
|
||||
});
|
||||
|
||||
//表格滚动时 重新计算位置
|
||||
document.querySelector('.layui-table-body').addEventListener('scroll', () => {
|
||||
xmSelect.get().forEach(function(item){
|
||||
item.calcPosition();
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
@ -5,45 +5,21 @@
|
||||
<div id="demo1" class="xm-select-demo"></div>
|
||||
|
||||
<script>
|
||||
var demo1 = xmSelect.render({
|
||||
xmSelect.render({
|
||||
el: '#demo1',
|
||||
autoRow: true,
|
||||
model: {
|
||||
label: {
|
||||
type: 'search'
|
||||
},
|
||||
},
|
||||
radio: true,
|
||||
filterable: true,
|
||||
tree: {
|
||||
show: true,
|
||||
showFolderIcon: true,
|
||||
showLine: true,
|
||||
indent: 20,
|
||||
expandedKeys: [ -3 ],
|
||||
simple: true,
|
||||
clickExpand: false,
|
||||
clickCheck: false,
|
||||
strict: false
|
||||
},
|
||||
toolbar: {
|
||||
show: true,
|
||||
list: ['ALL', 'REVERSE', 'CLEAR']
|
||||
},
|
||||
filterable: true,
|
||||
data(){
|
||||
return [
|
||||
{name: '销售员', value: -1, disabled: true, children: [
|
||||
{name: '张三1', value: 1, selected: true, children: []},
|
||||
{name: '李四1', value: 2, selected: true},
|
||||
{name: '王五1', value: 3, disabled: true},
|
||||
]},
|
||||
{name: '奖品', value: -2, disabled: true, children: [
|
||||
{name: '奖品3', value: -3, children: [
|
||||
{name: '苹果3', value: 14, selected: true},
|
||||
{name: '香蕉3', value: 15},
|
||||
{name: '葡萄3', value: 16},
|
||||
]},
|
||||
{name: '苹果2', value: 4, selected: true, disabled: true},
|
||||
{name: '香蕉2', value: 5},
|
||||
{name: '葡萄2', value: 6},
|
||||
]},
|
||||
]
|
||||
},
|
||||
data: [
|
||||
{name: '张三', value: 1, selected: true},
|
||||
{name: '李四', value: 2},
|
||||
{name: '王五', value: 3},
|
||||
]
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
@ -134,7 +134,7 @@ model: {
|
||||
}
|
||||
},
|
||||
},
|
||||
//展示类型, 下拉框形式: absolute, 直接显示模式: relative
|
||||
//展示类型, 下拉框形式: absolute, 直接显示模式: relative, 浮动布局: fixed
|
||||
type: 'absolute',
|
||||
},
|
||||
```
|
||||
@ -258,3 +258,4 @@ xmSelect.render()后会返回一个xmSelect对象, 可以进行方法调用
|
||||
| changeExpandedKeys | 树模式下更新节点展开状态, v1.2.0 新增 | (keys: true-全部展开, false-全部关闭, 数组-展开的节点值) |
|
||||
| enable | 启用选项, disabled=false, v1.2.0 新增 | (array: 想要启用的选项数组) |
|
||||
| disable | 禁用用选项, disabled=true, v1.2.0 新增 | (array: 想要禁用的选项数组) |
|
||||
| calcPosition | fixed布局模式下重新计算位置, v1.2.2 新增 | - |
|
||||
|
@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "xm-select",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"description": "始于Layui的select多选解决方案",
|
||||
"website": "https://maplemei.gitee.io/xm-select",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"dev": "cross-env NODE_ENV=dev node_modules/.bin/webpack-dev-server --config build/webpack.config.js",
|
||||
|
@ -31,11 +31,12 @@ class Framework extends Component{
|
||||
show: false,
|
||||
tmpColor: '',
|
||||
bodyClass: '',
|
||||
time: 0,
|
||||
}
|
||||
}
|
||||
|
||||
init(props, refresh){
|
||||
let { data, prop, initValue, radio } = props, sels;
|
||||
let { data, prop, initValue, radio, tree, cascader } = props, sels;
|
||||
//如果新数据和旧数据不同 或者 强制刷新 才进行数据处理
|
||||
if(refresh){
|
||||
let dataObj = {};
|
||||
@ -47,6 +48,9 @@ class Framework extends Component{
|
||||
}), dataObj)
|
||||
if(radio && sels.length > 1){
|
||||
sels = sels.slice(0, 1)
|
||||
if(tree.show && tree.strict || cascader.show && cascader.strict){
|
||||
this.clearAndReset(data, sels, false);
|
||||
}
|
||||
}
|
||||
this.setState({ sels, dataObj, flatData });
|
||||
}
|
||||
@ -139,14 +143,23 @@ class Framework extends Component{
|
||||
}
|
||||
|
||||
clearAndReset(data, changeData, parentCK){
|
||||
const { selected, children, value } = this.props.prop;
|
||||
const { selected, disabled, children, value } = this.props.prop;
|
||||
data.forEach(item => {
|
||||
item[selected] = changeData.findIndex(c => c[value] === item[value]) != -1 || parentCK;
|
||||
let child = item[children];
|
||||
child && isArray(child) && this.clearAndReset(child, changeData, item[selected])
|
||||
if(child && isArray(child)){
|
||||
this.clearAndReset(child, changeData, item[selected])
|
||||
let len = child.length;
|
||||
let slen = child.filter(i => i[selected] === true || i.__node.selected === true).length;
|
||||
item.__node.selected = slen === len;
|
||||
item.__node.half = slen > 0 && slen < len || child.filter(i => i.__node.half === true).length > 0;
|
||||
item.__node.disabled = child.filter(i => i[disabled] === true || i.__node.disabled === true).length === len;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
load(data, dataObj, flatData, parent, level = 0, initValue){
|
||||
const { prop, tree, cascader } = this.props;
|
||||
const { children, optgroup, value, selected, disabled } = prop;
|
||||
@ -252,7 +265,7 @@ class Framework extends Component{
|
||||
//选项, 选中状态, 禁用状态, 是否强制删除:在label上点击删除
|
||||
itemClick(item, itemSelected, itemDisabled, mandatoryDelete){
|
||||
|
||||
const { theme, prop, radio, repeat, clickClose, max, maxMethod, tree } = this.props
|
||||
const { theme, prop, radio, repeat, clickClose, max, maxMethod, tree, data } = this.props
|
||||
let sels = [ ...this.state.sels ]
|
||||
const { value, selected, disabled, children, optgroup } = prop
|
||||
|
||||
@ -308,6 +321,7 @@ class Framework extends Component{
|
||||
}else{
|
||||
sels = [...sels, item]
|
||||
}
|
||||
this.clearAndReset(data, sels, itemSelected)
|
||||
this.resetSelectValue(sels, [item], !itemSelected);
|
||||
}
|
||||
}
|
||||
@ -439,6 +453,20 @@ class Framework extends Component{
|
||||
}
|
||||
}
|
||||
|
||||
calcPosition(){
|
||||
if(this.state.show && this.props.model.type === 'fixed'){
|
||||
let rect = this.base.getBoundingClientRect();
|
||||
(Date.now() - this.state.time > 10) && this.setState({ time: Date.now() })
|
||||
return {
|
||||
position: 'fixed',
|
||||
left: rect.x,
|
||||
top: rect.y + rect.height + 4,
|
||||
width: rect.width,
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
//组件将要接收新属性
|
||||
componentWillReceiveProps(props){
|
||||
this.init(props, props.updateData);
|
||||
@ -482,6 +510,7 @@ class Framework extends Component{
|
||||
|
||||
//渲染组件
|
||||
let Body = content ? <Custom { ...bodyProps } /> : tree.show ? <Tree { ...bodyProps } ref={ ref => this.treeRef = ref } /> : config.cascader.show ? <Cascader { ...bodyProps } /> : <General { ...bodyProps } ref={ ref => this.generalRef = ref } />;
|
||||
let bodyStyle = this.calcPosition();
|
||||
|
||||
return (
|
||||
<xm-select { ...xmSelectProps } >
|
||||
@ -495,7 +524,7 @@ class Framework extends Component{
|
||||
<i class={ show ? 'xm-icon xm-icon-expand' : 'xm-icon' } />
|
||||
{ sels.length === 0 && <div class="xm-tips">{ config.tips }</div> }
|
||||
<Label { ...labelProps } ref={ ref => this.labelRef = ref } />
|
||||
<div class={ ['xm-body', bodyClass, config.model.type, show ? '':'dis', ].join(' ') } ref={ ref => this.bodyView = ref}>
|
||||
<div class={ ['xm-body', bodyClass, config.model.type, show ? '':'dis', ].join(' ') } style={ bodyStyle } ref={ ref => this.bodyView = ref}>
|
||||
{ Body }
|
||||
</div>
|
||||
{ disabled && <div class="xm-select-disabled"></div> }
|
||||
@ -558,6 +587,10 @@ class Framework extends Component{
|
||||
return ;
|
||||
}
|
||||
|
||||
if(model.type === 'fixed'){
|
||||
return ;
|
||||
}
|
||||
|
||||
let rect = this.base.getBoundingClientRect();
|
||||
if(direction === 'auto'){
|
||||
//用于控制js获取下拉框的高度
|
||||
|
@ -104,7 +104,10 @@ class Label extends Component{
|
||||
}
|
||||
}else if(type == 'search'){
|
||||
innerHTML = false;
|
||||
let one = list[0][name];
|
||||
let one = '';
|
||||
if(list.length){
|
||||
one = list[0][name]
|
||||
}
|
||||
|
||||
html = (
|
||||
<input class="label-search-input" type="text" placeholder={ config.searchTips } style={{ width: '100%', border: 'none' }} value={
|
||||
|
@ -286,8 +286,9 @@ class General extends Component{
|
||||
|
||||
//如果是分组模式, 要分页先去除分组, 然后在计算分页, 最后再加上分组
|
||||
let groupInfo = {};
|
||||
arr.filter(item => item[optgroup]).forEach(g => {
|
||||
g[children].forEach(item => groupInfo[item[value]] = g);
|
||||
arr.filter(item => item[optgroup]).forEach((g, groupIndex) => {
|
||||
groupInfo[groupIndex] = g;
|
||||
g[children].forEach(item => item.__group__index = groupIndex);
|
||||
});
|
||||
arr = arr.filter(item => !item[optgroup]);
|
||||
|
||||
@ -342,7 +343,8 @@ class General extends Component{
|
||||
let newArr = [], group, tmpGroup = { __tmp: true };
|
||||
tmpGroup[optgroup] = true;
|
||||
arr.forEach(item => {
|
||||
let g = groupInfo[item[value]];
|
||||
let g = groupInfo[item.__group__index];
|
||||
delete item.__group__index;
|
||||
if(group && !g){
|
||||
g = tmpGroup
|
||||
}
|
||||
|
@ -262,6 +262,14 @@ class xmOptions {
|
||||
let opt = this.options.dom.querySelector(`.xm-option[value="${ val }"]`);
|
||||
opt && opt.scrollIntoView(false)
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新计算下拉的位置
|
||||
*/
|
||||
calcPosition(){
|
||||
childData[this.options.el].calcPosition()
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ export default function (lan = 'zn') {
|
||||
},
|
||||
},
|
||||
icon: 'show',
|
||||
type: 'absolute',
|
||||
type: 'absolute',//可选值, relative, fixed
|
||||
},
|
||||
//自定义选中的图标
|
||||
iconfont: {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { name, version } from '../package.json'
|
||||
import { name, version, website } from '../package.json'
|
||||
import { selector, warn } from '@/common/util'
|
||||
import Select from '@/components/xm-select'
|
||||
|
||||
@ -9,6 +9,7 @@ export const childData = {};
|
||||
export default {
|
||||
name,
|
||||
version,
|
||||
doc: website,
|
||||
render(options) {
|
||||
let { el } = options;
|
||||
options.dom = selector(el);
|
||||
@ -20,10 +21,10 @@ export default {
|
||||
options.el = el;
|
||||
}
|
||||
optionData[el] = options;
|
||||
|
||||
|
||||
let instance = new Select(options);
|
||||
//已经渲染
|
||||
if (instance && instance.__render_success) {
|
||||
if (instance && instance.options.__render_success) {
|
||||
datas[el] = instance;
|
||||
}
|
||||
return instance;
|
||||
|
10
src/main.js
10
src/main.js
@ -14,6 +14,16 @@ window.addEventListener('click', () => {
|
||||
item && item.closed && item.closed()
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* 监听页面滚动事件
|
||||
*/
|
||||
window.addEventListener('scroll', () => {
|
||||
Object.keys(datas).forEach(key => {
|
||||
let item = datas[key]
|
||||
item && item.calcPosition && item.calcPosition()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
|
||||
|
@ -109,11 +109,13 @@ xm-select{
|
||||
}
|
||||
.label-content{
|
||||
flex-wrap: nowrap;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
&.auto-row{
|
||||
.label-content{
|
||||
flex-wrap: wrap;
|
||||
padding-right: 30px !important;
|
||||
}
|
||||
.xm-label-block > span{
|
||||
white-space: unset;
|
||||
@ -124,7 +126,7 @@ xm-select{
|
||||
.scroll{
|
||||
.label-content{
|
||||
display: flex;
|
||||
padding: 3px 30px 3px 10px;
|
||||
padding: 3px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user