This commit is contained in:
maplemei 2019-11-19 20:13:50 +08:00
parent e02db53b89
commit 1e9d58f0e6
93 changed files with 8300 additions and 8236 deletions

View File

@ -1,5 +1,5 @@
{
"plugins": [
["transform-react-jsx", { "pragma":"h" }]
]
{
"plugins": [
["transform-react-jsx", { "pragma":"h" }]
]
}

View File

@ -1,16 +1,16 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab
# http://editorconfig.org
root = true
[*]
indent_style = tab
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab

View File

@ -1,13 +1,13 @@
### 该问题是怎么引起的?
### 重现步骤
### 报错信息
### 该问题是怎么引起的?
### 重现步骤
### 报错信息

View File

@ -1,15 +1,15 @@
### 相关的Issue
### 原因(目的、解决的问题等)
### 描述(做了什么,变更了什么)
### 测试用例
### 相关的Issue
### 原因(目的、解决的问题等)
### 描述(做了什么,变更了什么)
### 测试用例

4
.gitignore vendored
View File

@ -1,3 +1,3 @@
.DS_Store
node_modules/*
.DS_Store
node_modules/*
yarn.lock

View File

@ -1,203 +1,220 @@
## 更新日志
### 1.0.13
*2019-11-07*
#### 新增
- `get`方法新增`single`参数, 可以获取单实例
#### Bug fixes
- 修复`reset`方法报错
- 修复IE下工具条全选数据错误
- 修改文档简单兼容IE
### 1.0.12
*2019-10-24*
#### 新增
- 新增配置`pageEmptyShow`, 调整分页+搜索模式下, 如果无数据是否展示分页
- 新增`create`创建条目时的回调参数`data`, 当前下拉的数据
- 工具条新增反选`REVERSE`
#### Bug fixes
- 修复`create`创建条目时, 工具条不能操作的创建条目的问题
- 修复`create`创建条目时, 分页页码显示异常的问题
- 修复`create`创建条目时, 搜索不存在的回调逻辑
- 修复多语言下工具条一直显示中文的问题
- 调整分页模式下无数据显示页码 0 -> 1
### 1.0.11
*2019-10-23*
#### 新增
- 新增`disabled`配置, 可以禁用多选
- 新增`create`配置, 可以创建条目, 具体见 [创建条目](https://maplemei.gitee.io/xm-select/#/example/XM27)
- 方法`warning`新增参数`sustain`, 可以配置是否持续显示
- 新增全局`get`方法, 可以获取多选渲染后的对象
- 新增全局`batch`方法, 可以批量给渲染后的多选执行方法
#### Bug fixes
- 修复`update`方法, 会使已选中数据丢失的问题
- 修复`Safari`浏览器下, 搜索框无法聚焦的问题
### 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*
#### 新增
- 新增`size`尺寸设置, `large`, `medium`, `small`, `mini`
- 新增`warning`方法, 可以闪烁边框提示
- 新增搜索完成回调参数, `list`:当前过滤后的数据
#### Bug fixes
- 修复远程搜索模式下 搜索完成回调错误
### 1.0.8
*2019-10-16*
#### 兼容提示
- 此版本的on方法结构调整, 升级请注意
#### 新增
- 新增分组单击事件 click, 可选值 `SELECT`, `CLEAR`, `AUTO`, `自定义`
- 新增`append`方法追加赋值, `delete`方法删除赋值
- 新增搜索完成回调`filterDone`
#### Bug fixes
- 修复全选和请空不走on监听的问题
- 修复`autoRow`模式下, 无选项时的css样式错误
- 修复`update`后, 下拉框显示状态被重置为隐藏
- 优化`setValue`方法, 可自行判断下拉框的显示状态
- 修复文档错误, 实例没有`render`方法
### 1.0.7
*2019-10-16*
#### 新增
- 新增`autoRow`配置, 可以开启自动换行
- 新增是否显示icon配置, 隐藏图标后将变换背景色显示
### 1.0.6
*2019-10-14*
#### 新增
- 新增`showCount`配置, 可以控制选项的数量, 提高渲染性能
- 新增分组模式, 可以在选项中使用`optgroup`或`children`来开启, 分组时不建议开启分页模式
- 远程搜索中新增`show`参数, 可以查看当前下拉框是否显示
#### Bug fixes
- 修复工具条中`全选`和`清空`还可以操作禁用选项的问题
- 修复远程搜索中`selected`不回显的问题
### 1.0.5
*2019-10-10*
#### Bug fixes
- 修复本地搜索模式下多次重复触发过滤方法, 优化搜索性能
- 修复选项过多时, 可以使用鼠标进行横向滚动
### 1.0.4
*2019-09-27*
#### 新增
- 新增多选上限设置, 可以设置多选选中上限
- 新增工具条, 可以全选, 清空, 自定义
- 新增name设置, 可以表单提交, 隐藏input实现, 值为value逗号分隔
- 新增getValue参数, 可以获取不同类型的值
#### Bug fixes
- 修复搜索模式下输入中文不显示的问题
- 修改render不能及时渲染, 需要二次渲染的问题
- 修改IE下输入循环触发input事件的问题, IE 慎入
### 1.0.3
*2019-09-25*
#### Bug fixes
- 借鉴[ElementUI](https://element.eleme.cn/#/zh-CN)的文档编写方式, 重新编辑使用文档
- 修改on监听时已选中数据不对的问题
- 修改显示模式也支持html方式
- 存在layui时, 同样也能直接使用xmSelect, 不用必须layui.xmSelect
### 1.0.2
*2019-09-23*
#### Bug fixes
- 搜索时输入中文延迟后才进行回显
- 远程搜索时, loading状态也能进行输入的问题
- 单选模式下, 前面的图标变成圆形
- 修正Windows下的一些样式错乱, 兼容IE10以上
- 启动分页, 当搜索时, 如果搜索总页码为0, 再次搜索有页码时, 当前页面为0的问题
- 当底部空间不足时, 再次判断顶部空间是否充足, 优化展开方向
### 1.0.1
*2019-09-22*
#### 新增
- 物理分页配置
- 自定义搜索模式(远程搜索)
- 下拉选高度配置
#### Bug fixes
- 调整布局为flex布局
- 展开下拉选时, 自动聚焦搜索框
### 1.1.0.Beta
*2019-11-19*
- 历时半个月, 也算是一次大的版本更新, 此版本仅为测试版本, 升级需谨慎
#### 新增
- 树形组件
#### 调整
- 移除分组中的optgroup模式
- 调整代码文件夹结构
- 调整preact版本
### 1.0.13
*2019-11-07*
#### 新增
- `get`方法新增`single`参数, 可以获取单实例
#### Bug fixes
- 修复`reset`方法报错
- 修复IE下工具条全选数据错误
- 修改文档简单兼容IE
### 1.0.12
*2019-10-24*
#### 新增
- 新增配置`pageEmptyShow`, 调整分页+搜索模式下, 如果无数据是否展示分页
- 新增`create`创建条目时的回调参数`data`, 当前下拉的数据
- 工具条新增反选`REVERSE`
#### Bug fixes
- 修复`create`创建条目时, 工具条不能操作的创建条目的问题
- 修复`create`创建条目时, 分页页码显示异常的问题
- 修复`create`创建条目时, 搜索不存在的回调逻辑
- 修复多语言下工具条一直显示中文的问题
- 调整分页模式下无数据显示页码 0 -> 1
### 1.0.11
*2019-10-23*
#### 新增
- 新增`disabled`配置, 可以禁用多选
- 新增`create`配置, 可以创建条目, 具体见 [创建条目](https://maplemei.gitee.io/xm-select/#/example/XM27)
- 方法`warning`新增参数`sustain`, 可以配置是否持续显示
- 新增全局`get`方法, 可以获取多选渲染后的对象
- 新增全局`batch`方法, 可以批量给渲染后的多选执行方法
#### Bug fixes
- 修复`update`方法, 会使已选中数据丢失的问题
- 修复`Safari`浏览器下, 搜索框无法聚焦的问题
### 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*
#### 新增
- 新增`size`尺寸设置, `large`, `medium`, `small`, `mini`
- 新增`warning`方法, 可以闪烁边框提示
- 新增搜索完成回调参数, `list`:当前过滤后的数据
#### Bug fixes
- 修复远程搜索模式下 搜索完成回调错误
### 1.0.8
*2019-10-16*
#### 兼容提示
- 此版本的on方法结构调整, 升级请注意
#### 新增
- 新增分组单击事件 click, 可选值 `SELECT`, `CLEAR`, `AUTO`, `自定义`
- 新增`append`方法追加赋值, `delete`方法删除赋值
- 新增搜索完成回调`filterDone`
#### Bug fixes
- 修复全选和请空不走on监听的问题
- 修复`autoRow`模式下, 无选项时的css样式错误
- 修复`update`后, 下拉框显示状态被重置为隐藏
- 优化`setValue`方法, 可自行判断下拉框的显示状态
- 修复文档错误, 实例没有`render`方法
### 1.0.7
*2019-10-16*
#### 新增
- 新增`autoRow`配置, 可以开启自动换行
- 新增是否显示icon配置, 隐藏图标后将变换背景色显示
### 1.0.6
*2019-10-14*
#### 新增
- 新增`showCount`配置, 可以控制选项的数量, 提高渲染性能
- 新增分组模式, 可以在选项中使用`optgroup`或`children`来开启, 分组时不建议开启分页模式
- 远程搜索中新增`show`参数, 可以查看当前下拉框是否显示
#### Bug fixes
- 修复工具条中`全选`和`清空`还可以操作禁用选项的问题
- 修复远程搜索中`selected`不回显的问题
### 1.0.5
*2019-10-10*
#### Bug fixes
- 修复本地搜索模式下多次重复触发过滤方法, 优化搜索性能
- 修复选项过多时, 可以使用鼠标进行横向滚动
### 1.0.4
*2019-09-27*
#### 新增
- 新增多选上限设置, 可以设置多选选中上限
- 新增工具条, 可以全选, 清空, 自定义
- 新增name设置, 可以表单提交, 隐藏input实现, 值为value逗号分隔
- 新增getValue参数, 可以获取不同类型的值
#### Bug fixes
- 修复搜索模式下输入中文不显示的问题
- 修改render不能及时渲染, 需要二次渲染的问题
- 修改IE下输入循环触发input事件的问题, IE 慎入
### 1.0.3
*2019-09-25*
#### Bug fixes
- 借鉴[ElementUI](https://element.eleme.cn/#/zh-CN)的文档编写方式, 重新编辑使用文档
- 修改on监听时已选中数据不对的问题
- 修改显示模式也支持html方式
- 存在layui时, 同样也能直接使用xmSelect, 不用必须layui.xmSelect
### 1.0.2
*2019-09-23*
#### Bug fixes
- 搜索时输入中文延迟后才进行回显
- 远程搜索时, loading状态也能进行输入的问题
- 单选模式下, 前面的图标变成圆形
- 修正Windows下的一些样式错乱, 兼容IE10以上
- 启动分页, 当搜索时, 如果搜索总页码为0, 再次搜索有页码时, 当前页面为0的问题
- 当底部空间不足时, 再次判断顶部空间是否充足, 优化展开方向
### 1.0.1
*2019-09-22*
#### 新增
- 物理分页配置
- 自定义搜索模式(远程搜索)
- 下拉选高度配置
#### Bug fixes
- 调整布局为flex布局
- 展开下拉选时, 自动聚焦搜索框

402
LICENSE
View File

@ -1,201 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [2019] [maplemei@aliyun.com]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [2019] [maplemei@aliyun.com]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -3,13 +3,26 @@
#### 介绍
始于Layui, 下拉选择框的多选解决方案
前身`formSelectes`, 移除了对`jquery`的依赖, 提高渲染速度
前身[前往formSelectes](https://github.com/hnzzmsf/layui-formSelects), 由于渲染速度慢, 代码冗余, 被放弃了
`xm-select`使用了新的开发方式, 利用preact进行渲染, 大幅度提高渲染速度, 并且可以灵活拓展
[xm-select演示站点](https://maplemei.gitee.io/xm-select/)
> 历史版本
> 支持功能
[前往formSelectes](https://github.com/hnzzmsf/layui-formSelects)
- [x] 国际化 - 中文/英文
- [x] 多选
- [x] 单选
- [x] 重复选
- [x] 分组
- [x] 工具条
- [x] 创建条目
- [x] 显示模式
- [x] 搜索模式 (本地数据过滤, 远程搜索)
- [x] 分页模式
- [x] 下拉树
- [x] 下拉任意 - 可以自己写html
> 联系方式
@ -94,3 +107,33 @@ QQ群: 660408068
// ...
</script>
```
#### 相关
> 支持IE吗
简单适配IE10以上的版本, 如有其它兼容性问题, 请加群反馈
> 为什么没有css文件
已经内置到js代码中了, 直接引入`xm-select.js`即可使用
> 开源 != 无私
有问题请自己多动手尝试^_^
> 成长之路
```
maplemei, 一个90后, 热爱前端的程序猿
16年接触了 贤心大大 的 layui, 开始走向了前端的不归之路
17年尝试自己写了一个基于layui的省市区联动插件, 同年底开发了layui select多选第一版
18年6月发布了formSelects
19年6月发布了xm-select
其实每个版本的更新都是自己对前端的一个新的认知, 也是一个新的学习之路
目前作者几乎不怎么使用layui, 已经走向了vue, react的新途 , xm-select的维护是对layui的一种情怀 ^_^
```

View File

@ -1,24 +1,24 @@
const mdContainer = require('markdown-it-container');
module.exports = md => {
md.use(mdContainer, 'demo', {
validate(params) {
return params.trim().match(/^demo\s*(.*)$/);
},
render(tokens, idx) {
const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/);
if (tokens[idx].nesting === 1) {
const description = m && m.length > 1 ? m[1] : '';
const content = tokens[idx + 1].type === 'fence' ? tokens[idx + 1].content : '';
return `<demo-block>
${description ? `<div>${md.render(description)}</div>` : ''}
<!--element-demo: ${content}:element-demo-->
`;
}
return '</demo-block>';
}
});
md.use(mdContainer, 'tip');
md.use(mdContainer, 'warning');
};
const mdContainer = require('markdown-it-container');
module.exports = md => {
md.use(mdContainer, 'demo', {
validate(params) {
return params.trim().match(/^demo\s*(.*)$/);
},
render(tokens, idx) {
const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/);
if (tokens[idx].nesting === 1) {
const description = m && m.length > 1 ? m[1] : '';
const content = tokens[idx + 1].type === 'fence' ? tokens[idx + 1].content : '';
return `<demo-block>
${description ? `<div>${md.render(description)}</div>` : ''}
<!--element-demo: ${content}:element-demo-->
`;
}
return '</demo-block>';
}
});
md.use(mdContainer, 'tip');
md.use(mdContainer, 'warning');
};

View File

@ -1,67 +1,67 @@
const {
stripScript,
stripTemplate,
genInlineComponentText
} = require('./util');
const md = require('./config');
module.exports = function(source) {
const content = md.render(source);
const startTag = '<!--element-demo:';
const startTagLen = startTag.length;
const endTag = ':element-demo-->';
const endTagLen = endTag.length;
let componenetsString = '';
let id = 0; // demo 的 id
let output = []; // 输出的内容
let start = 0; // 字符串开始位置
let commentStart = content.indexOf(startTag);
let commentEnd = content.indexOf(endTag, commentStart + startTagLen);
while (commentStart !== -1 && commentEnd !== -1) {
output.push(content.slice(start, commentStart));
const commentContent = content.slice(commentStart + startTagLen, commentEnd);
const html = stripTemplate(commentContent);
const script = stripScript(commentContent);
let demoComponentContent = genInlineComponentText(html, script);
const demoComponentName = `element-demo${id}`;
output.push(`<template slot="source"><${demoComponentName} /></template>`);
componenetsString += `${JSON.stringify(demoComponentName)}: ${demoComponentContent},`;
// 重新计算下一次的位置
id++;
start = commentEnd + endTagLen;
commentStart = content.indexOf(startTag, start);
commentEnd = content.indexOf(endTag, commentStart + startTagLen);
}
// 仅允许在 demo 不存在时,才可以在 Markdown 中写 script 标签
// todo: 优化这段逻辑
let pageScript = '';
if (componenetsString) {
pageScript = `<script>
export default {
name: 'component-doc',
components: {
${componenetsString}
},
}
</script>`;
} else if (content.indexOf('<script>') === 0) { // 硬编码,有待改善
start = content.indexOf('</script>') + '</script>'.length;
pageScript = content.slice(0, start);
}
output.push(content.slice(start));
return `
<template>
<section class="content element-doc">
${output.join('')}
</section>
</template>
${pageScript}
`;
};
const {
stripScript,
stripTemplate,
genInlineComponentText
} = require('./util');
const md = require('./config');
module.exports = function(source) {
const content = md.render(source);
const startTag = '<!--element-demo:';
const startTagLen = startTag.length;
const endTag = ':element-demo-->';
const endTagLen = endTag.length;
let componenetsString = '';
let id = 0; // demo 的 id
let output = []; // 输出的内容
let start = 0; // 字符串开始位置
let commentStart = content.indexOf(startTag);
let commentEnd = content.indexOf(endTag, commentStart + startTagLen);
while (commentStart !== -1 && commentEnd !== -1) {
output.push(content.slice(start, commentStart));
const commentContent = content.slice(commentStart + startTagLen, commentEnd);
const html = stripTemplate(commentContent);
const script = stripScript(commentContent);
let demoComponentContent = genInlineComponentText(html, script);
const demoComponentName = `element-demo${id}`;
output.push(`<template slot="source"><${demoComponentName} /></template>`);
componenetsString += `${JSON.stringify(demoComponentName)}: ${demoComponentContent},`;
// 重新计算下一次的位置
id++;
start = commentEnd + endTagLen;
commentStart = content.indexOf(startTag, start);
commentEnd = content.indexOf(endTag, commentStart + startTagLen);
}
// 仅允许在 demo 不存在时,才可以在 Markdown 中写 script 标签
// todo: 优化这段逻辑
let pageScript = '';
if (componenetsString) {
pageScript = `<script>
export default {
name: 'component-doc',
components: {
${componenetsString}
},
}
</script>`;
} else if (content.indexOf('<script>') === 0) { // 硬编码,有待改善
start = content.indexOf('</script>') + '</script>'.length;
pageScript = content.slice(0, start);
}
output.push(content.slice(start));
return `
<template>
<section class="content element-doc">
${output.join('')}
</section>
</template>
${pageScript}
`;
};

View File

@ -56,8 +56,8 @@ function genInlineComponentText(template, script) {
`;
// todo: 这里采用了硬编码有待改进
script = script.trim();
if (script) {
script = script.replace(/export\s+default/, 'const democomponentExport =');
if (script) {
script = script.replace(/export\s+default/, 'const democomponentExport =');
} else {
script = 'const democomponentExport = {}';
}
@ -74,11 +74,11 @@ function genInlineComponentText(template, script) {
}
}
})()`;
// console.log('\n\n\n=================\n\n\n')
// console.log(demoComponentContent);
// console.log('\n\n\n=================\n\n\n')
return demoComponentContent;
}

View File

@ -10,7 +10,7 @@ const isProd = process.env.NODE_ENV === 'prod';
const webpackConfig = {
entry: {
'xm-select': "./src/index.js",
'xm-select': "./src/main.js",
'static/docs': "./docs/entry.js",
},
output: {

12
dist/index.html vendored
View File

@ -1,7 +1,7 @@
<!DOCTYPE html><html><head><script>var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?758a90d7d534804ddd66137da7c9ee69";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
<!DOCTYPE html><html><head><script>var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?758a90d7d534804ddd66137da7c9ee69";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();</script><link rel="preload" href="./xm-select.js" as="script"><link rel="preload" href="./static/docs.js" as="script"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"><title>xm-select</title><link rel="stylesheet" href="https://www.layuicdn.com/layui-v2.5.5/css/layui.css"><script src="https://www.layuicdn.com/layui-v2.5.5/layui.all.js"></script><script src="https://unpkg.com/axios/dist/axios.min.js"></script></head><body><div id="app"></div><script type="text/javascript" src="./xm-select.js"></script><script type="text/javascript" src="./static/docs.js"></script></body></html>

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

10
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

@ -175,55 +175,57 @@
}
.content {
padding-top: 50px;
padding-top: 50px;
pre{
tab-size: 4;
}
&> {
h3 {
margin: 55px 0 20px;
&>h3 {
margin: 55px 0 20px;
}
&>ul:not(.timeline) {
margin: 10px 0;
padding: 0 0 0 20px;
font-size: 14px;
color: #5e6d82;
line-height: 2em;
}
&>table {
border-collapse: collapse;
width: 100%;
background-color: #fff;
font-size: 14px;
margin-bottom: 45px;
line-height: 1.5em;
strong {
font-weight: normal;
}
table {
border-collapse: collapse;
width: 100%;
background-color: #fff;
font-size: 14px;
margin-bottom: 45px;
line-height: 1.5em;
strong {
font-weight: normal;
}
td,
th {
border-bottom: 1px solid #dcdfe6;
padding: 15px;
max-width: 250px;
}
th {
text-align: left;
white-space: nowrap;
color: #909399;
font-weight: normal;
}
td {
color: #606266;
}
th:first-child,
td:first-child {
padding-left: 10px;
}
td,
th {
border-bottom: 1px solid #dcdfe6;
padding: 15px;
max-width: 250px;
}
ul:not(.timeline) {
margin: 10px 0;
padding: 0 0 0 20px;
font-size: 14px;
color: #5e6d82;
line-height: 2em;
th {
text-align: left;
white-space: nowrap;
color: #909399;
font-weight: normal;
}
td {
color: #606266;
}
th:first-child,
td:first-child {
padding-left: 10px;
}
}
}

View File

@ -1,245 +1,254 @@
*{
margin: 0;
padding: 0;
}
*{
margin: 0;
padding: 0;
}
html, body {
margin: 0;
padding: 0;
height: 100%;
font-family: 'Helvetica Neue',Helvetica,'PingFang SC','Hiragino Sans GB','Microsoft YaHei',SimSun,sans-serif;
font-weight: 400;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
&.is-component {
overflow: hidden;
}
}
#app {
height: 100%;
&.is-component {
overflow-y: hidden;
.main-cnt {
padding: 0;
margin-top: 0;
height: 100%;
min-height: auto;
}
.headerWrapper {
position: fixed;
width: 100%;
left: 0;
top: 0;
z-index: 1500;
.container {
padding: 0;
}
}
}
}
a {
color: #409EFF;
text-decoration: none;
}
code {
background-color: #f9fafc;
padding: 0 4px;
border: 1px solid #eaeefb;
border-radius: 4px;
}
button, input, select, textarea {
font-family: inherit;
font-size: inherit;
line-height: inherit;
color: inherit;
}
.hljs {
line-height: 1.8;
font-family: Menlo, Monaco, Consolas, Courier, monospace;
font-size: 12px;
padding: 18px 24px;
background-color: #fafafa;
border: solid 1px #eaeefb;
margin-bottom: 25px;
border-radius: 4px;
-webkit-font-smoothing: auto;
}
.main-cnt {
margin-top: -80px;
padding: 80px 0 340px;
box-sizing: border-box;
min-height: 100%;
}
.container,
.page-container {
width: 1140px;
padding: 0;
margin: 0 auto;
}
.page-container {
padding-top: 55px;
h2 {
font-size: 28px;
color: #1f2d3d;
margin: 0;
}
h3 {
font-size: 22px;
}
h2, h3, h4, h5 {
font-weight: normal;
color: #1f2f3d;
&:hover a {
opacity: .4;
}
a {
float: left;
margin-left: -20px;
opacity: 0;
cursor: pointer;
&:hover {
opacity: .4;
}
}
}
p {
font-size: 14px;
color: #5e6d82;
line-height: 1.5em;
}
.tip {
padding: 8px 16px;
background-color: #ECF8FF;
border-radius: 4px;
border-left: #50bfff 5px solid;
margin: 20px 0;
code {
background-color: rgba(255, 255, 255, .7);
color: #445368;
}
}
.warning {
padding: 8px 16px;
background-color: #fff6f7;
border-radius: 4px;
border-left: #FE6C6F 5px solid;
margin: 20px 0;
code {
background-color: rgba(255, 255, 255, .7);
color: #445368;
}
}
}
.demo {
margin: 20px 0;
}
@media (max-width: 1140px) {
.container,
.page-container {
width: 100%;
}
}
@media (max-width: 768px) {
.container,
.page-container {
padding: 0 20px;
}
#app.is-component .headerWrapper .container {
padding: 0 12px;
}
}
.xm-select-demo{
vertical-align: top;
display: inline-block;
width: 300px;
margin-bottom: 10px;
}
.xm-select-size{
vertical-align: top;
display: inline-block;
width: 150px;
}
.xm-select-demo-alert:extend(.xm-select-demo){
margin: 20px;
}
.btn{
outline: 0;
display: inline-block;
height: 38px;
line-height: 38px;
padding: 0 18px;
background-color: #009688;
color: #fff;
white-space: nowrap;
text-align: center;
font-size: 14px;
border: none;
border-radius: 2px;
cursor: pointer;
vertical-align: top;
margin-left: 10px;
margin-bottom: 10px;
&:hover{
opacity: .8;
}
&:active{
opacity: 1;
}
}
.demo-ZM03{
table{
margin-bottom: -1px !important;
border-collapse: unset !important;
line-height: unset !important;
font-size: unset !important;
background-color: unset !important;
th, td{
padding: 5px 0 !important;
}
}
}
.ly-label-center.layui-form-pane .layui-form-label{
display: flex;
align-items: center;
justify-content: center;
}
.demo-ZP01{
.xm-body-custom{
padding: 0 10px;
}
table{
margin-bottom: -1px !important;
}
}
html, body {
margin: 0;
padding: 0;
height: 100%;
font-family: 'Helvetica Neue',Helvetica,'PingFang SC','Hiragino Sans GB','Microsoft YaHei',SimSun,sans-serif;
font-weight: 400;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
&.is-component {
overflow: hidden;
}
}
#app {
height: 100%;
&.is-component {
overflow-y: hidden;
.main-cnt {
padding: 0;
margin-top: 0;
height: 100%;
min-height: auto;
}
.headerWrapper {
position: fixed;
width: 100%;
left: 0;
top: 0;
z-index: 1500;
.container {
padding: 0;
}
}
}
}
a {
color: #409EFF;
text-decoration: none;
}
code {
background-color: #f9fafc;
padding: 0 4px;
border: 1px solid #eaeefb;
border-radius: 4px;
}
button, input, select, textarea {
font-family: inherit;
font-size: inherit;
line-height: inherit;
color: inherit;
}
.hljs {
line-height: 1.8;
font-family: Menlo, Monaco, Consolas, Courier, monospace;
font-size: 12px;
padding: 18px 24px;
background-color: #fafafa;
border: solid 1px #eaeefb;
margin-bottom: 25px;
border-radius: 4px;
-webkit-font-smoothing: auto;
}
.main-cnt {
margin-top: -80px;
padding: 80px 0 340px;
box-sizing: border-box;
min-height: 100%;
}
.container,
.page-container {
width: 1140px;
padding: 0;
margin: 0 auto;
}
.page-container {
padding-top: 55px;
h2 {
font-size: 28px;
color: #1f2d3d;
margin: 0;
}
h3 {
font-size: 22px;
}
h2, h3, h4, h5 {
font-weight: normal;
color: #1f2f3d;
&:hover a {
opacity: .4;
}
a {
float: left;
margin-left: -20px;
opacity: 0;
cursor: pointer;
&:hover {
opacity: .4;
}
}
}
p {
font-size: 14px;
color: #5e6d82;
line-height: 1.5em;
}
.tip {
padding: 8px 16px;
background-color: #ECF8FF;
border-radius: 4px;
border-left: #50bfff 5px solid;
margin: 20px 0;
code {
background-color: rgba(255, 255, 255, .7);
color: #445368;
}
}
.warning {
padding: 8px 16px;
background-color: #fff6f7;
border-radius: 4px;
border-left: #FE6C6F 5px solid;
margin: 20px 0;
code {
background-color: rgba(255, 255, 255, .7);
color: #445368;
}
}
}
.demo {
margin: 20px 0;
}
@media (max-width: 1140px) {
.container,
.page-container {
width: 100%;
}
}
@media (max-width: 768px) {
.container,
.page-container {
padding: 0 20px;
}
#app.is-component .headerWrapper .container {
padding: 0 12px;
}
}
.xm-select-demo{
vertical-align: top;
display: inline-block;
width: 300px;
margin-bottom: 10px;
}
.xm-select-size{
vertical-align: top;
display: inline-block;
width: 150px;
}
.xm-select-demo-alert:extend(.xm-select-demo){
margin: 20px;
}
.btn{
outline: 0;
display: inline-block;
height: 38px;
line-height: 38px;
padding: 0 18px;
background-color: #009688;
color: #fff;
white-space: nowrap;
text-align: center;
font-size: 14px;
border: none;
border-radius: 2px;
cursor: pointer;
vertical-align: top;
margin-left: 10px;
margin-bottom: 10px;
&:hover{
opacity: .8;
.demo-ZP03{
.layui-laydate-footer{
padding: 0;
}
&:active{
opacity: 1;
xm-select .scroll-body{
text-align: center;
}
}
.demo-ZM03{
table{
margin-bottom: -1px !important;
border-collapse: unset !important;
line-height: unset !important;
font-size: unset !important;
background-color: unset !important;
th, td{
padding: 5px 0 !important;
}
}
}
.ly-label-center.layui-form-pane .layui-form-label{
display: flex;
align-items: center;
justify-content: center;
}
.demo-ZP01{
.xm-body-custom{
padding: 0 10px;
}
table{
margin-bottom: 10px !important;
}
}

View File

@ -24,7 +24,7 @@ const router = new VueRouter({
router.beforeEach((to, from, next) => {
if (to.path) {
_hmt.push(['_trackPageview', to.fullPath]);
_hmt.push(['_trackPageview', '/#' + to.fullPath]);
}
next();
});

View File

@ -1,31 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?758a90d7d534804ddd66137da7c9ee69";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<% for (var chunk in htmlWebpackPlugin.files.css) { %>
<link rel="preload" href="<%= htmlWebpackPlugin.files.css[chunk] %>" as="style">
<% } %>
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
<link rel="preload" href="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>" as="script">
<% } %>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title>xm-select</title>
<link rel="stylesheet" href="https://www.layuicdn.com/layui-v2.5.5/css/layui.css">
<script src="https://www.layuicdn.com/layui-v2.5.5/layui.all.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?758a90d7d534804ddd66137da7c9ee69";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<% for (var chunk in htmlWebpackPlugin.files.css) { %>
<link rel="preload" href="<%= htmlWebpackPlugin.files.css[chunk] %>" as="style">
<% } %>
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
<link rel="preload" href="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>" as="script">
<% } %>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title>xm-select</title>
<link rel="stylesheet" href="https://www.layuicdn.com/layui-v2.5.5/css/layui.css">
<script src="https://www.layuicdn.com/layui-v2.5.5/layui.all.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@ -1,26 +1,26 @@
## 基础使用
:::tip
只需引入`xm-select.js`, 剩下的就只有渲染了
:::
### 一个小栗子
:::demo `el`绑定的不一定是id, 也可以是其他css选择器
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
## 基础使用
:::tip
只需引入`xm-select.js`, 剩下的就只有渲染了
:::
### 一个小栗子
:::demo `el`绑定的不一定是id, 也可以是其他css选择器
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::

View File

@ -1,28 +1,28 @@
## 国际化
### 英语
:::demo 目前仅支持`中文`和`英文`, 如需更多语言, 可以`clone`代码进行二次开发
```html
<div id="demo1" class="xm-select-demo"></div>
<div xid="demo2" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
language: 'en',
data: []
})
var demo2 = xmSelect.render({
el: '[xid=demo2]',
language: 'en',
data: [
{name: 'apple', value: 1},
{name: 'banana', value: 2},
{name: 'orange', value: 3},
]
})
</script>
```
## 国际化
### 英语
:::demo 目前仅支持`中文`和`英文`, 如需更多语言, 可以`clone`代码进行二次开发
```html
<div id="demo1" class="xm-select-demo"></div>
<div xid="demo2" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
language: 'en',
data: []
})
var demo2 = xmSelect.render({
el: '[xid=demo2]',
language: 'en',
data: [
{name: 'apple', value: 1},
{name: 'banana', value: 2},
{name: 'orange', value: 3},
]
})
</script>
```
:::

View File

@ -1,47 +1,47 @@
## 默认选中
### 使用`selected`属性
:::demo 当然`selected`是选中, `disabled`是禁用
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 使用initValue进行初始化
:::demo `initValue`的优先级大于选项中的`selected`
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo5 = xmSelect.render({
el: '#demo1',
initValue: [4],
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
]
})
</script>
```
:::
## 默认选中
### 使用`selected`属性
:::demo 当然`selected`是选中, `disabled`是禁用
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 使用initValue进行初始化
:::demo `initValue`的优先级大于选项中的`selected`
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo5 = xmSelect.render({
el: '#demo1',
initValue: [4],
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
]
})
</script>
```
:::

View File

@ -1,64 +1,64 @@
## 修改提示
### 修改选项提示文字
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
tips: '你喜欢什么水果呢?',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 修改空数据提示文字
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
empty: '呀, 没有数据呢',
data: [ ]
})
</script>
```
:::
### 修改搜索提示文字
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
filterable: true,
searchTips: '你想吃什么水果吧',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
## 修改提示
### 修改选项提示文字
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
tips: '你喜欢什么水果呢?',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 修改空数据提示文字
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
empty: '呀, 没有数据呢',
data: [ ]
})
</script>
```
:::
### 修改搜索提示文字
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
filterable: true,
searchTips: '你想吃什么水果吧',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::

View File

@ -1,183 +1,183 @@
## 搜索模式
### 默认搜索
:::demo 默认按照`name`进行搜索
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
filterable: true,
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 重写搜索方法
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
filterable: true,
filterMethod: function(val, item, index, prop){
if(val == item.value){//把value相同的搜索出来
return true;
}
if(item.name.indexOf(val) != -1){//名称中包含的搜索出来
return true;
}
return false;//不知道的就不管了
},
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 搜索延迟
为了提高有效搜索, 当停止输入`500ms`后才开始进行过滤搜索, 当然这个`500`你也可以进行修改
:::demo `delay: 2000` 输入停止2s后进行搜索过滤
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
filterable: true,
delay: 2000,
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 自定义搜索 (远程搜索)
第一步: 需要先开启搜索 `filterable: true,`
第二步: 开启自定义搜索 `remoteSearch: true`
第三部: 重写搜索回调
简单吧, 记得Star ^_^
:::demo `render`后, 就会进行一次回调, 用于渲染第一次数据
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
filterable: true,
remoteSearch: true,
remoteMethod: function(val, cb, show){
//这里模拟3s后返回数据
setTimeout(function(){
//需要回传一个数组
cb([
{name: '水果' + val, value: val + 1},
{name: '蔬菜' + val, value: val + 2, selected: true},
{name: '桌子' + val, value: val + 3},
{name: '北京' + val, value: val + 4},
])
}, 3000)
},
data: []
})
</script>
```
:::
### 远程搜索
第一步: 需要先开启搜索 `filterable: true,`
第二步: 开启自定义搜索 `remoteSearch: true`
第三部: 重写搜索回调
简单吧, 记得Star ^_^
:::demo `render`后, 就会进行一次回调, 用于渲染第一次数据
```html
<div id="demo5" class="xm-select-demo"></div>
<script>
var demo5 = xmSelect.render({
el: '#demo5',
filterable: true,
remoteSearch: true,
remoteMethod: function(val, cb, show){
axios({
method: 'get',
url: 'https://www.fastmock.site/mock/98228b1f16b7e5112d6c0c87921eabc1/xmSelect/search',
params: {
keyword: val,
}
}).then(response => {
var res = response.data;
cb(res.data)
}).catch(err => {
cb([]);
});
},
data: []
})
</script>
```
:::
### 搜索完成回调
:::demo
```html
<div id="demo6" class="xm-select-demo"></div>
<script>
var demo6 = xmSelect.render({
el: '#demo6',
filterable: true,
filterDone: function(val, list){
alert(`搜索完毕, 搜索关键词: ${val}, 过滤数据: ${list.length}个`)
},
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
## 搜索模式
### 默认搜索
:::demo 默认按照`name`进行搜索
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
filterable: true,
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 重写搜索方法
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
filterable: true,
filterMethod: function(val, item, index, prop){
if(val == item.value){//把value相同的搜索出来
return true;
}
if(item.name.indexOf(val) != -1){//名称中包含的搜索出来
return true;
}
return false;//不知道的就不管了
},
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 搜索延迟
为了提高有效搜索, 当停止输入`500ms`后才开始进行过滤搜索, 当然这个`500`你也可以进行修改
:::demo `delay: 2000` 输入停止2s后进行搜索过滤
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
filterable: true,
delay: 2000,
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 自定义搜索 (远程搜索)
第一步: 需要先开启搜索 `filterable: true,`
第二步: 开启自定义搜索 `remoteSearch: true`
第三部: 重写搜索回调
简单吧, 记得Star ^_^
:::demo `render`后, 就会进行一次回调, 用于渲染第一次数据
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
filterable: true,
remoteSearch: true,
remoteMethod: function(val, cb, show){
//这里模拟3s后返回数据
setTimeout(function(){
//需要回传一个数组
cb([
{name: '水果' + val, value: val + 1},
{name: '蔬菜' + val, value: val + 2, selected: true},
{name: '桌子' + val, value: val + 3},
{name: '北京' + val, value: val + 4},
])
}, 3000)
},
data: []
})
</script>
```
:::
### 远程搜索
第一步: 需要先开启搜索 `filterable: true,`
第二步: 开启自定义搜索 `remoteSearch: true`
第三部: 重写搜索回调
简单吧, 记得Star ^_^
:::demo `render`后, 就会进行一次回调, 用于渲染第一次数据
```html
<div id="demo5" class="xm-select-demo"></div>
<script>
var demo5 = xmSelect.render({
el: '#demo5',
filterable: true,
remoteSearch: true,
remoteMethod: function(val, cb, show){
axios({
method: 'get',
url: 'https://www.fastmock.site/mock/98228b1f16b7e5112d6c0c87921eabc1/xmSelect/search',
params: {
keyword: val,
}
}).then(response => {
var res = response.data;
cb(res.data)
}).catch(err => {
cb([]);
});
},
data: []
})
</script>
```
:::
### 搜索完成回调
:::demo
```html
<div id="demo6" class="xm-select-demo"></div>
<script>
var demo6 = xmSelect.render({
el: '#demo6',
filterable: true,
filterDone: function(val, list){
alert(`搜索完毕, 搜索关键词: ${val}, 过滤数据: ${list.length}个`)
},
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::

View File

@ -1,69 +1,69 @@
## 下拉方向
### 自动`auto`
:::demo
```html
<div style="height: 500px">占位div, 演示效果使用, 底部空间不足时会自动向上展开</div>
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
direction: 'auto',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 打卡向上`up`
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
direction: 'up',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 打开向下`down`
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
direction: 'down',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
## 下拉方向
### 自动`auto`
:::demo
```html
<div style="height: 500px">占位div, 演示效果使用, 底部空间不足时会自动向上展开</div>
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
direction: 'auto',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 打卡向上`up`
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
direction: 'up',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 打开向下`down`
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
direction: 'down',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::

View File

@ -1,49 +1,49 @@
## 自定义样式
### 随便试试
修改一下外边距, 加上圆角, 更改一下高度
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
style: {
marginLeft: '200px',
borderRadius: '50px',
height: '50px',
},
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 修改下拉框的最大高度
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
height: '50px',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
## 自定义样式
### 随便试试
修改一下外边距, 加上圆角, 更改一下高度
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
style: {
marginLeft: '200px',
borderRadius: '50px',
height: '50px',
},
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 修改下拉框的最大高度
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
height: '50px',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::

View File

@ -1,176 +1,176 @@
## 分页
### 启用分页
```
xmSelect.render({
//...
paging: true,
})
```
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
paging: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::
### 自定义条数
每页3条
```
xmSelect.render({
//...
paging: true,
pageSize: 3,
})
```
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
paging: true,
pageSize: 3,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::
### 搜索+分页
```
xmSelect.render({
//...
paging: true,
pageSize: 5,
filterable: true,
})
```
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<button class="btn" id="demo3-5">每页5条</button>
<button class="btn" id="demo3-10">每页10条</button>
<button class="btn" id="demo3-20">每页20条</button>
<script>
var data = [];
for(var i = 0 ; i < 100 ; i++ ){
data.push({
name: '测试数据' + i,
value: i,
})
}
var demo3 = xmSelect.render({
el: '#demo3',
paging: true,
pageSize: 5,
filterable: true,
data
})
document.getElementById('demo3-5').onclick = function(){
demo3.update({
pageSize: 5
})
}
document.getElementById('demo3-10').onclick = function(){
demo3.update({
pageSize: 10
})
}
document.getElementById('demo3-20').onclick = function(){
demo3.update({
pageSize: 20
})
}
</script>
```
:::
### 搜索 + 分页 无数据 不展示分页
```
xmSelect.render({
//...
paging: true,
pageSize: 3,
filterable: true,
pageEmptyShow: false,
})
```
:::demo
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
paging: true,
pageSize: 3,
filterable: true,
pageEmptyShow: false,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::
## 分页
### 启用分页
```
xmSelect.render({
//...
paging: true,
})
```
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
paging: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::
### 自定义条数
每页3条
```
xmSelect.render({
//...
paging: true,
pageSize: 3,
})
```
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
paging: true,
pageSize: 3,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::
### 搜索+分页
```
xmSelect.render({
//...
paging: true,
pageSize: 5,
filterable: true,
})
```
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<button class="btn" id="demo3-5">每页5条</button>
<button class="btn" id="demo3-10">每页10条</button>
<button class="btn" id="demo3-20">每页20条</button>
<script>
var data = [];
for(var i = 0 ; i < 100 ; i++ ){
data.push({
name: '测试数据' + i,
value: i,
})
}
var demo3 = xmSelect.render({
el: '#demo3',
paging: true,
pageSize: 5,
filterable: true,
data
})
document.getElementById('demo3-5').onclick = function(){
demo3.update({
pageSize: 5
})
}
document.getElementById('demo3-10').onclick = function(){
demo3.update({
pageSize: 10
})
}
document.getElementById('demo3-20').onclick = function(){
demo3.update({
pageSize: 20
})
}
</script>
```
:::
### 搜索 + 分页 无数据 不展示分页
```
xmSelect.render({
//...
paging: true,
pageSize: 3,
filterable: true,
pageEmptyShow: false,
})
```
:::demo
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
paging: true,
pageSize: 3,
filterable: true,
pageEmptyShow: false,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::

View File

@ -1,79 +1,79 @@
## 单选
### 开启单选
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
radio: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 单选完关闭下拉
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
radio: true,
clickClose: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 更换显示方式
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
radio: true,
clickClose: true,
model: {
label: {
type: 'text',
text: {
//左边拼接的字符
left: '',
//右边拼接的字符
right: '',
//中间的分隔符
separator: ', ',
},
}
},
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
## 单选
### 开启单选
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
radio: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 单选完关闭下拉
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
radio: true,
clickClose: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 更换显示方式
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
radio: true,
clickClose: true,
model: {
label: {
type: 'text',
text: {
//左边拼接的字符
left: '',
//右边拼接的字符
right: '',
//中间的分隔符
separator: ', ',
},
}
},
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::

View File

@ -1,83 +1,83 @@
## 重复选
### 开启重复选
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
repeat: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 重复选完关闭下拉
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
repeat: true,
clickClose: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 更换显示方式
:::demo 好像这样只能增不能减了~~ 有待完善
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
repeat: true,
model: {
label: {
type: 'count',
count: {
template: function(data, sels){
var res = {};
sels.forEach(item => {
var name = item.name;
!res[name] && (res[name] = 0);
res[name] += 1;
});
return Object.keys(res).map(key => {
return `${key} (${res[key]})`
}).join(',');
}
},
}
},
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
## 重复选
### 开启重复选
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
repeat: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 重复选完关闭下拉
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
repeat: true,
clickClose: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 更换显示方式
:::demo 好像这样只能增不能减了~~ 有待完善
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
repeat: true,
model: {
label: {
type: 'count',
count: {
template: function(data, sels){
var res = {};
sels.forEach(item => {
var name = item.name;
!res[name] && (res[name] = 0);
res[name] += 1;
});
return Object.keys(res).map(key => {
return `${key} (${res[key]})`
}).join(',');
}
},
}
},
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::

View File

@ -1,35 +1,35 @@
## 自定义属性
### 更换属性key
也许你的数据库返回的并不是`name`和`value`, 也许你提交的时候不止`name`和`value`, 怎么办? 自定义就行
:::demo 我的`name`是`label`, 我的`value`是`id`, 我有其他属性`group`
```html
<div id="demo1" class="xm-select-demo"></div>
<button class="btn" id="demo1-getValue">获取选中值</button>
<pre id="demo1-value"></pre>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
prop: {
name: 'label',
value: 'id',
},
data: [
{label: '张三', id: 1, group: 1},
{label: '李四', id: 2, group: 1},
{label: '王五', id: 3, group: 2},
]
})
document.getElementById('demo1-getValue').onclick = function(){
//获取当前多选选中的值
var selectArr = demo1.getValue();
document.getElementById('demo1-value').innerHTML = JSON.stringify(selectArr, null, 2);
}
</script>
```
:::
## 自定义属性
### 更换属性key
也许你的数据库返回的并不是`name`和`value`, 也许你提交的时候不止`name`和`value`, 怎么办? 自定义就行
:::demo 我的`name`是`label`, 我的`value`是`id`, 我有其他属性`group`
```html
<div id="demo1" class="xm-select-demo"></div>
<button class="btn" id="demo1-getValue">获取选中值</button>
<pre id="demo1-value"></pre>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
prop: {
name: 'label',
value: 'id',
},
data: [
{label: '张三', id: 1, group: 1},
{label: '李四', id: 2, group: 1},
{label: '王五', id: 3, group: 2},
]
})
document.getElementById('demo1-getValue').onclick = function(){
//获取当前多选选中的值
var selectArr = demo1.getValue();
document.getElementById('demo1-value').innerHTML = JSON.stringify(selectArr, null, 2);
}
</script>
```
:::

View File

@ -1,329 +1,329 @@
## 主题
### 经典绿 ( #009688 )
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 嫣红 ( #e54d42 )
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
theme: {
color: '#e54d42',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 桔橙 ( #f37b1d )
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
theme: {
color: '#f37b1d',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 明黄 ( #fbbd08 )
:::demo
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
theme: {
color: '#fbbd08',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 橄榄 ( #8dc63f )
:::demo
```html
<div id="demo5" class="xm-select-demo"></div>
<script>
var demo5 = xmSelect.render({
el: '#demo5',
theme: {
color: '#8dc63f',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 天青 ( #1cbbb4 )
:::demo
```html
<div id="demo6" class="xm-select-demo"></div>
<script>
var demo6 = xmSelect.render({
el: '#demo6',
theme: {
color: '#1cbbb4',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 海蓝 ( #0081ff )
:::demo
```html
<div id="demo7" class="xm-select-demo"></div>
<script>
var demo7 = xmSelect.render({
el: '#demo7',
theme: {
color: '#0081ff',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 姹紫 ( #6739b6 )
:::demo
```html
<div id="demo8" class="xm-select-demo"></div>
<script>
var demo8 = xmSelect.render({
el: '#demo8',
theme: {
color: '#6739b6',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 木槿 ( #9c26b0 )
:::demo
```html
<div id="demo9" class="xm-select-demo"></div>
<script>
var demo9 = xmSelect.render({
el: '#demo9',
theme: {
color: '#9c26b0',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 桃粉 ( #e03997 )
:::demo
```html
<div id="demo10" class="xm-select-demo"></div>
<script>
var demo10 = xmSelect.render({
el: '#demo10',
theme: {
color: '#e03997',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 棕褐 ( #a5673f )
:::demo
```html
<div id="demo11" class="xm-select-demo"></div>
<script>
var demo11 = xmSelect.render({
el: '#demo11',
theme: {
color: '#a5673f',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 玄灰 ( #8799a3 )
:::demo
```html
<div id="demo12" class="xm-select-demo"></div>
<script>
var demo12 = xmSelect.render({
el: '#demo12',
theme: {
color: '#8799a3',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 草灰 ( #aaaaaa )
:::demo
```html
<div id="demo13" class="xm-select-demo"></div>
<script>
var demo13 = xmSelect.render({
el: '#demo13',
theme: {
color: '#aaaaaa',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 墨黑 ( #333333 )
:::demo
```html
<div id="demo14" class="xm-select-demo"></div>
<script>
var demo14 = xmSelect.render({
el: '#demo14',
theme: {
color: '#333333',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
:::warning
颜色值来源于[ColorUI](https://github.com/weilanwl/ColorUI), 有兴趣的可以看看
:::
## 主题
### 经典绿 ( #009688 )
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 嫣红 ( #e54d42 )
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
theme: {
color: '#e54d42',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 桔橙 ( #f37b1d )
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
theme: {
color: '#f37b1d',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 明黄 ( #fbbd08 )
:::demo
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
theme: {
color: '#fbbd08',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 橄榄 ( #8dc63f )
:::demo
```html
<div id="demo5" class="xm-select-demo"></div>
<script>
var demo5 = xmSelect.render({
el: '#demo5',
theme: {
color: '#8dc63f',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 天青 ( #1cbbb4 )
:::demo
```html
<div id="demo6" class="xm-select-demo"></div>
<script>
var demo6 = xmSelect.render({
el: '#demo6',
theme: {
color: '#1cbbb4',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 海蓝 ( #0081ff )
:::demo
```html
<div id="demo7" class="xm-select-demo"></div>
<script>
var demo7 = xmSelect.render({
el: '#demo7',
theme: {
color: '#0081ff',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 姹紫 ( #6739b6 )
:::demo
```html
<div id="demo8" class="xm-select-demo"></div>
<script>
var demo8 = xmSelect.render({
el: '#demo8',
theme: {
color: '#6739b6',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 木槿 ( #9c26b0 )
:::demo
```html
<div id="demo9" class="xm-select-demo"></div>
<script>
var demo9 = xmSelect.render({
el: '#demo9',
theme: {
color: '#9c26b0',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 桃粉 ( #e03997 )
:::demo
```html
<div id="demo10" class="xm-select-demo"></div>
<script>
var demo10 = xmSelect.render({
el: '#demo10',
theme: {
color: '#e03997',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 棕褐 ( #a5673f )
:::demo
```html
<div id="demo11" class="xm-select-demo"></div>
<script>
var demo11 = xmSelect.render({
el: '#demo11',
theme: {
color: '#a5673f',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 玄灰 ( #8799a3 )
:::demo
```html
<div id="demo12" class="xm-select-demo"></div>
<script>
var demo12 = xmSelect.render({
el: '#demo12',
theme: {
color: '#8799a3',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 草灰 ( #aaaaaa )
:::demo
```html
<div id="demo13" class="xm-select-demo"></div>
<script>
var demo13 = xmSelect.render({
el: '#demo13',
theme: {
color: '#aaaaaa',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 墨黑 ( #333333 )
:::demo
```html
<div id="demo14" class="xm-select-demo"></div>
<script>
var demo14 = xmSelect.render({
el: '#demo14',
theme: {
color: '#333333',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
:::warning
颜色值来源于[ColorUI](https://github.com/weilanwl/ColorUI), 有兴趣的可以看看
:::

View File

@ -1,63 +1,63 @@
## 显示与隐藏
### 主动打开/关闭下拉框
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<button class="btn" id="demo1-open">打开下拉框</button>
<button class="btn" id="demo1-close">关闭下拉框</button>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
document.getElementById('demo1-open').onclick = function(){
//这里延迟1S, 是因为, 点击下拉框外边的位置 会出发关闭事件, 所以延迟演示效果
setTimeout(function(){
demo1.opened();
}, 1000);
}
document.getElementById('demo1-close').onclick = function(){
//先点一下关闭, 然后把下拉框点开, 3S后会自动关闭
setTimeout(function(){
demo1.closed();
}, 3000);
}
</script>
```
:::
### 监听打开/关闭下拉框
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
],
show(){
alert('打开了')
},
hide(){
alert('关闭了')
}
})
</script>
```
:::
## 显示与隐藏
### 主动打开/关闭下拉框
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<button class="btn" id="demo1-open">打开下拉框</button>
<button class="btn" id="demo1-close">关闭下拉框</button>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
document.getElementById('demo1-open').onclick = function(){
//这里延迟1S, 是因为, 点击下拉框外边的位置 会出发关闭事件, 所以延迟演示效果
setTimeout(function(){
demo1.opened();
}, 1000);
}
document.getElementById('demo1-close').onclick = function(){
//先点一下关闭, 然后把下拉框点开, 3S后会自动关闭
setTimeout(function(){
demo1.closed();
}, 3000);
}
</script>
```
:::
### 监听打开/关闭下拉框
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
],
show(){
alert('打开了')
},
hide(){
alert('关闭了')
}
})
</script>
```
:::

View File

@ -1,178 +1,178 @@
## 显示方式
### 方块形状
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 方块形状, 隐藏删除图标
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
model: {
label: {
type: 'block',
block: {
//最大显示数量, 0:不限制
showCount: 0,
//是否显示删除图标
showIcon: false,
}
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 方块形状, 超过1个隐藏
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
model: {
label: {
type: 'block',
block: {
//最大显示数量, 0:不限制
showCount: 1,
//是否显示删除图标
showIcon: true,
}
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 简单拼接形式
:::demo
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
model: {
label: {
type: 'text',
//使用字符串拼接的方式
text: {
//左边拼接的字符
left: '【',
//右边拼接的字符
right: '】',
//中间的分隔符
separator: '',
},
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
],
})
</script>
```
:::
### 自定义显示
:::demo
```html
<div id="demo5" class="xm-select-demo"></div>
<script>
var demo5 = xmSelect.render({
el: '#demo5',
model: {
label: {
type: 'xxxx', //自定义与下面的对应
xxxx: {
template(data, sels){
return "已选中 " + sels.length + " 项, 共 " + data.length + " 项"
}
},
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
],
})
</script>
```
:::
### 自定义显示HTML
:::demo
```html
<div id="demo6" class="xm-select-demo"></div>
<script>
var demo6 = xmSelect.render({
el: '#demo6',
model: {
label: {
type: 'xxxx', //自定义与下面的对应
xxxx: {
template(data, sels){
//也可以是html
return `<div style="color: red;">${sels.length} / ${data.length}</div>`
}
},
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
],
})
</script>
```
:::
## 显示方式
### 方块形状
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 方块形状, 隐藏删除图标
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
model: {
label: {
type: 'block',
block: {
//最大显示数量, 0:不限制
showCount: 0,
//是否显示删除图标
showIcon: false,
}
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 方块形状, 超过1个隐藏
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
model: {
label: {
type: 'block',
block: {
//最大显示数量, 0:不限制
showCount: 1,
//是否显示删除图标
showIcon: true,
}
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 简单拼接形式
:::demo
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
model: {
label: {
type: 'text',
//使用字符串拼接的方式
text: {
//左边拼接的字符
left: '【',
//右边拼接的字符
right: '】',
//中间的分隔符
separator: '',
},
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
],
})
</script>
```
:::
### 自定义显示
:::demo
```html
<div id="demo5" class="xm-select-demo"></div>
<script>
var demo5 = xmSelect.render({
el: '#demo5',
model: {
label: {
type: 'xxxx', //自定义与下面的对应
xxxx: {
template(data, sels){
return "已选中 " + sels.length + " 项, 共 " + data.length + " 项"
}
},
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
],
})
</script>
```
:::
### 自定义显示HTML
:::demo
```html
<div id="demo6" class="xm-select-demo"></div>
<script>
var demo6 = xmSelect.render({
el: '#demo6',
model: {
label: {
type: 'xxxx', //自定义与下面的对应
xxxx: {
template(data, sels){
//也可以是html
return `<div style="color: red;">${sels.length} / ${data.length}</div>`
}
},
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
],
})
</script>
```
:::

View File

@ -1,44 +1,44 @@
## 构建选项
### 默认渲染
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 'zhangsan', selected: true},
{name: '李四', value: 'lisi', selected: true},
{name: '王五', value: 'wangwu'},
]
})
</script>
```
:::
### 自定义渲染
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
template({ item, sels, name, value }){
return name + '<span style="position: absolute; right: 10px; color: #8799a3">'+value+'</span>'
},
data: [
{name: '张三', value: 'zhangsan', selected: true},
{name: '李四', value: 'lisi', selected: true},
{name: '王五', value: 'wangwu'},
]
})
</script>
```
:::
## 构建选项
### 默认渲染
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 'zhangsan', selected: true},
{name: '李四', value: 'lisi', selected: true},
{name: '王五', value: 'wangwu'},
]
})
</script>
```
:::
### 自定义渲染
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
template({ item, sels, name, value }){
return name + '<span style="position: absolute; right: 10px; color: #8799a3">'+value+'</span>'
},
data: [
{name: '张三', value: 'zhangsan', selected: true},
{name: '李四', value: 'lisi', selected: true},
{name: '王五', value: 'wangwu'},
]
})
</script>
```
:::

View File

@ -1,76 +1,81 @@
## 监听选择
### 实时监听
实时监听多选的选中状态变化
:::demo
```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',
on({ arr, change, isAdd }){
alert(`已有: ${arr.length} 变化: ${change.length}, 状态: ${isAdd}`)
},
data: [
{name: '张三', value: 'zhangsan', selected: true},
{name: '李四', value: 'lisi', selected: true},
{name: '王五', value: 'wangwu'},
]
})
document.getElementById('setValue1').onclick = function(){
demo1.setValue(['zhangsan'], null, true);
}
document.getElementById('setValue2').onclick = function(){
demo1.setValue(['zhangsan']);
}
</script>
```
:::
### 监听+动态赋值
选中北京后, 不能选中上海, 二者互斥
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
toolbar: {
show: true
},
on({ arr, change, isAdd }){
//arr: 当前多选已选中的数据
//change, 此次选择变化的数据,数组
//isAdd, 此次操作是新增还是删除
console.log(arr);
if(isAdd){
var item = change[0];
var index = arr.findIndex(i => i.mutex == item.mutex && i.value != item.value);
if(index != -1){
arr.splice(index, 1);
}
}
},
data: [
{name: '北京', value: 1, mutex: 1, selected: true},
{name: '上海', value: 2, mutex: 1},
{name: '广州', value: 3},
]
})
</script>
```
:::
## 监听选择
### 实时监听
实时监听多选的选中状态变化
:::demo
```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',
on({ arr, change, isAdd }){
alert(`已有: ${arr.length} 变化: ${change.length}, 状态: ${isAdd}`)
},
data: [
{name: '张三', value: 'zhangsan', selected: true},
{name: '李四', value: 'lisi', selected: true},
{name: '王五', value: 'wangwu'},
]
})
document.getElementById('setValue1').onclick = function(){
demo1.setValue(['zhangsan'], null, true);
}
document.getElementById('setValue2').onclick = function(){
demo1.setValue(['zhangsan']);
}
</script>
```
:::
### 监听+动态赋值
选中北京后, 不能选中上海, 二者互斥
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
toolbar: {
show: true
},
on: function(data){
//arr: 当前多选已选中的数据
var arr = data.arr;
//change, 此次选择变化的数据,数组
var change = data.change;
//isAdd, 此次操作是新增还是删除
var isAdd = data.isAdd;
console.log(arr);
if(isAdd){
var item = change[0];
var index = arr.findIndex(i => i.mutex == item.mutex && i.value != item.value);
if(index != -1){
arr.splice(index, 1);
}
}
},
data: [
{name: '北京', value: 1, mutex: 1, selected: true},
{name: '上海', value: 2, mutex: 1},
{name: '广州', value: 3},
]
})
</script>
```
:::

View File

@ -1,57 +1,57 @@
## 性能测试
### 数据渲染耗时测试
:::demo 事实证明分页是好使的 ^_^
```html
<div id="demo1" class="xm-select-demo"></div>
<button class="btn" id="demo1-test1">测试1000条</button>
<button class="btn" id="demo1-test2">测试10000条</button>
<button class="btn" id="demo1-test3">测试10000条+分页</button>
<pre id="demo1-result"></pre>
<script>
function run(count, paging){
//生成数据
var data = [];
for(var i = 0; i < count; i++){
data.push({
name: '测试数据' + i,
value: i,
})
}
//记录开始渲染时间
var startTime = Date.now();
var demo1 = xmSelect.render({
el: '#demo1',
paging,
data
})
//记录结束时间
var endTime = Date.now();
document.getElementById('demo1-result').innerText = `渲染耗时: ${endTime - startTime} ms`
}
document.getElementById('demo1-test1').onclick = function(){
run(1000, false)
};
document.getElementById('demo1-test2').onclick = function(){
run(10000, false)
};
document.getElementById('demo1-test3').onclick = function(){
run(10000, true)
};
run(1000, false);
</script>
```
:::
## 性能测试
### 数据渲染耗时测试
:::demo 事实证明分页是好使的 ^_^
```html
<div id="demo1" class="xm-select-demo"></div>
<button class="btn" id="demo1-test1">测试1000条</button>
<button class="btn" id="demo1-test2">测试10000条</button>
<button class="btn" id="demo1-test3">测试10000条+分页</button>
<pre id="demo1-result"></pre>
<script>
function run(count, paging){
//生成数据
var data = [];
for(var i = 0; i < count; i++){
data.push({
name: '测试数据' + i,
value: i,
})
}
//记录开始渲染时间
var startTime = Date.now();
var demo1 = xmSelect.render({
el: '#demo1',
paging,
data
})
//记录结束时间
var endTime = Date.now();
document.getElementById('demo1-result').innerText = `渲染耗时: ${endTime - startTime} ms`
}
document.getElementById('demo1-test1').onclick = function(){
run(1000, false)
};
document.getElementById('demo1-test2').onclick = function(){
run(10000, false)
};
document.getElementById('demo1-test3').onclick = function(){
run(10000, true)
};
run(1000, false);
</script>
```
:::

View File

@ -1,70 +1,70 @@
## 多选上限
### 最多选择2个
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
max: 2,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 自定义选超的提示
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
max: 2,
maxMethod(seles, item){
alert(`${item.name}不能选了, 已经超了`)
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 自定义选超的闪烁颜色
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
max: 2,
theme: {
maxColor: 'orange',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::
## 多选上限
### 最多选择2个
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
max: 2,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 自定义选超的提示
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
max: 2,
maxMethod(seles, item){
alert(`${item.name}不能选了, 已经超了`)
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 自定义选超的闪烁颜色
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
max: 2,
theme: {
maxColor: 'orange',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::

View File

@ -1,156 +1,156 @@
## 工具条
### 默认工具条
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
toolbar: {
show: true,
},
filterable: true,
paging: true,
pageSize: 3,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::
### 隐藏图标
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
toolbar: {
show: true,
showIcon: false,
},
filterable: true,
paging: true,
pageSize: 3,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::
### 自定义工具条
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
toolbar: {
show: true,
list: ['ALL', {
name: '自定义',
icon: 'el-icon-star-off',
method(data){
alert('我是自定义的');
}
}]
},
filterable: true,
paging: true,
pageSize: 3,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::
### 全部工具条
```
//全选, 清空, 反选
xmSelect.render({
toolbar: {
show: true,
list: [ 'ALL', 'CLEAR', 'REVERSE' ]
},
})
```
:::demo
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
toolbar: {
show: true,
list: [ 'ALL', 'CLEAR', 'REVERSE' ]
},
filterable: true,
paging: true,
pageSize: 3,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
## 工具条
### 默认工具条
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
toolbar: {
show: true,
},
filterable: true,
paging: true,
pageSize: 3,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::
### 隐藏图标
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
toolbar: {
show: true,
showIcon: false,
},
filterable: true,
paging: true,
pageSize: 3,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::
### 自定义工具条
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
toolbar: {
show: true,
list: ['ALL', {
name: '自定义',
icon: 'el-icon-star-off',
method(data){
alert('我是自定义的');
}
}]
},
filterable: true,
paging: true,
pageSize: 3,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::
### 全部工具条
```
//全选, 清空, 反选
xmSelect.render({
toolbar: {
show: true,
list: [ 'ALL', 'CLEAR', 'REVERSE' ]
},
})
```
:::demo
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
toolbar: {
show: true,
list: [ 'ALL', 'CLEAR', 'REVERSE' ]
},
filterable: true,
paging: true,
pageSize: 3,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::

View File

@ -1,39 +1,39 @@
## 选项显示数量
:::tip
当数量量过大时, 又不想使用分页的形式, 就可以控制显示数量, 用搜索的方式把最适合的数据展示出来
!!! 此处与分页配置互斥, 开启分页后, 此配置无效
!!! 使用此配置时建议开启搜索模式, 否则无法显示全部数据
:::
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<div>可以搜索 1, 2, 3看看效果</div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
filterable: true,
showCount: 5,
data: [
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3},
{name: '赵六1', value: 4},
{name: '苹果2', value: 5},
{name: '香蕉2', value: 6},
{name: '凤梨2', value: 7},
{name: '葡萄2', value: 8},
{name: '樱桃3', value: 9},
{name: '车厘子3', value: 10},
{name: '火龙果3', value: 11},
]
})
</script>
```
:::
## 选项显示数量
:::tip
当数量量过大时, 又不想使用分页的形式, 就可以控制显示数量, 用搜索的方式把最适合的数据展示出来
!!! 此处与分页配置互斥, 开启分页后, 此配置无效
!!! 使用此配置时建议开启搜索模式, 否则无法显示全部数据
:::
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<div>可以搜索 1, 2, 3看看效果</div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
filterable: true,
showCount: 5,
data: [
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3},
{name: '赵六1', value: 4},
{name: '苹果2', value: 5},
{name: '香蕉2', value: 6},
{name: '凤梨2', value: 7},
{name: '葡萄2', value: 8},
{name: '樱桃3', value: 9},
{name: '车厘子3', value: 10},
{name: '火龙果3', value: 11},
]
})
</script>
```
:::

View File

@ -1,164 +1,104 @@
## 分组
### optgroup模式
:::demo 指定选项中的`optgroup`为`true`
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
toolbar:{
show: true,
},
height: '500px',
data: [
{name: '销售员', optgroup: true},
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3, disabled: true},
{name: '奖品', optgroup: true},
{name: '苹果2', value: 4, selected: true, disabled: true},
{name: '香蕉2', value: 5},
{name: '葡萄2', value: 6},
]
})
</script>
```
:::
### children模式
:::demo 选项中的`children`为数组
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
toolbar:{
show: true,
},
filterable: true,
height: '500px',
data: [
{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>
```
:::
### 混合模式
如果自己感觉舒服的话, 也可以这么用...
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
filterable: true,
toolbar: {
show: true
},
height: '500px',
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},
]},
],
})
</script>
```
:::
### 分组的单击事件
:::demo
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
toolbar:{
show: true,
},
height: '500px',
data: [
{name: '选中', optgroup: true, click: 'SELECT'},
{name: '张三', value: 1},
{name: '李四', value: 2, disabled: true},
{name: '清空', optgroup: true, click: 'CLEAR'},
{name: '王五', value: 3, disabled: true},
{name: '苹果', value: 4, selected: true},
{name: '自动', optgroup: true, click: 'AUTO'},
{name: '香蕉', value: 5},
{name: '葡萄', value: 6},
{name: '自定义', optgroup: true, click: function(item){
alert('自定义的, 想干嘛干嘛');
}},
{name: '小米', value: 7},
{name: '华为', value: 8},
]
})
</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>
```
:::
## 分组
### children模式
:::demo 选项中的`children`为数组
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
toolbar:{
show: true,
},
filterable: true,
height: '500px',
data: [
{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>
```
:::
### 分组的单击事件
:::demo
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
toolbar:{
show: true,
},
height: '500px',
data: [
{name: '选中', optgroup: true, click: 'SELECT', children: [
{name: '张三', value: 1},
{name: '李四', value: 2, disabled: true},
]},
{name: '清空', optgroup: true, click: 'CLEAR', children: [
{name: '王五', value: 3, disabled: true},
{name: '苹果', value: 4, selected: true},
]},
{name: '自动', optgroup: true, click: 'AUTO', children: [
{name: '香蕉', value: 5},
{name: '葡萄', value: 6},
]},
{name: '自定义', optgroup: true, click: function(item){ alert('自定义的, 想干嘛干嘛') }, children: [
{name: '小米', value: 7},
{name: '华为', value: 8},
]},
]
})
</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>
```
:::

View File

@ -1,107 +1,107 @@
## 自动换行
:::tip
当需要选择很多选项时, 横向滚动满足不了你的需求, 可以开启自动换行
:::
### 开启换行
:::demo `autoRow` = `true`
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
toolbar:{
show: true,
},
autoRow: true,
height: '500px',
data: [
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4, selected: true, disabled: true},
{name: '香蕉2', value: 5, selected: true},
{name: '葡萄2', value: 6},
]
})
</script>
```
:::
### Layui风格
前面的label居中 需要 **自行** 加一段css, 这里就没有内置到插件中了, 避免样式污染, 当前或许你有更好的css解决方案 ^_^
```css
.layui-form-pane .layui-form-label{
display: flex;
align-items: center;
justify-content: center;
}
```
:::demo
```html
<form class="layui-form layui-form-pane xm-select-demo ly-label-center" action="">
<div class="layui-form-item" pane>
<label class="layui-form-label">居中风格</label>
<div class="layui-input-block">
<div id="demo2"></div>
</div>
</div>
</form>
<form class="layui-form layui-form-pane xm-select-demo" action="">
<div class="layui-form-item" pane>
<label class="layui-form-label">默认风格</label>
<div class="layui-input-block">
<div id="demo3"></div>
</div>
</div>
</form>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
toolbar:{
show: true,
},
filterable: true,
height: '500px',
autoRow: true,
data: [
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4, selected: true, disabled: true},
{name: '香蕉2', value: 5, selected: true},
{name: '葡萄2', value: 6},
]
})
var demo3 = xmSelect.render({
el: '#demo3',
toolbar:{
show: true,
},
filterable: true,
height: '500px',
autoRow: true,
data: [
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4, selected: true, disabled: true},
{name: '香蕉2', value: 5, selected: true},
{name: '葡萄2', value: 6},
]
})
</script>
```
:::
## 自动换行
:::tip
当需要选择很多选项时, 横向滚动满足不了你的需求, 可以开启自动换行
:::
### 开启换行
:::demo `autoRow` = `true`
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
toolbar:{
show: true,
},
autoRow: true,
height: '500px',
data: [
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4, selected: true, disabled: true},
{name: '香蕉2', value: 5, selected: true},
{name: '葡萄2', value: 6},
]
})
</script>
```
:::
### Layui风格
前面的label居中 需要 **自行** 加一段css, 这里就没有内置到插件中了, 避免样式污染, 当前或许你有更好的css解决方案 ^_^
```css
.layui-form-pane .layui-form-label{
display: flex;
align-items: center;
justify-content: center;
}
```
:::demo
```html
<form class="layui-form layui-form-pane xm-select-demo ly-label-center" action="">
<div class="layui-form-item" pane>
<label class="layui-form-label">居中风格</label>
<div class="layui-input-block">
<div id="demo2"></div>
</div>
</div>
</form>
<form class="layui-form layui-form-pane xm-select-demo" action="">
<div class="layui-form-item" pane>
<label class="layui-form-label">默认风格</label>
<div class="layui-input-block">
<div id="demo3"></div>
</div>
</div>
</form>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
toolbar:{
show: true,
},
filterable: true,
height: '500px',
autoRow: true,
data: [
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4, selected: true, disabled: true},
{name: '香蕉2', value: 5, selected: true},
{name: '葡萄2', value: 6},
]
})
var demo3 = xmSelect.render({
el: '#demo3',
toolbar:{
show: true,
},
filterable: true,
height: '500px',
autoRow: true,
data: [
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4, selected: true, disabled: true},
{name: '香蕉2', value: 5, selected: true},
{name: '葡萄2', value: 6},
]
})
</script>
```
:::

View File

@ -1,76 +1,76 @@
## 隐藏图标
### 隐藏单选图标
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
radio: true,
clickClose: true,
model: {
icon: 'hidden',
label: {
type: 'text'
}
},
data: [
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4},
]
})
var demo2 = xmSelect.render({
el: '#demo2',
radio: true,
clickClose: true,
theme: {
color: '#5FB878',
},
model: {
icon: 'hidden',
label: {
type: 'text'
}
},
data: [
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4},
]
})
</script>
```
:::
### 隐藏多选图标
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
model: {
icon: 'hidden',
},
data: [
{name: '张三1', value: 1, selected: true, disabled: true},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4},
]
})
</script>
```
:::
## 隐藏图标
### 隐藏单选图标
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
radio: true,
clickClose: true,
model: {
icon: 'hidden',
label: {
type: 'text'
}
},
data: [
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4},
]
})
var demo2 = xmSelect.render({
el: '#demo2',
radio: true,
clickClose: true,
theme: {
color: '#5FB878',
},
model: {
icon: 'hidden',
label: {
type: 'text'
}
},
data: [
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4},
]
})
</script>
```
:::
### 隐藏多选图标
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
model: {
icon: 'hidden',
},
data: [
{name: '张三1', value: 1, selected: true, disabled: true},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4},
]
})
</script>
```
:::

View File

@ -1,61 +1,61 @@
## 尺寸
### 四种尺寸变换
:::demo `large`, `medium`, `small`, `mini`
```html
<div id="demo1" class="xm-select-size"></div>
<div id="demo2" class="xm-select-size"></div>
<div id="demo3" class="xm-select-size"></div>
<div id="demo4" class="xm-select-size"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
size: 'large',
data: [
{name: 'large', value: 1, selected: true},
{name: '李四1', value: 2},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4},
]
})
var demo2 = xmSelect.render({
el: '#demo2',
size: 'medium',
data: [
{name: 'medium', value: 1, selected: true},
{name: '李四1', value: 2},
{name: '默认尺寸', value: 3, selected: true, disabled: true},
{name: '苹果2', value: 4},
]
})
var demo3 = xmSelect.render({
el: '#demo3',
size: 'small',
data: [
{name: 'small', value: 1, selected: true},
{name: '李四1', value: 2},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4},
]
})
var demo4 = xmSelect.render({
el: '#demo4',
size: 'mini',
data: [
{name: 'mini', value: 1, selected: true},
{name: '李四1', value: 2},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4},
]
})
</script>
```
:::
## 尺寸
### 四种尺寸变换
:::demo `large`, `medium`, `small`, `mini`
```html
<div id="demo1" class="xm-select-size"></div>
<div id="demo2" class="xm-select-size"></div>
<div id="demo3" class="xm-select-size"></div>
<div id="demo4" class="xm-select-size"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
size: 'large',
data: [
{name: 'large', value: 1, selected: true},
{name: '李四1', value: 2},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4},
]
})
var demo2 = xmSelect.render({
el: '#demo2',
size: 'medium',
data: [
{name: 'medium', value: 1, selected: true},
{name: '李四1', value: 2},
{name: '默认尺寸', value: 3, selected: true, disabled: true},
{name: '苹果2', value: 4},
]
})
var demo3 = xmSelect.render({
el: '#demo3',
size: 'small',
data: [
{name: 'small', value: 1, selected: true},
{name: '李四1', value: 2},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4},
]
})
var demo4 = xmSelect.render({
el: '#demo4',
size: 'mini',
data: [
{name: 'mini', value: 1, selected: true},
{name: '李四1', value: 2},
{name: '王五1', value: 3, disabled: true},
{name: '苹果2', value: 4},
]
})
</script>
```
:::

View File

@ -1,88 +1,88 @@
## 警告
### 警告提示
放下她, 让我来!!! 默认颜色`#e54d42`, 多选上限的样色
```
/*
* COLOR: 自定义颜色, 默认是 options.theme.maxColor的颜色
* SUSTAIN: 是否持续显示, 默认为false
*/
xmSelectObj.warning(COLOR, SUSTAIN);
```
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<button class="btn" id="demo1-warning">警告</button>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
})
document.getElementById('demo1-warning').onclick = function(){
demo1.warning();
}
</script>
```
:::
### 自定义闪烁颜色
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<button class="btn" id="demo2-warning">警告</button>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
})
document.getElementById('demo2-warning').onclick = function(){
demo2.warning('#6739b6');
}
</script>
```
:::
### 持续显示
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<button class="btn" id="demo3-warning">警告</button>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
})
document.getElementById('demo3-warning').onclick = function(){
demo3.warning('#6739b6', true);
}
</script>
```
:::
## 警告
### 警告提示
放下她, 让我来!!! 默认颜色`#e54d42`, 多选上限的样色
```
/*
* COLOR: 自定义颜色, 默认是 options.theme.maxColor的颜色
* SUSTAIN: 是否持续显示, 默认为false
*/
xmSelectObj.warning(COLOR, SUSTAIN);
```
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<button class="btn" id="demo1-warning">警告</button>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
})
document.getElementById('demo1-warning').onclick = function(){
demo1.warning();
}
</script>
```
:::
### 自定义闪烁颜色
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<button class="btn" id="demo2-warning">警告</button>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
})
document.getElementById('demo2-warning').onclick = function(){
demo2.warning('#6739b6');
}
</script>
```
:::
### 持续显示
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<button class="btn" id="demo3-warning">警告</button>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
})
document.getElementById('demo3-warning').onclick = function(){
demo3.warning('#6739b6', true);
}
</script>
```
:::

View File

@ -1,90 +1,90 @@
## 禁用
### 渲染禁用
```
xmSelect.render({
//...
disabled: true
})
```
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
disabled: true,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
})
</script>
```
:::
### 动态启用禁用
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<button class="btn" id="demo21">禁用</button>
<button class="btn" id="demo22">启用</button>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
})
document.getElementById('demo21').onclick = function(){
demo2.update({ disabled: true });
}
document.getElementById('demo22').onclick = function(){
demo2.update({ disabled: false });
}
</script>
```
:::
### 选完`张三`后禁用
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<button class="btn" id="demo3-disabled">启用</button>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
],
on({ arr, change, isAdd }){
var hasZS = change.find(item => item.name === '张三');
if(isAdd && hasZS){
demo3.update({ disabled: true });
}
}
})
//没有做不到, 只有想不到, 把多选玩出花来吧
document.getElementById('demo3-disabled').onclick = function(){
demo3.update({ disabled: false });
}
</script>
```
:::
## 禁用
### 渲染禁用
```
xmSelect.render({
//...
disabled: true
})
```
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
disabled: true,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
})
</script>
```
:::
### 动态启用禁用
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<button class="btn" id="demo21">禁用</button>
<button class="btn" id="demo22">启用</button>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
})
document.getElementById('demo21').onclick = function(){
demo2.update({ disabled: true });
}
document.getElementById('demo22').onclick = function(){
demo2.update({ disabled: false });
}
</script>
```
:::
### 选完`张三`后禁用
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<button class="btn" id="demo3-disabled">启用</button>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
],
on({ arr, change, isAdd }){
var hasZS = change.find(item => item.name === '张三');
if(isAdd && hasZS){
demo3.update({ disabled: true });
}
}
})
//没有做不到, 只有想不到, 把多选玩出花来吧
document.getElementById('demo3-disabled').onclick = function(){
demo3.update({ disabled: false });
}
</script>
```
:::

View File

@ -1,78 +1,78 @@
## 创建条目
### 搜索不存在则创建条目
```
//想创建就必须要开启本地搜索
xmSelect.render({
//...
filterable: true,
create: function(val){
//返回一个创建成功的对象, val是搜索的数据
return {
name: '创建-' + val,
value: val
}
}
})
```
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
filterable: true,
create: function(val){
return {
name: '创建-' + val,
value: val
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
})
</script>
```
:::
### 单选创建
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo2',
radio: true,
clickClose: true,
filterable: true,
create: function(val){
return {
name: '创建-' + val,
value: val
}
},
model: {
icon: 'hidden',
label: {
type: 'text',
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
## 创建条目
### 搜索不存在则创建条目
```
//想创建就必须要开启本地搜索
xmSelect.render({
//...
filterable: true,
create: function(val){
//返回一个创建成功的对象, val是搜索的数据
return {
name: '创建-' + val,
value: val
}
}
})
```
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
filterable: true,
create: function(val){
return {
name: '创建-' + val,
value: val
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
})
</script>
```
:::
### 单选创建
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo2',
radio: true,
clickClose: true,
filterable: true,
create: function(val){
return {
name: '创建-' + val,
value: val
}
},
model: {
icon: 'hidden',
label: {
type: 'text',
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::

View File

@ -1,104 +1,104 @@
## 赋值与取值
### 给多选赋值
函数`setValue(array)`, 动态赋值多选选中的数据, array可以是value数组, 也可以是完整的object数组
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<br/><br/>
<button class="btn" id="demo1-test1">赋值张三</button>
<button class="btn" id="demo1-test2">赋值张三(value方式)</button>
<button class="btn" id="demo1-test3">追加赋值李四</button>
<br/><br/>
<button class="btn" id="demo1-test4">清除李四</button>
<button class="btn" id="demo1-test5">清空</button>
<pre id="demo1-result"></pre>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
document.getElementById('demo1-test1').onclick = function(){
demo1.setValue([
{name: '张三', value: 1},
])
};
document.getElementById('demo1-test2').onclick = function(){
demo1.setValue([ 1 ])
};
document.getElementById('demo1-test3').onclick = function(){
demo1.append([ 2 ]);
};
document.getElementById('demo1-test4').onclick = function(){
demo1.delete([ 2 ])
};
document.getElementById('demo1-test5').onclick = function(){
demo1.setValue([ ])
};
</script>
```
:::
### 取值
函数`getValue(type)`, type类型 name, nameStr, value, valueStr
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<button class="btn" id="demo2-getValue">获取选中值</button>
<br/><br/>
<button class="btn" id="name">获取name数组</button>
<button class="btn" id="nameStr">获取name字符串</button>
<button class="btn" id="value">获取value数组</button>
<button class="btn" id="valueStr">获取value字符串</button>
<pre id="demo2-value"></pre>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
document.getElementById('demo2-getValue').onclick = function(){
//获取当前多选选中的值
var selectArr = demo2.getValue();
document.getElementById('demo2-value').innerHTML = `\ndemo2.getValue()\n\n` + JSON.stringify(selectArr, null, 2);
}
var types = ['name', 'nameStr', 'value', 'valueStr'];
types.forEach(function(type){
document.getElementById(type).onclick = function(){
//获取当前多选选中的值
var selectArr = demo2.getValue(type);
document.getElementById('demo2-value').innerHTML = `\ndemo2.getValue('${type}')\n\n` + JSON.stringify(selectArr, null, 2);
}
});
</script>
```
:::
## 赋值与取值
### 给多选赋值
函数`setValue(array)`, 动态赋值多选选中的数据, array可以是value数组, 也可以是完整的object数组
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<br/><br/>
<button class="btn" id="demo1-test1">赋值张三</button>
<button class="btn" id="demo1-test2">赋值张三(value方式)</button>
<button class="btn" id="demo1-test3">追加赋值李四</button>
<br/><br/>
<button class="btn" id="demo1-test4">清除李四</button>
<button class="btn" id="demo1-test5">清空</button>
<pre id="demo1-result"></pre>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
document.getElementById('demo1-test1').onclick = function(){
demo1.setValue([
{name: '张三', value: 1},
])
};
document.getElementById('demo1-test2').onclick = function(){
demo1.setValue([ 1 ])
};
document.getElementById('demo1-test3').onclick = function(){
demo1.append([ 2 ]);
};
document.getElementById('demo1-test4').onclick = function(){
demo1.delete([ 2 ])
};
document.getElementById('demo1-test5').onclick = function(){
demo1.setValue([ ])
};
</script>
```
:::
### 取值
函数`getValue(type)`, type类型 name, nameStr, value, valueStr
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<button class="btn" id="demo2-getValue">获取选中值</button>
<br/><br/>
<button class="btn" id="name">获取name数组</button>
<button class="btn" id="nameStr">获取name字符串</button>
<button class="btn" id="value">获取value数组</button>
<button class="btn" id="valueStr">获取value字符串</button>
<pre id="demo2-value"></pre>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
document.getElementById('demo2-getValue').onclick = function(){
//获取当前多选选中的值
var selectArr = demo2.getValue();
document.getElementById('demo2-value').innerHTML = `\ndemo2.getValue()\n\n` + JSON.stringify(selectArr, null, 2);
}
var types = ['name', 'nameStr', 'value', 'valueStr'];
types.forEach(function(type){
document.getElementById(type).onclick = function(){
//获取当前多选选中的值
var selectArr = demo2.getValue(type);
document.getElementById('demo2-value').innerHTML = `\ndemo2.getValue('${type}')\n\n` + JSON.stringify(selectArr, null, 2);
}
});
</script>
```
:::

View File

@ -1,50 +1,50 @@
## 表单提交
### 默认表单提交
:::demo
```html
<form>
<div id="demo1" class="xm-select-demo"></div>
<button class="btn" type="submit">提交</button>
</form>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 修改name
:::demo
```html
<form>
<div id="demo2" class="xm-select-demo"></div>
<button class="btn" type="submit">提交</button>
</form>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
name: 'lalalalalala',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
## 表单提交
### 默认表单提交
:::demo
```html
<form>
<div id="demo1" class="xm-select-demo"></div>
<button class="btn" type="submit">提交</button>
</form>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 修改name
:::demo
```html
<form>
<div id="demo2" class="xm-select-demo"></div>
<button class="btn" type="submit">提交</button>
</form>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
name: 'lalalalalala',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::

View File

@ -9,65 +9,65 @@
<table id="demo" lay-filter="test"></table>
<script>
layui.use('table', function() {
var table = layui.table;
//第一个实例
table.render({
elem: '#demo',
page: true, //开启分页
height: 500,
cols: [
[ //表头
{ field: 'id', title: 'ID', width: 80, sort: true },
{ field: 'username', title: '用户名', width: 80 },
{ field: 'sex', title: '性别', width: 80, sort: true },
{ field: 'city', title: '城市', width: 80 },
{ field: 'sign', title: '爱好', width: 200, templet: function(d){
return '<div id="XM-' + d.id + '" ></div>'
} },
{ field: 'experience', title: '积分', width: 80, sort: true },
{ field: 'score', title: '评分', width: 80, sort: true },
{ field: 'classify', title: '职业', width: 80 },
{ field: 'wealth', title: '财富', width: 135, sort: true }
]
],
data: [
{"id":10000,"username":"user-0","sex":"女","city":"城市-0","sign":"签名-0","experience":255,"logins":24,"wealth":82830700,"classify":"作家","score":57},
{"id":10001,"username":"user-1","sex":"男","city":"城市-1","sign":"签名-1","experience":884,"logins":58,"wealth":64928690,"classify":"词人","score":27},
{"id":10002,"username":"user-2","sex":"女","city":"城市-2","sign":"签名-2","experience":650,"logins":77,"wealth":6298078,"classify":"酱油","score":31},
{"id":10003,"username":"user-3","sex":"女","city":"城市-3","sign":"签名-3","experience":362,"logins":157,"wealth":37117017,"classify":"诗人","score":68},
{"id":10004,"username":"user-4","sex":"男","city":"城市-4","sign":"签名-4","experience":807,"logins":51,"wealth":76263262,"classify":"作家","score":6},
{"id":10005,"username":"user-5","sex":"女","city":"城市-5","sign":"签名-5","experience":173,"logins":68,"wealth":60344147,"classify":"作家","score":87},
{"id":10006,"username":"user-6","sex":"女","city":"城市-6","sign":"签名-6","experience":982,"logins":37,"wealth":57768166,"classify":"作家","score":34},
{"id":10007,"username":"user-7","sex":"男","city":"城市-7","sign":"签名-7","experience":727,"logins":150,"wealth":82030578,"classify":"作家","score":28},
{"id":10008,"username":"user-8","sex":"男","city":"城市-8","sign":"签名-8","experience":951,"logins":133,"wealth":16503371,"classify":"词人","score":14},
{"id":10009,"username":"user-9","sex":"女","city":"城市-9","sign":"签名-9","experience":484,"logins":25,"wealth":86801934,"classify":"词人","score":75}
],
done: function(res){
//修改一些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.height = 'auto';
}
//渲染多选
res.data.forEach(item => {
var xm = xmSelect.render({
el: '#XM-' + item.id,
autoRow: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
item.__xm = xm;
})
}
});
layui.use('table', function() {
var table = layui.table;
//第一个实例
table.render({
elem: '#demo',
page: true, //开启分页
height: 500,
cols: [
[ //表头
{ field: 'id', title: 'ID', width: 80, sort: true },
{ field: 'username', title: '用户名', width: 80 },
{ field: 'sex', title: '性别', width: 80, sort: true },
{ field: 'city', title: '城市', width: 80 },
{ field: 'sign', title: '爱好', width: 200, templet: function(d){
return '<div id="XM-' + d.id + '" ></div>'
} },
{ field: 'experience', title: '积分', width: 80, sort: true },
{ field: 'score', title: '评分', width: 80, sort: true },
{ field: 'classify', title: '职业', width: 80 },
{ field: 'wealth', title: '财富', width: 135, sort: true }
]
],
data: [
{"id":10000,"username":"user-0","sex":"女","city":"城市-0","sign":"签名-0","experience":255,"logins":24,"wealth":82830700,"classify":"作家","score":57},
{"id":10001,"username":"user-1","sex":"男","city":"城市-1","sign":"签名-1","experience":884,"logins":58,"wealth":64928690,"classify":"词人","score":27},
{"id":10002,"username":"user-2","sex":"女","city":"城市-2","sign":"签名-2","experience":650,"logins":77,"wealth":6298078,"classify":"酱油","score":31},
{"id":10003,"username":"user-3","sex":"女","city":"城市-3","sign":"签名-3","experience":362,"logins":157,"wealth":37117017,"classify":"诗人","score":68},
{"id":10004,"username":"user-4","sex":"男","city":"城市-4","sign":"签名-4","experience":807,"logins":51,"wealth":76263262,"classify":"作家","score":6},
{"id":10005,"username":"user-5","sex":"女","city":"城市-5","sign":"签名-5","experience":173,"logins":68,"wealth":60344147,"classify":"作家","score":87},
{"id":10006,"username":"user-6","sex":"女","city":"城市-6","sign":"签名-6","experience":982,"logins":37,"wealth":57768166,"classify":"作家","score":34},
{"id":10007,"username":"user-7","sex":"男","city":"城市-7","sign":"签名-7","experience":727,"logins":150,"wealth":82030578,"classify":"作家","score":28},
{"id":10008,"username":"user-8","sex":"男","city":"城市-8","sign":"签名-8","experience":951,"logins":133,"wealth":16503371,"classify":"词人","score":14},
{"id":10009,"username":"user-9","sex":"女","city":"城市-9","sign":"签名-9","experience":484,"logins":25,"wealth":86801934,"classify":"词人","score":75}
],
done: function(res){
//修改一些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.height = 'auto';
}
//渲染多选
res.data.forEach(item => {
var xm = xmSelect.render({
el: '#XM-' + item.id,
autoRow: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
item.__xm = xm;
})
}
});
});

View File

@ -1,36 +1,36 @@
## 远程搜索
:::demo
```html
<div id="demo1"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
autoRow: true,
toolbar: { show: true },
filterable: true,
remoteSearch: true,
remoteMethod: function(val, cb, show){
//这里如果val为空, 则不触发搜索
if(!val){
return cb([]);
}
//这里引入了一个第三方插件axios, 相当于$.ajax
axios({
method: 'get',
url: 'https://www.fastmock.site/mock/98228b1f16b7e5112d6c0c87921eabc1/xmSelect/search',
params: {
keyword: val,
}
}).then(response => {
var res = response.data;
cb(res.data)
}).catch(err => {
cb([]);
});
},
})
</script>
```
:::
## 远程搜索
:::demo
```html
<div id="demo1"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
autoRow: true,
toolbar: { show: true },
filterable: true,
remoteSearch: true,
remoteMethod: function(val, cb, show){
//这里如果val为空, 则不触发搜索
if(!val){
return cb([]);
}
//这里引入了一个第三方插件axios, 相当于$.ajax
axios({
method: 'get',
url: 'https://www.fastmock.site/mock/98228b1f16b7e5112d6c0c87921eabc1/xmSelect/search',
params: {
keyword: val,
}
}).then(response => {
var res = response.data;
cb(res.data)
}).catch(err => {
cb([]);
});
},
})
</script>
```
:::

View File

@ -1,56 +1,56 @@
## 动态数据
### 本地数据动态赋值
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: []
})
demo1.update({
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3, disabled: true},
]
})
</script>
```
:::
### 远程数据动态赋值
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
toolbar: {show: true},
data: []
})
axios({
method: 'get',
url: 'https://www.fastmock.site/mock/98228b1f16b7e5112d6c0c87921eabc1/xmSelect/search',
}).then(response => {
var res = response.data;
demo2.update({
data: res.data,
autoRow: true,
})
});
</script>
```
:::
## 动态数据
### 本地数据动态赋值
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: []
})
demo1.update({
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3, disabled: true},
]
})
</script>
```
:::
### 远程数据动态赋值
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
toolbar: {show: true},
data: []
})
axios({
method: 'get',
url: 'https://www.fastmock.site/mock/98228b1f16b7e5112d6c0c87921eabc1/xmSelect/search',
}).then(response => {
var res = response.data;
demo2.update({
data: res.data,
autoRow: true,
})
});
</script>
```
:::

View File

@ -1,33 +1,33 @@
## 远程搜索
### layer弹出框
:::demo
```html
<button class="btn" id="demo1-btn">弹出多选</button>
<script>
document.getElementById('demo1-btn').onclick = function(){
layer.open({
type: 1,
title: '多选',
content: '<div id="demo1" class="xm-select-demo-alert"></div>',
success: function(layero, index){
//这里因为内容过少, 会被遮挡, 所以简单修改了下样式
document.getElementById('layui-layer' + index).getElementsByClassName('layui-layer-content')[0].style.overflow = 'unset';
//渲染多选
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, disabled: true},
{name: '王五', value: 3},
]
})
}
});
}
</script>
```
:::
## 远程搜索
### layer弹出框
:::demo
```html
<button class="btn" id="demo1-btn">弹出多选</button>
<script>
document.getElementById('demo1-btn').onclick = function(){
layer.open({
type: 1,
title: '多选',
content: '<div id="demo1" class="xm-select-demo-alert"></div>',
success: function(layero, index){
//这里因为内容过少, 会被遮挡, 所以简单修改了下样式
document.getElementById('layui-layer' + index).getElementsByClassName('layui-layer-content')[0].style.overflow = 'unset';
//渲染多选
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, disabled: true},
{name: '王五', value: 3},
]
})
}
});
}
</script>
```
:::

View File

@ -1,79 +1,79 @@
## 获取实例对象
### 全局方法 get
:::warning
get方法默认返回的是符合条件的数组,
:::
```
//所有
xmSelect.get();
//字符串
xmSelect.get('#demo2');
//正则
xmSelect.get(/demo.*/);
//过滤方法
xmSelect.get((el) => {
return el == '#demo1' || el == '#xm3'
});
//获取单实例
xmSelect.get('#demo2', true);
```
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<div id="demo2" class="xm-select-demo"></div>
<div id="xm3" class="xm-select-demo"></div>
<div><button class="btn" id="btn1">get(所有)</button></div>
<div><button class="btn" id="btn2">get(字符串)</button></div>
<div><button class="btn" id="btn3">get(正则)</button></div>
<div><button class="btn" id="btn4">get(过滤方法)</button></div>
<div><button class="btn" id="btn5">get(获取单实例)</button></div>
<script>
['#demo1', '#demo2', '#xm3'].forEach((el, index) => {
xmSelect.render({
el,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
});
});
document.getElementById('btn1').onclick = function(){
var xmList = xmSelect.get();
alert('当前页面多选个数: ' + xmList.length)
}
document.getElementById('btn2').onclick = function(){
var xmList = xmSelect.get('#demo2');
alert('获取 #demo2 实例: ' + xmList.length)
}
document.getElementById('btn3').onclick = function(){
var xmList = xmSelect.get(/demo.*/);
alert('获取匹配正则 /demo.*/ 的实例: ' + xmList.length)
}
document.getElementById('btn4').onclick = function(){
var xmList = xmSelect.get((el) => {
return el == '#demo1' || el == '#xm3'
});
alert('自定义方法的实例: ' + xmList.length)
}
document.getElementById('btn5').onclick = function(){
var demo2 = xmSelect.get('#demo2', true);
alert('获取单实例#demo2当前选中值: ' + demo2.getValue('nameStr'));
}
</script>
```
:::
## 获取实例对象
### 全局方法 get
:::warning
get方法默认返回的是符合条件的数组,
:::
```
//所有
xmSelect.get();
//字符串
xmSelect.get('#demo2');
//正则
xmSelect.get(/demo.*/);
//过滤方法
xmSelect.get((el) => {
return el == '#demo1' || el == '#xm3'
});
//获取单实例
xmSelect.get('#demo2', true);
```
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<div id="demo2" class="xm-select-demo"></div>
<div id="xm3" class="xm-select-demo"></div>
<div><button class="btn" id="btn1">get(所有)</button></div>
<div><button class="btn" id="btn2">get(字符串)</button></div>
<div><button class="btn" id="btn3">get(正则)</button></div>
<div><button class="btn" id="btn4">get(过滤方法)</button></div>
<div><button class="btn" id="btn5">get(获取单实例)</button></div>
<script>
['#demo1', '#demo2', '#xm3'].forEach((el, index) => {
xmSelect.render({
el,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
});
});
document.getElementById('btn1').onclick = function(){
var xmList = xmSelect.get();
alert('当前页面多选个数: ' + xmList.length)
}
document.getElementById('btn2').onclick = function(){
var xmList = xmSelect.get('#demo2');
alert('获取 #demo2 实例: ' + xmList.length)
}
document.getElementById('btn3').onclick = function(){
var xmList = xmSelect.get(/demo.*/);
alert('获取匹配正则 /demo.*/ 的实例: ' + xmList.length)
}
document.getElementById('btn4').onclick = function(){
var xmList = xmSelect.get((el) => {
return el == '#demo1' || el == '#xm3'
});
alert('自定义方法的实例: ' + xmList.length)
}
document.getElementById('btn5').onclick = function(){
var demo2 = xmSelect.get('#demo2', true);
alert('获取单实例#demo2当前选中值: ' + demo2.getValue('nameStr'));
}
</script>
```
:::

View File

@ -1,61 +1,61 @@
## 批量操作
### 批量操作已渲染实例
```
//filter, 同get方法
//method, 需要执行的方法
//args, 执行方法的参数
xmSelect.batch(filter, method, ...args);
```
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<div id="demo2" class="xm-select-demo"></div>
<div id="xm3" class="xm-select-demo"></div>
<div><button class="btn" id="btn1">batch禁用</button></div>
<div><button class="btn" id="btn2">batch启用</button></div>
<div><button class="btn" id="btn3">batch警告</button></div>
<div><button class="btn" id="btn4">batch获取已选中数据</button></div>
<pre id="demo-value"></pre>
<script>
['#demo1', '#demo2', '#xm3'].forEach((el, index) => {
xmSelect.render({
el,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
});
});
document.getElementById('btn1').onclick = function(){
xmSelect.batch('', 'update', {
disabled: true
});
}
document.getElementById('btn2').onclick = function(){
xmSelect.batch('', 'update', {
disabled: false
});
}
document.getElementById('btn3').onclick = function(){
xmSelect.batch(/demo.*/, 'warning', '#F00', true);
}
document.getElementById('btn4').onclick = function(){
var selectArr = xmSelect.batch(null, 'getValue', 'name');
document.getElementById('demo-value').innerHTML = JSON.stringify(selectArr, null, 2);
}
</script>
```
:::
## 批量操作
### 批量操作已渲染实例
```
//filter, 同get方法
//method, 需要执行的方法
//args, 执行方法的参数
xmSelect.batch(filter, method, ...args);
```
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<div id="demo2" class="xm-select-demo"></div>
<div id="xm3" class="xm-select-demo"></div>
<div><button class="btn" id="btn1">batch禁用</button></div>
<div><button class="btn" id="btn2">batch启用</button></div>
<div><button class="btn" id="btn3">batch警告</button></div>
<div><button class="btn" id="btn4">batch获取已选中数据</button></div>
<pre id="demo-value"></pre>
<script>
['#demo1', '#demo2', '#xm3'].forEach((el, index) => {
xmSelect.render({
el,
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3, disabled: true},
]
});
});
document.getElementById('btn1').onclick = function(){
xmSelect.batch('', 'update', {
disabled: true
});
}
document.getElementById('btn2').onclick = function(){
xmSelect.batch('', 'update', {
disabled: false
});
}
document.getElementById('btn3').onclick = function(){
xmSelect.batch(/demo.*/, 'warning', '#F00', true);
}
document.getElementById('btn4').onclick = function(){
var selectArr = xmSelect.batch(null, 'getValue', 'name');
document.getElementById('demo-value').innerHTML = JSON.stringify(selectArr, null, 2);
}
</script>
```
:::

View File

@ -1,53 +1,75 @@
## 下拉自定义
### 下拉表格
至于能干什么, 就看你们的想象了~~
:::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>
```
:::
## 下拉自定义
### 下拉表格
至于能干什么, 就看你们的想象了~~
:::demo
```html
<div id="demo1"></div>
<script>
//先渲染多选
var demo1 = xmSelect.render({
el: '#demo1',
prop: {
name: 'username',
value: 'username',
},
content: `
<table class="layui-table" lay-filter="demo">
<thead>
<tr>
<th lay-data="{field:'username', width:80}">昵称</th>
<th lay-data="{field:'experience', width:50, sort:true}">积分</th>
<th lay-data="{field:'sign', width: 200}">签名</th>
</tr>
</thead>
<tbody>
<tr>
<td>贤心1</td>
<td>66</td>
<td>人生就像是一场修行a</td>
</tr>
<tr>
<td>贤心2</td>
<td>88</td>
<td>人生就像是一场修行b</td>
</tr>
<tr>
<td>贤心3</td>
<td>33</td>
<td>人生就像是一场修行c</td>
</tr>
</tbody>
</table>
`,
height: 'auto',
})
layui.table.init('demo', {
done: function(res){
demo1.update({ data: res.data })
}
}).on('row(demo)', function(obj){
var values = demo1.getValue();
var item = obj.data;
var has = values.find(function(i){
return i.username === item.username
})
if(has){
demo1.delete([ item ]);
}else{
demo1.append([ item ]);
}
})
</script>
```
:::

View File

@ -1,8 +1,23 @@
## 下拉树
### eleTree
### tree
结合 `layui` 插件中心的 `eleTree`, <a href='https://fly.layui.com/extend/eleTree/' target='_blank'>传送门</a>
默认配置
```
tree: {
//是否显示树状结构
show: false,
//是否展示三角图标
showFolderIcon: true,
//是否显示虚线
showLine: false,
//间距
indent: 20,
//默认展开节点的数组
expandedKeys: [],
},
```
:::demo
@ -10,60 +25,81 @@
<div id="demo1" class="xm-select-demo"></div>
<br/>
<div class="layui-form">
<input type="checkbox" name="showFolderIcon" lay-filter="showFolderIcon" lay-skin="primary" title="是否展示三角图标" checked>
<input type="checkbox" name="showLine" lay-filter="showLine" lay-skin="primary" title="是否显示虚线" checked>
</div>
<div style="margin-top: 20px">间距</div>
<div id="slideTest1"></div>
<script>
//先渲染多选
layui.form.render();
layui.form.on('checkbox(showFolderIcon)', function(data){
demo1.update({
tree: {
showFolderIcon: data.elem.checked
}
})
});
layui.form.on('checkbox(showLine)', function(data){
demo1.update({
tree: {
showLine: data.elem.checked
}
})
});
layui.slider.render({
elem: '#slideTest1',
min: 10,
max: 100,
showstep: true,
input: true,
tips: true,
value: 20,
change: function(value){
demo1.update({
tree: {
indent: value
}
})
}
});
var demo1 = xmSelect.render({
el: '#demo1',
theme: {
color: '#5FB878',
},
content: '<div id="ele1" lay-filter="ele1"></div>',
el: '#demo1',
autoRow: true,
tree: {
show: true,
showFolderIcon: true,
showLine: true,
indent: 20,
expandedKeys: [ -3 ],
},
height: 'auto',
data(){
return [
{name: '销售员', value: -1, disabled: true, children: [
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3, disabled: true},
]},
{name: '奖品', value: -2, 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},
]},
]
}
})
//渲染自定义内容
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: "郑州市" },
{ id: 7, label: "开封市" },
{ id: 8, label: "焦作市" },
{ id: 9, 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>
```
:::

View File

@ -1,65 +1,85 @@
## 下拉树
## 下拉日期多选
### laydate
### layuiTree
```
//css调整部分
xm-select .scroll-body{
text-align: center;
}
结合 `layui``tree`, <a href='https://www.layui.com/doc/modules/tree.html' target='_blank'>传送门</a>
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var data = [
{ id: 1, title: "安徽省", children: [
{ id: 2, title: "马鞍山市", disabled: true, children: [
{ id: 3, title: "和县" },
{ id: 4, title: "花山区" }
]}
]},
{ id: 5, title: "河南省", children: [
{ id: 6, title: "郑州市" },
{ id: 7, title: "开封市" },
{ id: 8, title: "焦作市" },
{ id: 9, title: "洛阳市" },
]}
]
//先渲染多选
var demo1 = xmSelect.render({
el: '#demo1',
theme: {
color: '#5FB878',
},
content: '<div id="layuiTree"></div>',
data: data,
prop: {
name: 'title',
value: 'id',
}
```
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
content: '<div id="laydate" />',
height: 'auto',
autoRow: true,
on: function(data){
if(!data.isAdd){
dateSelect(demo1.getValue('value'));
}
}
})
//渲染自定义内容
var ele = layui.tree.render({
id: 'demoId',
elem: '#layuiTree',
data: data,
showCheckbox: true,
oncheck: function(obj){
var checkData = layui.tree.getChecked('demoId');
}
});
layui.laydate.render({
elem: '#laydate',
position: 'static',
showBottom: false,
format: 'yyyy-M-dd',
change: function(){
dateSelect(demo1.getValue('value'));
},
done: function(value){
console.log(value)
var values = demo1.getValue('value');
var index = values.findIndex(function(val){
return val === value
});
if(index != -1){
values.splice(index, 1);
}else{
values.push(value);
}
dateSelect(values);
demo1.update({
data: values.map(function(val){
return {
name: val,
value: val,
selected: true,
}
})
})
},
ready: removeAll,
})
//监听下拉多选的选择
demo1.update({
on({ arr, change, isAdd }){
if(isAdd === false){//监听取消
ele.setChecked(arr.map(item => item.id), true);
}
},
});
function removeAll(){
document.querySelectorAll('#laydate td[lay-ymd].layui-this').forEach(function(dom){
dom.classList.remove('layui-this');
});
}
</script>
```
:::
function dateSelect(values){
removeAll();
values.forEach(function(val){
var dom = document.querySelector('#laydate td[lay-ymd="'+val.replace(/-0([1-9])/g, '-$1')+'"]');
dom && dom.classList.add('layui-this');
});
}
//这里仅仅提供一个演示, 更多的想法由你自己来创造
</script>
```
:::

View File

@ -9,36 +9,36 @@
<script>
//先渲染多选
var demo1 = xmSelect.render({
el: '#demo1',
autoRow: true,
filterable: true,
toolbar: {show: true},
paging: true,
create: (val, data) => {
console.log(val, data)
return {
name: val,
value: val,
}
},
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},
]},
]
}
el: '#demo1',
autoRow: true,
tree: {
show: true,
expandedKeys: [-3],
},
height: 'auto',
on({ arr, change, isAdd }){
console.log(arr, change, isAdd)
},
data(){
return [
{name: '销售员', value: -1, disabled: true, children: [
{name: '张三1', value: 1, selected: true},
{name: '李四1', value: 2, selected: true},
{name: '王五1', value: 3, disabled: true},
]},
{name: '奖品', value: -2, children: [
{name: '奖品3', value: -3, children: [
{name: '苹果3', value: 14, selected: true, disabled: 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},
]},
]
}
})
</script>
```
:::

View File

@ -1,146 +1,146 @@
## es6语法说明
:::warning
文档中会存在es6语法, 这里简单说明一下, 其中`IE`不支持`es6`语法
:::
### 概览
- let const
- 模板字符串
- 对象中属性方法简写
- 箭头函数
- 解构
这里只是简单说明, 有兴趣可以看大神<a href="https://es6.ruanyifeng.com/" target="_blank">阮一峰的资料</a>
### let与const
```
//lES6 新增了let命令用来声明变量。它的用法类似于var但是所声明的变量只在let命令所在的代码块内有效。
{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1
//const声明一个只读的常量。一旦声明常量的值就不能改变。
const PI = 3.1415;
PI // 3.1415
PI = 3;
// TypeError: Assignment to constant variable.
```
### 模板字符串
```
//模板字符串template string是增强版的字符串用反引号`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
// 普通字符串
`In JavaScript '\n' is a line-feed.`
// 多行字符串
`In JavaScript this is
not legal.`
console.log(`string text line 1
string text line 2`);
// 字符串中嵌入变量
let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
```
### 对象中属性方法简写
```
//常规写法
var name = 'zs';
var obj = {
name: name,
run: function(){
console.log('haha');
}
}
//简写
let name = 'zs';
let obj = {
name,
run(){
console.log('haha');
}
}
```
### 箭头函数
```
//常规写法
setTimeout(function(){
//...
}, 1000);
//简写
setTimeout(() => {
//...
}, 1000);
```
### 解构
```
//假如现在有一个对象
let obj = {
name: 'zs',
age: 18,
address: 'beijing',
}
//正常获取name
var name = obj.name
//解构写法
let { name } = obj
//也可以多个
let { name, age, address } = obj;
//如果不存在也可以声明默认值
let { name, age, address, status = '1' } = obj;
//想添加一条属性
obj.status = '1';
//对象属性合并
var newObj = {
...obj,
status: '1'
}
//方法传参
function calc(data){
var a = data.a;
var b = data.b;
return a + b;
}
//解构传参
function calc({ a, b }){
return a + b;
}
```
至于更多的就自己去找学习资料吧
## es6语法说明
:::warning
文档中会存在es6语法, 这里简单说明一下, 其中`IE`不支持`es6`语法
:::
### 概览
- let const
- 模板字符串
- 对象中属性方法简写
- 箭头函数
- 解构
这里只是简单说明, 有兴趣可以看大神<a href="https://es6.ruanyifeng.com/" target="_blank">阮一峰的资料</a>
### let与const
```
//lES6 新增了let命令用来声明变量。它的用法类似于var但是所声明的变量只在let命令所在的代码块内有效。
{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1
//const声明一个只读的常量。一旦声明常量的值就不能改变。
const PI = 3.1415;
PI // 3.1415
PI = 3;
// TypeError: Assignment to constant variable.
```
### 模板字符串
```
//模板字符串template string是增强版的字符串用反引号`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
// 普通字符串
`In JavaScript '\n' is a line-feed.`
// 多行字符串
`In JavaScript this is
not legal.`
console.log(`string text line 1
string text line 2`);
// 字符串中嵌入变量
let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
```
### 对象中属性方法简写
```
//常规写法
var name = 'zs';
var obj = {
name: name,
run: function(){
console.log('haha');
}
}
//简写
let name = 'zs';
let obj = {
name,
run(){
console.log('haha');
}
}
```
### 箭头函数
```
//常规写法
setTimeout(function(){
//...
}, 1000);
//简写
setTimeout(() => {
//...
}, 1000);
```
### 解构
```
//假如现在有一个对象
let obj = {
name: 'zs',
age: 18,
address: 'beijing',
}
//正常获取name
var name = obj.name
//解构写法
let { name } = obj
//也可以多个
let { name, age, address } = obj;
//如果不存在也可以声明默认值
let { name, age, address, status = '1' } = obj;
//想添加一条属性
obj.status = '1';
//对象属性合并
var newObj = {
...obj,
status: '1'
}
//方法传参
function calc(data){
var a = data.a;
var b = data.b;
return a + b;
}
//解构传参
function calc({ a, b }){
return a + b;
}
```
至于更多的就自己去找学习资料吧

View File

@ -13,12 +13,12 @@
- [Fly社区交流贴](https://fly.layui.com/jie/57776/)
- QQ交流群: `660408068`
> 作者: maplemei, 热爱前端的Java程序猿, 如果喜欢作者的插件, 可以请作者吃雪糕 ^_^
<p>
<a href="javascript:;">
<img src="../assets/wx.jpg" alt="打赏" width="300">
</a>
> 作者: maplemei, 热爱前端的Java程序猿, 如果喜欢作者的插件, 可以请作者吃雪糕 ^_^
<p>
<a href="javascript:;">
<img src="../assets/wx.jpg" alt="打赏" width="300">
</a>
</p>
@ -52,19 +52,19 @@ $ npm install && npm run dev
<script>
var demo1 = xmSelect.render({
el: '#demo1',
language: 'zn',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
el: '#demo1',
language: 'zn',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
document.getElementById('demo1-getValue').onclick = function(){
//获取当前多选选中的值
var selectArr = demo1.getValue();
document.getElementById('demo1-value').innerHTML = JSON.stringify(selectArr, null, 2);
//获取当前多选选中的值
var selectArr = demo1.getValue();
document.getElementById('demo1-value').innerHTML = JSON.stringify(selectArr, null, 2);
}
</script>

View File

@ -1,218 +1,224 @@
## 配置项与方法
### 配置项
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------------- | ------------------------------ | --------------- | ------ | ------ |
| el | 渲染对象, css选择器 | string | - | - |
| language | 语言选择 | string | zn / en | zn |
| data | 显示的数据 | array | - | [ ] |
| content | 自定义下拉框html | string | - | - |
| initValue | 初始化选中的数据, 需要在data中存在 | array | - | null |
| tips | 默认提示, 类似于placeholder | string | - | 请选择 |
| empty | 空数据提示 | string | - | 暂无数据 |
| filterable | 是否开启搜索 | boolean | true / false | false |
| searchTips | 搜索提示 | string | - | 请选择 |
| delay | 搜索延迟 ms | int | - | 500 |
| filterMethod | 搜索回调函数 | function(val, item, index, prop) val: 当前搜索值, item: 每个option选项, index: 位置数据中的下标, prop: 定义key | - | - |
| filterDone | 搜索完成函数 | function(val, list) val: 当前搜索值, list: 过滤后的数据 | - | - |
| remoteSearch | 是否开启自定义搜索 (远程搜索)| boolean | true / false | false |
| remoteMethod | 自定义搜索回调函数 | function(val, cb, show) val: 当前搜索值, cb: 回调函数, 需要回调一个数组, 结构同data, show: 下拉框显示状态 | - | - |
| direction | 下拉方向| string | auto / up / down | auto |
| style | 自定义样式| object | - | { } |
| height | 默认最大高度| string | - | 200px |
| paging | 是否开启自定义分页 | boolean | true / false | false |
| pageSize | 分页条数 | int | - | 10 |
| pageEmptyShow | 分页无数据是否显示 | boolean | true / false | true |
| radio | 是否开启单选模式 | boolean | true / false | false |
| repeat | 是否开启重复性模式 | boolean | true / false | false |
| clickClose | 是否点击选项后自动关闭下拉框 | boolean | true / false | false |
| prop | 自定义属性名称, 具体看下表 | object | - | |
| theme | 主题配置, 具体看下表 | object | - | |
| model | 模型, 多选的展示方式, 具体见下表 | object | - | |
| show | 展开下拉的回调 | function | - | - |
| hide | 隐藏下拉的回调 | function | - | - |
| template | 自定义渲染选项 | function({ item, sels, name, value }) | - | - |
| on | 监听选中变化 | function({ arr, change, isAdd }) | - | - |
| max | 设置多选选中上限 | int | - | 0 |
| maxMethod | 达到选中上限的回到 | function(sels, item), sels: 已选中数据, item: 当前选中的值 | - | - |
| name | 表单提交时的name | string | - | select |
| toolbar | 工具条, 具体看下表 | object | - | - |
| showCount | 展示在下拉框中的最多选项数量 | int | - | 0 |
| autoRow | 是否开启自动换行(选项过多时) | boolean | true / false | false |
| size | 尺寸 | string | large / medium / small / mini | medium |
| disabled | 是否禁用多选 | boolean | true / false | false |
| create | 创建条目 | function(val, data), val: 搜索的数据, data: 当前下拉数据 | - | null |
### prop
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------------- | ------------------------------ | --------------- | ------ | ------ |
| name | 显示名称 | string | - | name |
| value | 选中值, 当前多选唯一 | string | - | value |
| selected | 是否选中 | string | - | selected |
| disabled | 是否禁用 | string | - | disabled |
| children | 分组children | string | - | children |
| optgroup | 分组optgroup | string | - | optgroup |
### 分组说明
如果children属性为数组, 或者optgroup=true的时候开启分组模式
```
//平级结构下面的数据为一组
{name: '城市', optgroup: true},
//children下的数组为一组
{name: '销售员', children: [
{name: '李四', value: 4, selected: true},
{name: '王五', value: 5},
]},
//可在分组上定义click属性, 来定义点击事件
//这里以optgroup模式为例, children模式同理
{name: '选中', optgroup: true, click: 'SELECT'},
{name: '清空', optgroup: true, click: 'CLEAR'},
{name: '自动', optgroup: true, click: 'AUTO'},
{name: '自定义', optgroup: true, click: function(item){
alert('自定义的, 想干嘛干嘛');
}},
```
### theme
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------ | --------- | --------------- | ------ | ------ |
| color | 主题颜色 | string | - | #009688 |
| maxColor | 选中上限闪烁边框颜色 | string | - | #e54d42 |
### model
目前仅配置label即可
```
model: {
//是否展示复选框或者单选框图标 show, hidden:变换背景色
icon: 'show',
label: {
//使用方式
type: 'block',
//使用字符串拼接的方式
text: {
//左边拼接的字符
left: '',
//右边拼接的字符
right: '',
//中间的分隔符
separator: ', ',
},
//使用方块显示
block: {
//最大显示数量, 0:不限制
showCount: 0,
//是否显示删除图标
showIcon: true,
},
//自定义文字
count: {
//函数处理
template(data, sels){
//data: 所有的数据
//sels: 选中的数据
return `已选中 ${sels.length} 项, 共 ${data.length} 项`
}
},
},
},
```
### toolbar
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------ | --------- | --------------- | ------ | ------ |
| show | 是否展示工具条 | boolean | true / false | false |
| showIcon | 是否显示工具图标 | boolean | true / false | true |
| list | 工具条数组 (默认有 全选/清空, 可以自定义), 还有 REVERSE:反选 | array | - | [ "ALL", "CLEAR" ] |
> 自定义方式
```
list: [ "ALL", "CLEAR",
{
//显示图标, 可以是layui内置的图标, 也可以是自己引入的图标
//传入的icon会转化为 <i class="layui-icon layui-icon-face-smile"></i>
icon: 'layui-icon layui-icon-face-smile',
//显示名称
name: 'xxx',
//点击时触发的回调
method: function(data){
//data 当前页面的数据
}
}
]
```
### 全局方法
| 事件名 | 说明 | 参数 | 返回值 |
| ------ | ------------------ | -------- | -------- |
| render | 渲染多选 | (options: 配置项) | 实例对象 |
| get | 获取页面中已经渲染的多选 | (filter: 过滤`el`, single: 是否返回单实例) | 符合条件的实例数组 |
| batch | 批量操作已渲染的多选 | (filter: 过滤`el`, method: 方法, ...方法参数) | 符合条件的实例数组 |
```
//render 使用方式
xmSelect.render(OPTIONS);
//get 使用方式
xmSelect.get('#demo1'); //指定某一个获取
xmSelect.get(/.*demo1.*/); //正则获取
//自定义方法获取
xmSelect.get(function(el){
return el == '#demo1' || el == '#demo2';
});
//单实例
xmSelect.get('#demo2', true);
//batch 使用方式
//批量执行禁用
xmSelect.batch(/.*demo/, 'update', {
disabled: true,
});
//批量执行warning
xmSelect.batch(/.*demo/, 'warning', '#F00', true);
```
### 实例方法
:::warning
xmSelect.render()后会返回一个xmSelect对象, 可以进行方法调用
:::
| 事件名 | 说明 | 参数 |
| ------ | ------------------ | -------- |
| getValue | 获取当前选中的数据 | (type: 类型), 可选值: name, nameStr, value, valueStr |
| setValue | 动态设置数据 | (array: 选中的数据, show: 是否展开下拉,不传默认当前显示状态,取值: true/false, listenOn: 是否触发on的监听, 默认false) |
| append | 追加赋值 | (array: 追加的数据) |
| delete | 删除赋值 | (array: 删除的数据) |
| opened | 主动展开下拉 | - |
| closed | 主动关闭下拉 | - |
| reset | 重置为上一次的render状态 | - |
| update | 更新多选选中, reset不保留 | (options: 见配置项) |
| warning | 警告 | (color: 默认同theme.maxColor, sustain: 是否持续显示) |
## 配置项与方法
### 配置项
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------------- | ------------------------------ | --------------- | ------ | ------ |
| el | 渲染对象, css选择器 | string | - | - |
| language | 语言选择 | string | zn / en | zn |
| data | 显示的数据 | array | - | [ ] |
| content | 自定义下拉框html | string | - | - |
| initValue | 初始化选中的数据, 需要在data中存在 | array | - | null |
| tips | 默认提示, 类似于placeholder | string | - | 请选择 |
| empty | 空数据提示 | string | - | 暂无数据 |
| filterable | 是否开启搜索 | boolean | true / false | false |
| searchTips | 搜索提示 | string | - | 请选择 |
| delay | 搜索延迟 ms | int | - | 500 |
| filterMethod | 搜索回调函数 | function(val, item, index, prop) val: 当前搜索值, item: 每个option选项, index: 位置数据中的下标, prop: 定义key | - | - |
| filterDone | 搜索完成函数 | function(val, list) val: 当前搜索值, list: 过滤后的数据 | - | - |
| remoteSearch | 是否开启自定义搜索 (远程搜索)| boolean | true / false | false |
| remoteMethod | 自定义搜索回调函数 | function(val, cb, show) val: 当前搜索值, cb: 回调函数, 需要回调一个数组, 结构同data, show: 下拉框显示状态 | - | - |
| direction | 下拉方向| string | auto / up / down | auto |
| style | 自定义样式| object | - | { } |
| height | 默认最大高度| string | - | 200px |
| paging | 是否开启自定义分页 | boolean | true / false | false |
| pageSize | 分页条数 | int | - | 10 |
| pageEmptyShow | 分页无数据是否显示 | boolean | true / false | true |
| radio | 是否开启单选模式 | boolean | true / false | false |
| repeat | 是否开启重复性模式 | boolean | true / false | false |
| clickClose | 是否点击选项后自动关闭下拉框 | boolean | true / false | false |
| prop | 自定义属性名称, 具体看下表 | object | - | |
| theme | 主题配置, 具体看下表 | object | - | |
| model | 模型, 多选的展示方式, 具体见下表 | object | - | |
| show | 展开下拉的回调 | function | - | - |
| hide | 隐藏下拉的回调 | function | - | - |
| template | 自定义渲染选项 | function({ item, sels, name, value }) | - | - |
| on | 监听选中变化 | function({ arr, change, isAdd }) | - | - |
| max | 设置多选选中上限 | int | - | 0 |
| maxMethod | 达到选中上限的回到 | function(sels, item), sels: 已选中数据, item: 当前选中的值 | - | - |
| name | 表单提交时的name | string | - | select |
| toolbar | 工具条, 具体看下表 | object | - | - |
| showCount | 展示在下拉框中的最多选项数量 | int | - | 0 |
| autoRow | 是否开启自动换行(选项过多时) | boolean | true / false | false |
| size | 尺寸 | string | large / medium / small / mini | medium |
| disabled | 是否禁用多选 | boolean | true / false | false |
| create | 创建条目 | function(val, data), val: 搜索的数据, data: 当前下拉数据 | - | null |
| tree | 树形结构, 具体看下表 | object | - | - |
### prop
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------------- | ------------------------------ | --------------- | ------ | ------ |
| name | 显示名称 | string | - | name |
| value | 选中值, 当前多选唯一 | string | - | value |
| selected | 是否选中 | string | - | selected |
| disabled | 是否禁用 | string | - | disabled |
| children | 分组children | string | - | children |
| optgroup | 分组optgroup | string | - | optgroup |
### 分组说明
如果children属性为数组的时候开启分组模式
```
{name: '销售员', children: [
{name: '李四', value: 4, selected: true},
{name: '王五', value: 5},
]},
//可在分组上定义click属性, 来定义点击事件
{name: '选中', children: [...], click: 'SELECT'},
{name: '清空', children: [...], click: 'CLEAR'},
{name: '自动', children: [...], click: 'AUTO'},
{name: '自定义', children: [...], click: function(item){
alert('自定义的, 想干嘛干嘛');
}},
```
### theme
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------ | --------- | --------------- | ------ | ------ |
| color | 主题颜色 | string | - | #009688 |
| maxColor | 选中上限闪烁边框颜色 | string | - | #e54d42 |
### model
目前仅配置label即可
```
model: {
//是否展示复选框或者单选框图标 show, hidden:变换背景色
icon: 'show',
label: {
//使用方式
type: 'block',
//使用字符串拼接的方式
text: {
//左边拼接的字符
left: '',
//右边拼接的字符
right: '',
//中间的分隔符
separator: ', ',
},
//使用方块显示
block: {
//最大显示数量, 0:不限制
showCount: 0,
//是否显示删除图标
showIcon: true,
},
//自定义文字
count: {
//函数处理
template(data, sels){
//data: 所有的数据
//sels: 选中的数据
return `已选中 ${sels.length} 项, 共 ${data.length} 项`
}
},
},
},
```
### toolbar
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------ | --------- | --------------- | ------ | ------ |
| show | 是否展示工具条 | boolean | true / false | false |
| showIcon | 是否显示工具图标 | boolean | true / false | true |
| list | 工具条数组 (默认有 全选/清空, 可以自定义), 还有 REVERSE:反选 | array | - | [ "ALL", "CLEAR" ] |
> 自定义方式
```
list: [ "ALL", "CLEAR",
{
//显示图标, 可以是layui内置的图标, 也可以是自己引入的图标
//传入的icon会转化为 <i class="layui-icon layui-icon-face-smile"></i>
icon: 'layui-icon layui-icon-face-smile',
//显示名称
name: 'xxx',
//点击时触发的回调
method: function(data){
//data 当前页面的数据
}
}
]
```
### tree
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------ | --------- | --------------- | ------ | ------ |
| show | 是否展示为树状结构 | boolean | true / false | false |
| showFolderIcon | 是否显示节点前的三角图标 | boolean | true / false | true |
| showLine | 是否显示虚线 | boolean | true / false | true |
| indent | 间距 | int | - | 20 |
| expandedKeys | 默认展开的节点数组 | array | - | [ ] |
### 全局方法
| 事件名 | 说明 | 参数 | 返回值 |
| ------ | ------------------ | -------- | -------- |
| render | 渲染多选 | (options: 配置项) | 实例对象 |
| get | 获取页面中已经渲染的多选 | (filter: 过滤`el`, single: 是否返回单实例) | 符合条件的实例数组 |
| batch | 批量操作已渲染的多选 | (filter: 过滤`el`, method: 方法, ...方法参数) | 符合条件的实例数组 |
```
//render 使用方式
xmSelect.render(OPTIONS);
//get 使用方式
xmSelect.get('#demo1'); //指定某一个获取
xmSelect.get(/.*demo1.*/); //正则获取
//自定义方法获取
xmSelect.get(function(el){
return el == '#demo1' || el == '#demo2';
});
//单实例
xmSelect.get('#demo2', true);
//batch 使用方式
//批量执行禁用
xmSelect.batch(/.*demo/, 'update', {
disabled: true,
});
//批量执行warning
xmSelect.batch(/.*demo/, 'warning', '#F00', true);
```
### 实例方法
:::warning
xmSelect.render()后会返回一个xmSelect对象, 可以进行方法调用
:::
| 事件名 | 说明 | 参数 |
| ------ | ------------------ | -------- |
| getValue | 获取当前选中的数据 | (type: 类型), 可选值: name, nameStr, value, valueStr |
| setValue | 动态设置数据 | (array: 选中的数据, show: 是否展开下拉,不传默认当前显示状态,取值: true/false, listenOn: 是否触发on的监听, 默认false) |
| append | 追加赋值 | (array: 追加的数据) |
| delete | 删除赋值 | (array: 删除的数据) |
| opened | 主动展开下拉 | - |
| closed | 主动关闭下拉 | - |
| reset | 重置为上一次的render状态 | - |
| update | 更新多选选中, reset不保留 | (options: 见配置项) |
| warning | 警告 | (color: 默认同theme.maxColor, sustain: 是否持续显示) |

View File

@ -1,60 +1,60 @@
## 常见问题
### formSelects 与 xm-select
[formSelects](https://github.com/hnzzmsf/layui-formSelects/)是作者很久以前开发的一款多选插件, 在jQuery时代还是相对比较稳定, 不过性能上有很大的问题。痛并思痛后,开始学习其他开源组件的编写方案,最后决定重新开发。
[xm-select](https://gitee.com/maplemei/xm-select)作者精心二次开发的组件, 在formSelects的样式基础上进行了性能优化。目前看来还是比较稳定的 ^_^
### 1.在哪里下载
[Gitee码云下载](https://gitee.com/maplemei/xm-select/releases), 使用时引入`xm-select.js`即可, 已经内置了css, 具体请看[入门指南](/#/component/install)
### 2.为什么多选不显示
重要的事情说三遍, 需要渲染, 需要渲染, 需要渲染
### 3.渲染后还是不显示
- 打开控制台查看是否报错
- 加群: 660408068, 询问
### 4.占位标签为什么是div
演示中使用的是div, 不限制标签, 但是不建议使用`select`, 因为`layui`会渲染`select`标签
### 5.动态数据渲染报错
![](../assets/dataNotArray.png)
检查设置的data数据是否为数组类型
```
var demo1 = xmSelect.render({
el: '#demo1',
data: []
})
//....N多操作以后
var arr = data;//这里的data可能是ajax返回的数据
//这里必须是 [object Array]
console.log(Object.prototype.toString.call(arr));
//如果是 [object String]
//1. JSON数据
arr = JSON.parse(arr);
//2. 类似JSON的数据
arr = eval('(' + arr + ')');
demo1.update({
data: arr,
})
```
## 常见问题
### formSelects 与 xm-select
[formSelects](https://github.com/hnzzmsf/layui-formSelects/)是作者很久以前开发的一款多选插件, 在jQuery时代还是相对比较稳定, 不过性能上有很大的问题。痛并思痛后,开始学习其他开源组件的编写方案,最后决定重新开发。
[xm-select](https://gitee.com/maplemei/xm-select)作者精心二次开发的组件, 在formSelects的样式基础上进行了性能优化。目前看来还是比较稳定的 ^_^
### 1.在哪里下载
[Gitee码云下载](https://gitee.com/maplemei/xm-select/releases), 使用时引入`xm-select.js`即可, 已经内置了css, 具体请看[入门指南](/#/component/install)
### 2.为什么多选不显示
重要的事情说三遍, 需要渲染, 需要渲染, 需要渲染
### 3.渲染后还是不显示
- 打开控制台查看是否报错
- 加群: 660408068, 询问
### 4.占位标签为什么是div
演示中使用的是div, 不限制标签, 但是不建议使用`select`, 因为`layui`会渲染`select`标签
### 5.动态数据渲染报错
![](../assets/dataNotArray.png)
检查设置的data数据是否为数组类型
```
var demo1 = xmSelect.render({
el: '#demo1',
data: []
})
//....N多操作以后
var arr = data;//这里的data可能是ajax返回的数据
//这里必须是 [object Array]
console.log(Object.prototype.toString.call(arr));
//如果是 [object String]
//1. JSON数据
arr = JSON.parse(arr);
//2. 类似JSON的数据
arr = eval('(' + arr + ')');
demo1.update({
data: arr,
})
```

View File

@ -1,168 +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;
}
/* #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 */

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +1,2 @@
import './eleTree/eleTree.js'
import './eleTree/eleTree.js'
import './eleTree/eleTree.css'

View File

@ -1,118 +1,119 @@
import Component from './components/component.vue';
import { version } from '../package.json'
function importVue(path) {
return r => require.ensure([], () => r(require(`./pages${path}.vue`)));
}
function importMd(path) {
return r => require.ensure([], () => r(require(`./mds${path}.md`)));
}
export default [{
path: '*',
hidden: true,
redirect: '/',
},{
path: '/',
name: '/',
hidden: true,
redirect: '/component',
}, {
path: '/changelog',
name: '更新日志 v' + version,
component: importVue('/changelog'),
}, {
path: '/add',
name: 'QQ群: 660408068',
redirect: '/',
}, {
path: '/component',
name: '入门指南',
redirect: '/component/install',
component: Component,
children: [{
path: '/component/install',
name: '安装与使用',
component: importMd('/install'),
}, {
path: '/component/options',
name: '配置项与方法',
component: importMd('/options'),
}]
}, {
path: '/example',
name: '示例',
redirect: '/example/XM01',
component: Component,
children: [
{ path: '/example/XM01', name: 'Base 基础使用', component: importMd('/XM01') },
{ path: '/example/XM02', name: 'Language 国际化', component: importMd('/XM02') },
{ path: '/example/XM03', name: 'InitValue 默认选中', component: importMd('/XM03') },
{ path: '/example/XM04', name: 'Tips 修改提示', component: importMd('/XM04') },
{ path: '/example/XM05', name: 'Filterable 搜索模式', component: importMd('/XM05') },
{ path: '/example/XM06', name: 'Direction 下拉方向', component: importMd('/XM06') },
{ path: '/example/XM07', name: 'Style 自定义样式', component: importMd('/XM07') },
{ path: '/example/XM08', name: 'Paging 分页', component: importMd('/XM08') },
{ path: '/example/XM09', name: 'Radio 单选', component: importMd('/XM09') },
{ path: '/example/XM10', name: 'Repeat 重复选', component: importMd('/XM10') },
{ path: '/example/XM11', name: 'Prop 自定义属性', component: importMd('/XM11') },
{ path: '/example/XM12', name: 'Theme 主题', component: importMd('/XM12') },
{ path: '/example/XM13', name: 'Show 显示与隐藏', component: importMd('/XM13') },
{ path: '/example/XM14', name: 'Model 显示方式', component: importMd('/XM14') },
{ path: '/example/XM15', name: 'Template 构建选项', component: importMd('/XM15') },
{ path: '/example/XM16', name: 'On 监听选择', component: importMd('/XM16') },
{ path: '/example/XM17', name: 'Test 性能测试', component: importMd('/XM17') },
{ path: '/example/XM18', name: 'Max 多选上限', component: importMd('/XM18') },
{ path: '/example/XM19', name: 'Toolbar 工具条', component: importMd('/XM19') },
{ path: '/example/XM20', name: 'ShowCount 选项数量', component: importMd('/XM20') },
{ path: '/example/XM21', name: 'Optgroup 分组', component: importMd('/XM21') },
{ path: '/example/XM22', name: 'AutoRow 自动换行', component: importMd('/XM22') },
{ path: '/example/XM23', name: 'HiddenIcon 隐藏图标', component: importMd('/XM23') },
{ path: '/example/XM24', name: 'Size 尺寸', component: importMd('/XM24') },
{ path: '/example/XM25', name: 'Warning 警告', component: importMd('/XM25') },
{ path: '/example/XM26', name: 'Disabled 禁用', component: importMd('/XM26') },
{ path: '/example/XM27', name: 'Create 创建条目', component: importMd('/XM27') },
]
}, {
path: '/example-custom',
name: '进阶示例',
redirect: '/example-custom/ZM01',
component: Component,
children: [
{ path: '/example-custom/ZM01', name: '赋值与取值', component: importMd('/ZM01') },
{ path: '/example-custom/ZM02', name: '表单提交', component: importMd('/ZM02') },
{ path: '/example-custom/ZM03', name: '表格中多选', component: importMd('/ZM03') },
{ 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/ZM07', name: '获取实例对象', component: importMd('/ZM07') },
{ path: '/example-custom/ZM08', name: '批量操作', component: importMd('/ZM08') },
]
}, {
path: '/example-plugin',
name: '拓展中心',
redirect: '/example-plugin/ZP01',
component: Component,
children: [
{ path: '/example-plugin/ZP01', name: '下拉自定义', component: importMd('/ZP01') },
{ path: '/example-plugin/ZP02', name: '下拉树 EleTree', component: importMd('/ZP02') },
// { path: '/example-plugin/ZP03', name: '下拉树 LayuiTree', component: importMd('/ZP03') },
]
}, {
path: '/question',
name: '常见问题',
component: importMd('/question'),
}, {
path: '/es6',
name: 'es6语法说明',
component: importMd('/es6'),
}, {
path: '/test',
name: '测试',
hidden: true,
component: importMd('/ZTEST'),
},
];
import Component from './components/component.vue';
import { version } from '../package.json'
function importVue(path) {
return r => require.ensure([], () => r(require(`./pages${path}.vue`)));
}
function importMd(path) {
return r => require.ensure([], () => r(require(`./mds${path}.md`)));
}
export default [{
path: '*',
hidden: true,
redirect: '/',
},{
path: '/',
name: '/',
hidden: true,
redirect: '/component',
}, {
path: '/changelog',
name: '更新日志 v' + version,
component: importVue('/changelog'),
}, {
path: '/add',
name: 'QQ群: 660408068',
redirect: '/',
}, {
path: '/component',
name: '入门指南',
redirect: '/component/install',
component: Component,
children: [{
path: '/component/install',
name: '安装与使用',
component: importMd('/install'),
}, {
path: '/component/options',
name: '配置项与方法',
component: importMd('/options'),
}]
}, {
path: '/example',
name: '示例',
redirect: '/example/XM01',
component: Component,
children: [
{ path: '/example/XM01', name: 'Base 基础使用', component: importMd('/XM01') },
{ path: '/example/XM02', name: 'Language 国际化', component: importMd('/XM02') },
{ path: '/example/XM03', name: 'InitValue 默认选中', component: importMd('/XM03') },
{ path: '/example/XM04', name: 'Tips 修改提示', component: importMd('/XM04') },
{ path: '/example/XM05', name: 'Filterable 搜索模式', component: importMd('/XM05') },
{ path: '/example/XM06', name: 'Direction 下拉方向', component: importMd('/XM06') },
{ path: '/example/XM07', name: 'Style 自定义样式', component: importMd('/XM07') },
{ path: '/example/XM08', name: 'Paging 分页', component: importMd('/XM08') },
{ path: '/example/XM09', name: 'Radio 单选', component: importMd('/XM09') },
{ path: '/example/XM10', name: 'Repeat 重复选', component: importMd('/XM10') },
{ path: '/example/XM11', name: 'Prop 自定义属性', component: importMd('/XM11') },
{ path: '/example/XM12', name: 'Theme 主题', component: importMd('/XM12') },
{ path: '/example/XM13', name: 'Show 显示与隐藏', component: importMd('/XM13') },
{ path: '/example/XM14', name: 'Model 显示方式', component: importMd('/XM14') },
{ path: '/example/XM15', name: 'Template 构建选项', component: importMd('/XM15') },
{ path: '/example/XM16', name: 'On 监听选择', component: importMd('/XM16') },
{ path: '/example/XM17', name: 'Test 性能测试', component: importMd('/XM17') },
{ path: '/example/XM18', name: 'Max 多选上限', component: importMd('/XM18') },
{ path: '/example/XM19', name: 'Toolbar 工具条', component: importMd('/XM19') },
{ path: '/example/XM20', name: 'ShowCount 选项数量', component: importMd('/XM20') },
{ path: '/example/XM21', name: 'Optgroup 分组', component: importMd('/XM21') },
{ path: '/example/XM22', name: 'AutoRow 自动换行', component: importMd('/XM22') },
{ path: '/example/XM23', name: 'HiddenIcon 隐藏图标', component: importMd('/XM23') },
{ path: '/example/XM24', name: 'Size 尺寸', component: importMd('/XM24') },
{ path: '/example/XM25', name: 'Warning 警告', component: importMd('/XM25') },
{ path: '/example/XM26', name: 'Disabled 禁用', component: importMd('/XM26') },
{ path: '/example/XM27', name: 'Create 创建条目', component: importMd('/XM27') },
]
}, {
path: '/example-custom',
name: '进阶示例',
redirect: '/example-custom/ZM01',
component: Component,
children: [
{ path: '/example-custom/ZM01', name: '赋值与取值', component: importMd('/ZM01') },
{ path: '/example-custom/ZM02', name: '表单提交', component: importMd('/ZM02') },
{ path: '/example-custom/ZM03', name: '表格中多选', component: importMd('/ZM03') },
{ 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/ZM07', name: '获取实例对象', component: importMd('/ZM07') },
{ path: '/example-custom/ZM08', name: '批量操作', component: importMd('/ZM08') },
]
}, {
path: '/example-plugin',
name: '拓展中心',
redirect: '/example-plugin/ZP01',
component: Component,
children: [
{ path: '/example-plugin/ZP01', name: '下拉自定义', component: importMd('/ZP01') },
{ path: '/example-plugin/ZP02', name: '下拉树 Tree', component: importMd('/ZP02') },
{ path: '/example-plugin/ZP03', name: '下拉日期多选', component: importMd('/ZP03') },
]
}, {
path: '/question',
name: '常见问题',
component: importMd('/question'),
}, {
path: '/es6',
name: 'es6语法说明',
component: importMd('/es6'),
}, {
path: '/test',
name: '测试',
hidden: true,
// hidden: false,
component: importMd('/ZTEST'),
},
];

View File

@ -1,6 +1,6 @@
{
"name": "xm-select",
"version": "1.0.13",
"version": "1.1.0",
"description": "始于Layui的select多选解决方案",
"main": "index.js",
"scripts": {
@ -27,6 +27,7 @@
"markdown-it-anchor": "^5.2.4",
"markdown-it-chain": "^1.3.0",
"markdown-it-container": "^2.0.0",
"preact": "^10.0.5",
"style-loader": "^0.23.1",
"transliteration": "^2.1.7",
"url-loader": "^2.1.0",

166
src/common/util.js Normal file
View File

@ -0,0 +1,166 @@
/**
* 选中dom元素
*/
export function selector(el) {
return document.querySelector(el);
}
/**
* 警告提示
*/
export function warn() {
let arr = [];
for (var i = 0; i < arguments.length; i++) {
arr.push(`${i + 1}. ${arguments[i]}`);
}
console.warn(arr.join('\n'));
}
/**
* 安全拷贝数据
*/
export function safety(data) {
return JSON.parse(JSON.stringify(data));
}
/**
* 检测对象是否为数组
*/
export function isArray(obj) {
return Object.prototype.toString.call(obj) == "[object Array]";
}
/**
* 检测对象是否为函数
*/
export function isFunction(obj) {
return Object.prototype.toString.call(obj) == "[object Function]";
}
/**
* 转化为数字
*/
export function toNum(obj) {
obj -= 0;
isNaN(obj) && (obj = 0);
return obj;
}
/**
* 简单的深度合并
*/
export function deepMerge(obj1, obj2) {
let key;
for (key in obj2) {
// 如果target(也就是obj1[key])存在且是对象的话再去调用deepMerge否则就是obj1[key]里面没这个对象需要与obj2[key]合并
// 如果obj2[key]没有值或者值不是对象此时直接替换obj1[key]
obj1[key] =
obj1[key] &&
obj1[key].toString() === "[object Object]" &&
(obj2[key] && obj2[key].toString() === "[object Object]") ?
deepMerge(obj1[key], obj2[key]) :
(obj1[key] = obj2[key]);
}
return obj1;
}
/**
* 数组合并
*/
export function mergeArr(arr1, arr2, prop) {
let value = prop.value;
let result = [...arr2];
for (let i = 0; i < arr1.length; i++) {
let item = arr1[i];
if (!arr2.find(a => a[value] == item[value])) {
result.push(item);
}
}
return result;
}
export function watch(data) {
return new Promise((resolve, reject) => {
for (let key in data) {
let value = data[key];
Object.defineProperty(data, key, {
configurable: false, // 该状态下的属性描述符不能被修改和删除
enumerable: false, // 该状态下的属性描述符中的属性不可被枚举
get() {
return value;
},
set(newVal) {
if (newVal !== value) {
resolve(key, newVal, value);
value = newVal;
}
}
});
}
});
}
export function checkUserAgent() {
const ua = navigator.userAgent;
if (ua.indexOf('Mac OS') != -1) {
return 'mac';
}
return 'win';
}
export function IEVersion() {
var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1; //判断是否IE<11浏览器
var isEdge = userAgent.indexOf("Edge") > -1 && !isIE; //判断是否IE的Edge浏览器
var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1;
if (isIE) {
var reIE = new RegExp("MSIE (\\d+\\.\\d+);");
reIE.test(userAgent);
var fIEVersion = parseFloat(RegExp["$1"]);
if (fIEVersion == 7) {
return 7;
} else if (fIEVersion == 8) {
return 8;
} else if (fIEVersion == 9) {
return 9;
} else if (fIEVersion == 10) {
return 10;
} else {
return 6; //IE版本<=7
}
} else if (isEdge) {
return 'edge'; //edge
} else if (isIE11) {
return 11; //IE11
} else {
return -1; //不是ie浏览器
}
}
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

@ -1,172 +0,0 @@
/**
* 选中dom元素
*/
export function selector(el) {
return document.querySelector(el);
}
/**
* 警告提示
*/
export function warn() {
let arr = [];
for (var i = 0; i < arguments.length; i++) {
arr.push(`${i + 1}. ${arguments[i]}`);
}
console.warn(arr.join('\n'));
}
/**
* 全局监听点击事件
*/
export function listenerClose(data, handler) {
window.addEventListener('click', (e) => handler(e));
}
/**
* 安全拷贝数据
*/
export function safety(data) {
return JSON.parse(JSON.stringify(data));
}
/**
* 检测对象是否为数组
*/
export function isArray(obj) {
return Object.prototype.toString.call(obj) == "[object Array]";
}
/**
* 检测对象是否为函数
*/
export function isFunction(obj) {
return Object.prototype.toString.call(obj) == "[object Function]";
}
/**
* 转化为数字
*/
export function toNum(obj) {
obj -= 0;
isNaN(obj) && (obj = 0);
return obj;
}
/**
* 简单的深度合并
*/
export function deepMerge(obj1, obj2) {
let key;
for (key in obj2) {
// 如果target(也就是obj1[key])存在且是对象的话再去调用deepMerge否则就是obj1[key]里面没这个对象需要与obj2[key]合并
// 如果obj2[key]没有值或者值不是对象此时直接替换obj1[key]
obj1[key] =
obj1[key] &&
obj1[key].toString() === "[object Object]" &&
(obj2[key] && obj2[key].toString() === "[object Object]") ?
deepMerge(obj1[key], obj2[key]) :
(obj1[key] = obj2[key]);
}
return obj1;
}
/**
* 数组合并
*/
export function mergeArr(arr1, arr2, prop) {
let value = prop.value;
let result = [...arr2];
for (let i = 0; i < arr1.length; i++) {
let item = arr1[i];
if (!arr2.find(a => a[value] == item[value])) {
result.push(item);
}
}
return result;
}
export function watch(data) {
return new Promise((resolve, reject) => {
for (let key in data) {
let value = data[key];
Object.defineProperty(data, key, {
configurable: false, // 该状态下的属性描述符不能被修改和删除
enumerable: false, // 该状态下的属性描述符中的属性不可被枚举
get() {
return value;
},
set(newVal) {
if (newVal !== value) {
resolve(key, newVal, value);
value = newVal;
}
}
});
}
});
}
export function checkUserAgent() {
const ua = navigator.userAgent;
if (ua.indexOf('Mac OS') != -1) {
return 'mac';
}
return 'win';
}
export function IEVersion() {
var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1; //判断是否IE<11浏览器
var isEdge = userAgent.indexOf("Edge") > -1 && !isIE; //判断是否IE的Edge浏览器
var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1;
if (isIE) {
var reIE = new RegExp("MSIE (\\d+\\.\\d+);");
reIE.test(userAgent);
var fIEVersion = parseFloat(RegExp["$1"]);
if (fIEVersion == 7) {
return 7;
} else if (fIEVersion == 8) {
return 8;
} else if (fIEVersion == 9) {
return 9;
} else if (fIEVersion == 10) {
return 10;
} else {
return 6; //IE版本<=7
}
} else if (isEdge) {
return 'edge'; //edge
} else if (isIE11) {
return 11; //IE11
} else {
return -1; //不是ie浏览器
}
}
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

@ -1,11 +0,0 @@
export default {
tips: 'please selected',
empty: 'no data',
searchTips: 'please search',
toolbar: {
ALL: 'select all',
CLEAR: 'clear',
REVERSE: 'invert select',
SEARCH: 'search',
}
}

View File

@ -1,11 +0,0 @@
export default {
tips: '请选择',
empty: '暂无数据',
searchTips: '请选择',
toolbar: {
ALL: '全选',
CLEAR: '清空',
REVERSE: '反选',
SEARCH: '搜索',
}
}

View File

@ -1,179 +0,0 @@
import { h, Component, render } from '@/components/preact'
import Framework from '@/components/element/framework'
import { selector, warn, listenerClose, isArray, deepMerge, exchangeOptionsData } from '@/components/common/util'
import defaultOptions from '@/components/config/options'
/**
* 保留初始化的数据
*/
const initData = {};
const data = {};
const onClose = (el) => Object.keys(data).filter(a => a != el).forEach(el => data[el].closed());
listenerClose(data, onClose);
/**
* 子组件集合
*/
const childs = {};
/**
* 对外提供的处理方法
*/
class xmOptions {
constructor(options) {
//保留初始化时的数据
initData[options.el] = options;
//定义默认值
this.options = defaultOptions(options.language);
//开始渲染数据
this.update(options);
}
/**
* 更新数据 + 重新渲染
*/
update(options = {}){
//记录最新的配置项
this.options = deepMerge(this.options, options);
//如果dom不存在, 则不进行渲染事项
let dom = selector(this.options.el);
if(!dom){
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;
render(<Framework { ...this.options } onClose={ onClose } onRef={ onRef } />, dom);
//记录数据
data[this.options.el] = this;
//返回多选对象
return this;
}
/**
* 重置多选, 回到初始化的状态
*/
reset(){
let initVal = this.options;
//设置options的默认数据
this.options = defaultOptions(initVal.language);
//更新渲染
this.update({ ...initData[initVal.el]});
//子组件初始化
childs[this.options.el].reset(this.options, true);
return this;
}
/**
* 主动打开多选
*/
opened(){
let ref = childs[this.options.el];
!ref.state.show && ref.onClick();
return this;
}
/**
* 主动关闭多选
*/
closed(){
let ref = childs[this.options.el];
ref.state.show && ref.onClick();
return this;
}
/**
* 获取多选选中的数据
*/
getValue(type){
let arr = deepMerge([], childs[this.options.el].state.sels);
if(type === 'name'){
return arr.map(item => item[this.options.prop.name]);
}else
if(type === 'nameStr'){
return arr.map(item => item[this.options.prop.name]).join(',');
}else
if(type === 'value'){
return arr.map(item => item[this.options.prop.value]);
}else
if(type === 'valueStr'){
return arr.map(item => item[this.options.prop.value]).join(',');
}
return arr;
}
/**
* 设置多选数据
*/
setValue(sels, show, listenOn = false){
if(!isArray(sels)){
warn('请传入数组结构...')
return ;
}
childs[this.options.el].value(sels, show, listenOn);
return this;
}
/**
* 追加赋值
*/
append(sels){
if(!isArray(sels)){
warn('请传入数组结构...')
return ;
}
childs[this.options.el].append(sels);
return this;
}
/**
* 删除赋值
*/
delete(sels){
if(!isArray(sels)){
warn('请传入数组结构...')
return ;
}
childs[this.options.el].del(sels);
return this;
}
/**
* 闪烁警告边框
*/
warning(color, sustain = false){
let showColor = color || this.options.theme.maxColor;
sustain === true ? (
childs[this.options.el].base.style.borderColor = showColor
) : (
childs[this.options.el].updateBorderColor(showColor)
)
return this;
}
}
export default xmOptions;

View File

@ -1,283 +0,0 @@
import { h, Component, render } from '@/components/preact'
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';
/**
* 框架渲染类, 渲染基础的外边框 + 属性变化监听
*/
class Framework extends Component{
constructor(options){
super(options);
//初始化多选数据
this.reset(this.props);
//回传子组件
this.props.onRef(this);
this.bodyView = null;
}
reset(props, refresh = false){
//用于多选上限的边框颜色变化
this.updateBorderColor('');
let old = this.state.data;
this.resetDate(props.data);
(JSON.stringify(props.data) !== JSON.stringify(old) || refresh) && this.value(props.initValue ? props.initValue : this.findValue(this.state.data), !!this.state.show);
}
findValue(data){
const { selected } = this.props.prop;
return data.filter(item => item[selected] === true);
}
resetSelectValue(sels = [], change = [], isAdd, listenOn = true){
let on = this.props.on;
if(isFunction(on) && this.prepare && listenOn){
on({ arr: sels, change, isAdd });
}
this.setState({ sels });
}
resetDate(data = []){
this.setState({ data });
}
value(sels, show, listenOn){
if(show !== false && show !== true){
show = this.state.show;
}
let changeData = this.exchangeValue(sels);
this.resetSelectValue(changeData, changeData, true, listenOn);
this.setState({ show })
}
exchangeValue(sels){
const { optgroup, value } = this.props.prop;
let data = this.state.data;
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);
}
append(arr){
let changeData = this.exchangeValue(arr);
this.resetSelectValue(mergeArr(changeData, this.state.sels, this.props.prop), changeData, true);
}
del(arr){
let value = this.props.prop.value;
let sels = this.state.sels;
arr = this.exchangeValue(arr);
arr.forEach(v => {
let index = sels.findIndex(item => item[value] === v[value]);
if(index != -1){
sels.splice(index, 1);
}
});
this.resetSelectValue(sels, arr, false);
}
auto(arr){
let value = this.props.prop.value;
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);
}
updateBorderColor(tmpColor){
this.setState({ tmpColor });
}
onReset(data, type){
//重置数据
if(type === 'data'){
let changeData = this.findValue(data);
this.resetSelectValue(mergeArr(changeData, this.state.sels, this.props.prop), changeData, true);
this.setState({ data });
}else
//重置选中数据
if(type === 'sels'){
this.resetSelectValue(data, data, true);
}else
//追加数据
if(type === 'append'){
this.append(data);
}else
//清理数据
if(type === 'delete'){
this.del(data);
}else
//自动判断模式
if(type === 'auto'){
this.auto(data);
}
}
onClick(e){
if(this.props.disabled){
this.state.show !== false && this.setState({ show: false });
return ;
}
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.hide && this.props.hide() == false){
return;
}
//如果产生滚动条, 关闭下拉后回到顶部
this.bodyView.scroll && this.bodyView.scroll(0, 0);
}
this.setState({ show });
//阻止其他绑定事件的冒泡
e && e.stopPropagation();
}
componentWillReceiveProps(props){
this.reset(props)
}
componentDidUpdate(){
let direction = this.props.direction;
let rect = this.base.getBoundingClientRect();
if(direction === 'auto'){
//用于控制js获取下拉框的高度
this.bodyView.style.display = 'block';
this.bodyView.style.visibility = 'hidden';
//获取下拉元素的高度
let bodyViewRect = this.bodyView.getBoundingClientRect();
let bodyViewHeight = bodyViewRect.height;
//还原控制效果
this.bodyView.style.display = '';
this.bodyView.style.visibility = '';
//确定下拉框是朝上还是朝下
let clientHeight = document.documentElement.clientHeight;
let diff = clientHeight - (rect.y || rect.top) - rect.height - 20;
direction = diff > bodyViewHeight || (rect.y || rect.top) < diff ? 'down' : 'up';
}
if(direction == 'down'){
this.bodyView.style.top = rect.height + 4 + 'px';
this.bodyView.style.bottom = 'auto';
}else{
this.bodyView.style.top = 'auto';
this.bodyView.style.bottom = rect.height + 4 + 'px';
}
}
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 };
//最外层边框的属性
const xmSelectProps = {
style: {
...style,
...(show ? borderStyle : {})
},
onClick: this.onClick.bind(this),
ua: checkUserAgent(),
size: config.size,
}
if(this.state.tmpColor){
xmSelectProps.style.borderColor = this.state.tmpColor;
setTimeout(() => {
xmSelectProps.style.borderColor = '';
this.updateBorderColor('')
}, 300);
}
if(config.disabled){
show = false;
}
//右边下拉箭头的变化class
const iconClass = show ? 'xm-icon xm-icon-expand' : 'xm-icon';
//提示信息的属性
const tipsProps = {
tips,
//没有已选择数据, 则显示提示
show: !sels.length
}
//普通多选数据
const valueProp = prop.value;
//选项, 选中状态, 禁用状态, 是否强制删除:在label上点击删除
const ck = (item, selected, disabled, mandatoryDelete) => {
//如果是禁用状态, 不能进行操作
if(disabled) return;
//如果现在是选中状态
if(selected && (!repeat || mandatoryDelete)){
let index = sels.findIndex(sel => sel[valueProp] == item[valueProp])
if(index != -1){
sels.splice(index, 1);
this.resetSelectValue(sels, [item], !selected);
}
}else{
//查看是否设置了多选上限
let maxCount = toNum(max);
if(maxCount > 0 && sels.length >= maxCount){
this.updateBorderColor(theme.maxColor);
//查看是否需要回调
maxMethod && isFunction(maxMethod) && maxMethod(sels, item);
return ;
}
//如果是单选模式
if(radio){
this.resetSelectValue([item], [item], !selected);
}else{
this.resetSelectValue([...sels, item], [item], !selected);
}
}
//检查是否为选择即关闭状态, 强制删除情况下不做处理
clickClose && !mandatoryDelete && this.onClick();
};
const select = (
<input class="xm-select-default" name={ config.name } value={ sels.map(item => item[prop.value]).join(',') }></input>
)
const labelProps = { ...config, data: this.state.data, sels, ck, title: sels.map(sel => sel[prop.name]).join(',') }
const bodyProps = { ...config, data: this.state.data, sels, ck, show, onReset: this.onReset.bind(this) }
//控制下拉框的显示于隐藏
const bodyClass = ['xm-body', show ? '' : 'dis'].join(' ');
return (
<xm-select { ...xmSelectProps } >
{ select }
<i class={ iconClass } />
<Tips { ...tipsProps } />
<Label { ...labelProps } />
<div class={ bodyClass } ref={ ref => this.bodyView = ref}>
{ config.content ? (
<Custom content={ config.content } height={ config.height } />
) : (
<General { ...bodyProps } />
) }
</div>
{ config.disabled && <div class="xm-select-disabled"></div> }
</xm-select>
);
}
}
export default Framework;

View File

@ -1,32 +0,0 @@
import { h, Component, render } from '@/components/preact'
/**
* 默认提示
*/
class Custom extends Component{
constructor(options){
super(options);
}
blockClick(e){
e.stopPropagation();
}
shouldComponentUpdate(){
return !this.prepare;
}
render(config) {
this.prepare = true;
return (
<div onClick={ this.blockClick } class="xm-body-custom" >
<div class="scroll-body" style={ {maxHeight: config.height} }>
<div style="margin: 5px 0" dangerouslySetInnerHTML={{ __html: config.content }}></div>
</div>
</div>
)
}
}
export default Custom;

View File

@ -1,412 +0,0 @@
import { h, Component, render } from '@/components/preact'
import { isFunction, isArray, safety, deepMerge, mergeArr, IEVersion } from '@/components/common/util'
/**
* 普通的多选渲染
*/
class General extends Component{
constructor(options){
super(options);
this.setState({
filterValue: '',
remote: true,
loading: false,
pageIndex: 1,
pageSize: 10,
});
this.searchCid = 0;
this.inputOver = true;
this.__value = '';
this.dynamicInput = false;
}
optionClick(item, selected, disabled, e){
this.props.ck(item, selected, disabled);
//阻止父组件上的事件冒泡
this.blockClick(e);
}
groupClick(item, e){
const { click, children, disabled } = this.props.prop;
let m = item[click], arr = item[children].filter(opt => !opt[disabled]);
if(m === 'SELECT'){
this.props.onReset(arr, 'append');
}else if(m === 'CLEAR'){
this.props.onReset(arr, 'delete');
}else if(m === 'AUTO'){
this.props.onReset(arr, 'auto');
}else if(isFunction(m)){
m(item);
}
//阻止父组件上的事件冒泡
this.blockClick(e);
}
blockClick(e){
e.stopPropagation();
}
pagePrevClick(e){
let index = this.state.pageIndex;
if(index <= 1){
return ;
}
this.changePageIndex(index - 1);
}
pageNextClick(e, size){
let index = this.state.pageIndex;
if(index >= size){
return ;
}
this.changePageIndex(index + 1);
}
changePageIndex(index){
this.setState({
pageIndex: index
})
}
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, remote: true })
}, 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);
}
}
componentWillReceiveProps(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);
}
}
}
componentDidUpdate(){
if(this.callback){
this.callback = false;
let done = this.props.filterDone;
if(isFunction(done)){
done(this.state.filterValue, this.tempData || []);
}
}
}
render(config) {
let { data, prop, template, theme, radio, sels, empty, filterable, filterMethod, remoteSearch, remoteMethod, delay, searchTips, create } = config
const { name, value, disabled, children, optgroup } = prop;
let arr = deepMerge([], data), creator;
//是否开启了搜索
if(filterable){
if(remoteSearch){//是否进行远程搜索
if(this.state.remote){
this.callback = false;
this.setState({ loading: true, remote: false });
//让输入框失去焦点
this.blur();
remoteMethod(this.state.filterValue, result => {
//回调后可以重新聚焦
this.focus();
this.callback = true;
this.setState({ loading: false });
this.props.onReset(result, 'data');
}, this.props.show);
}
}else{
const filterData = (item, index) => {
const isGroup = item[optgroup];
if(isGroup){
delete item.__del;
return true;
}
return filterMethod(this.state.filterValue, item, index, prop);
}
arr = arr.filter(filterData);
for(let i = 0; i < arr.length - 1; i++){
let a = arr[i];
let b = arr[i + 1];
if(a[optgroup] && b[optgroup]){
arr[i].__del = true;
}
}
if(arr.length && arr[arr.length - 1][optgroup]){
arr[arr.length - 1].__del = true;
}
arr = arr.filter(item => !item.__del);
//创建条目
creator = this.state.filterValue && isFunction(create);
}
}
const search = (
<div class='xm-search'>
<i class="xm-iconfont xm-icon-sousuo"></i>
<input type="text" class="xm-input xm-search-input" placeholder={ searchTips }
ref={ input => this.searchInputRef = input }
onClick={ this.blockClick.bind(this) }
onInput={ this.searchInput.bind(this) }
onCompositionStart={ this.handleComposition.bind(this) }
onCompositionUpdate={ this.handleComposition.bind(this) }
onCompositionEnd={ this.handleComposition.bind(this) }
/>
</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){
//计算当前分页的总页码
let size = Math.floor((arr.length - 1) / config.pageSize) + 1;
size <= 0 && (size = 1);
let pageIndex = this.state.pageIndex;
//如果当前页码大于总页码, 重置一下
if(pageIndex > size){
pageIndex = size;
}
//如有总页码>1, 但是因为搜索造成的页码=0的情况
if(size > 0 && pageIndex <= 0){
pageIndex = 1;
}
//实现简单的物理分页
let start = (pageIndex - 1) * config.pageSize;
let end = start + config.pageSize;
arr = arr.slice(start, end);
const disabledStyle = {cursor: 'no-drop', color: '#d2d2d2'};
let prevStyle = {}, nextStyle = {};
pageIndex <= 1 && (prevStyle = disabledStyle);
pageIndex == size && (nextStyle = disabledStyle);
// const defaultCurrClass = {
// position: 'relative',
// borderRadius: '1px',
// }
// {
// ''.padEnd(size, ' ').split('').map((s, i) => (
// <span style={
// this.state.pageIndex == i + 1 ? {
// ...defaultCurrClass,
// backgroundColor: theme.color,
// borderColor: theme.color,
// color: '#FFF',
// } : defaultCurrClass
// }>{ i + 1 }</span>
// ))
// }
this.state.pageIndex !== pageIndex && this.changePageIndex(pageIndex);
paging = (
<div class='xm-paging'>
<span style={ prevStyle } onClick={ this.pagePrevClick.bind(this) }>上一页</span>
<span>{ this.state.pageIndex } / { size }</span>
<span style={ nextStyle } onClick={ e => this.pageNextClick.bind(this, e, size)() }>下一页</span>
</div>
)
}else{
//检查是否设置了显示数量上限
if(config.showCount > 0){
arr = arr.slice(0, config.showCount);
}
}
let newArr = [], group;
arr.forEach(item => {
let g = groupInfo[item[value]];
if(g != group){
group = g;
newArr.push(group);
}
newArr.push(item);
});
arr = newArr;
//查看是否创建了条目
if(creator){
creator = create(this.state.filterValue, deepMerge([], arr));
creator && arr.splice(0, 0, creator);
}
let safetyArr = deepMerge([], arr);
this.tempData = safetyArr;
//工具条操作
const toolbar = (
<div class='xm-toolbar'>
{ config.toolbar.list.map(tool => {
const toolClass = 'toolbar-tag';
const toolStyle = {};
let info, name = config.languageProp.toolbar[tool];
if(tool === 'ALL'){
info = { icon: 'xm-iconfont xm-icon-quanxuan', name, method: (pageData) => {
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) => {
this.props.onReset(sels.filter(item => item[prop.disabled]), 'sels');
} };
}else if(tool === 'REVERSE'){
info = { icon: 'xm-iconfont xm-icon-fanxuan', name, method: (pageData) => {
const { optgroup, disabled } = prop;
const list = pageData.filter(item => !item[optgroup]).filter(item => !item[disabled])
let selectedList = [];
sels.forEach(item => {
let index = list.findIndex(pageItem => pageItem[value] === item[value]);
if(index == -1){
selectedList.push(item);
}else{
list.splice(index, 1);
}
})
this.props.onReset(mergeArr(list, selectedList, prop), 'sels');
} };
}else if(tool === 'SEARCH'){
toolStyle.color = theme.color;
info = { icon: 'xm-iconfont xm-icon-sousuo', name, method: (pageData) => {
} };
}else {
info = tool
}
const hoverChange = e => {
if(e.type === 'mouseenter') e.target.style.color = theme.color;
if(e.type === 'mouseleave') e.target.style.color = '';
}
return (<div class={ toolClass } style={ toolStyle } onClick={ () => {
isFunction(info.method) && info.method(safetyArr)
} } onMouseEnter={ hoverChange } onMouseLeave={ hoverChange }>
{ config.toolbar.showIcon && <i class={ info.icon }></i> }
<span>{ info.name }</span>
</div>)
}).filter(a => a) }
</div>
)
const showIcon = config.model.icon != 'hidden';
const renderItem = item => {
const selected = !!sels.find(sel => sel[value] == item[value])
const iconStyle = selected ? {
color: theme.color,
border: 'none'
} : {
borderColor: theme.color,
};
const itemStyle = {}
if(!showIcon && selected){
itemStyle.backgroundColor = theme.color;
item[disabled] && (itemStyle.backgroundColor = '#C2C2C2');
}
const className = ['xm-option', (item[disabled] ? ' disabled' : ''), (selected ? ' selected' : ''), (showIcon ? 'show-icon' : 'hide-icon') ].join(' ');
const iconClass = ['xm-option-icon xm-iconfont', radio ? 'xm-icon-danx' : 'xm-icon-duox'].join(' ');
return (
<div class={ className } style={ itemStyle } value={ item[value] } onClick={ this.optionClick.bind(this, item, selected, item[disabled]) }>
{ showIcon && <i class={ iconClass } style={ iconStyle }></i> }
<div class='xm-option-content' dangerouslySetInnerHTML={{ __html: template({ data, item, arr: sels, name: item[name], value: item[value] }) }}></div>
</div>
)
}
const renderGroup = item => {
const isGroup = item[optgroup];
if(isGroup){//分组模式
return (
<div class="xm-group">
<div class="xm-group-item" onClick={ this.groupClick.bind(this, item) }>{ item[name] }</div>
</div>
)
}
return renderItem(item);
}
arr = arr.map(renderGroup);
if(!arr.length){
//查看无数据情况下是否显示分页
!config.pageEmptyShow && (paging = '');
arr.push(<div class="xm-select-empty">{ empty }</div>)
}
return (
<div onClick={ this.blockClick }>
<div>
{ config.toolbar.show && toolbar }
{ filterable && search }
<div class="scroll-body" style={ {maxHeight: config.height} }>{ arr }</div>
{ config.paging && paging }
</div>
{ this.state.loading && <div class="loading" >
<span class="loader"></span>
</div> }
</div>
)
}
}
export default General;

View File

@ -1,20 +0,0 @@
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;

View File

@ -0,0 +1,384 @@
import { h, Component, render } from 'preact'
import { datas, childData } from '@/index.js';
import { checkUserAgent, isFunction, isArray, toNum, mergeArr } from '@/common/util'
import Label from '../label';
import General from '../plugin/general';
import Custom from '../plugin/custom';
import Tree from '../plugin/tree';
/**
* 框架渲染类, 渲染基础的外边框 + 属性变化监听
*/
class Framework extends Component{
constructor(options){
super(options);
//保留对象引用
childData[options.el] = this;
//初始化state数据
this.state = this.initState();
this.bodyView = null;
}
initState(){
return {
data: [],
dataObj: {},
flatData: [],
sels: [],
show: false,
tmpColor: '',
}
}
init(props, refresh){
let { data } = props;
//如果新数据和旧数据不同 或者 强制刷新 才进行数据处理
if(refresh){
let dataObj = {};
let flatData = [];
this.load(data, dataObj, flatData);
let sels = props.initValue ? this.exchangeValue(props.initValue) : Object.values(dataObj).filter(item => item[props.prop.selected] === true).filter(item => item[this.props.prop.optgroup] !== true)
this.setState({ sels, dataObj, flatData });
}
this.setState({ data });
}
exchangeValue(arr){
return arr.map(sel => typeof sel === 'object' ? sel : this.state.dataObj[sel]).filter(a => a).filter(item => item[this.props.prop.optgroup] !== true)
}
value(sels, show, listenOn){
if(show !== false && show !== true){
show = this.state.show;
}
let changeData = this.exchangeValue(sels);
this.resetSelectValue(changeData, changeData, true, listenOn);
this.setState({ show })
}
load(data, dataObj, flatData, parent){
const { children, optgroup, value, selected, disabled } = this.props.prop;
data.forEach(item => {
//数据提取/处理
item.__node = { parent }
dataObj[item[value]] = item;
flatData.push(item);
//遍历子级数据
let child = item[children];
if(child && isArray(child)){
item[optgroup] = true;
this.load(child, dataObj, flatData, item);
if(item[selected] === true){
delete item[selected]
child.forEach(c => c[selected] = true)
}
if(item[disabled] === true){
delete item[disabled]
child.forEach(c => c[disabled] = true)
}
let len = child.length;
if(len > 0){
//检查子节点的数据是否都被选中
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;
item.__node.disabled = child.filter(i => i[disabled] === true || i.__node.disabled === true).length === len;
}
}
});
}
//重置已选择数据
resetSelectValue(sels = [], change = [], isAdd, listenOn = true){
let on = this.props.on;
if(isFunction(on) && this.prepare && listenOn){
on({ arr: sels, change, isAdd });
}
this.setState({ sels });
}
updateBorderColor(tmpColor){
this.setState({ tmpColor });
}
treeHandler(sels, parent, change, type){
const { value, selected, disabled, children, optgroup } = this.props.prop;
let child = parent[children];
child.filter(item => !(item[disabled] || item.__node.disabled)).forEach(item => {
if(item[optgroup]){
this.treeHandler(sels, item, change, type);
}else{
let index = sels.findIndex(sel => sel[value] == item[value])
if(type === 'del'){
if(index != -1){
sels.splice(index, 1);
change.push(item);
}
}else if(type === 'half' || type === 'add'){
if(index == -1){
sels.push(item);
change.push(item);
}
}
}
})
let len = child.length;
let slen = child.filter(i => sels.findIndex(sel => sel[value] === i[value]) !== -1 || i.__node.selected === true).length;
parent.__node.selected = slen === len;
parent.__node.half = slen > 0 && slen < len;
}
//选项, 选中状态, 禁用状态, 是否强制删除:在label上点击删除
itemClick(item, itemSelected, itemDisabled, mandatoryDelete){
const { theme, prop, radio, repeat, clickClose, max, maxMethod } = this.props
let { sels } = this.state
const { value, selected, disabled, children, optgroup } = prop
//如果是禁用状态, 不能进行操作
if(itemDisabled) return;
if(item[optgroup]){
let child = item[children], change = [], isAdd = true;
if(item.__node.selected){
this.treeHandler(sels, item, change, 'del');
isAdd = false;
}else if(item.__node.half){
this.treeHandler(sels, item, change, 'half');
}else{
this.treeHandler(sels, item, change, 'add');
}
this.resetSelectValue(sels, change, isAdd);
this.setState({ data: this.state.data })
}else{
//如果现在是选中状态
if(itemSelected && (!repeat || mandatoryDelete)){
let index = sels.findIndex(sel => sel[value] == item[value])
if(index != -1){
sels.splice(index, 1);
this.resetSelectValue(sels, [item], !itemSelected);
}
}else{
//查看是否设置了多选上限
let maxCount = toNum(max);
if(maxCount > 0 && sels.length >= maxCount){
this.updateBorderColor(theme.maxColor);
//查看是否需要回调
maxMethod && isFunction(maxMethod) && maxMethod(sels, item);
return ;
}
//如果是单选模式
if(radio){
sels = [item];
}else{
sels = [...sels, item]
}
this.resetSelectValue(sels, [item], !itemSelected);
}
let parent = item.__node.parent;
if(parent){
while(parent){
let child = parent[children], len = child.length;
let slen = child.filter(i => sels.findIndex(sel => sel[value] === i[value]) !== -1 || i.__node.selected === true).length;
parent.__node.selected = slen === len;
parent.__node.half = slen > 0 && slen < len;
parent = parent.__node.parent;
}
this.setState({ data: this.state.data })
}
}
//检查是否为选择即关闭状态, 强制删除情况下不做处理
clickClose && !mandatoryDelete && this.onClick();
};
//select框被点击
onClick(e){
if(this.props.disabled){
this.state.show !== false && this.setState({ show: false });
return ;
}
let show = !this.state.show;
if(show){
if(this.props.show && this.props.show() == false){
return;
}
//事件互斥原则, 打开一个多选, 关闭其他所有多选
Object.keys(datas).filter(key => key != this.props.el).forEach(el => datas[el].closed())
}else{
if(this.props.hide && this.props.hide() == false){
return;
}
//如果产生滚动条, 关闭下拉后回到顶部
this.bodyView.scroll && this.bodyView.scroll(0, 0);
}
this.setState({ show });
//阻止其他绑定事件的冒泡
e && e.stopPropagation();
}
onReset(data, type){
//重置数据
if(type === 'data'){
let changeData = data.filter(item => item[this.props.prop.selected] === true);
this.resetSelectValue(mergeArr(changeData, this.state.sels, this.props.prop), changeData, true);
let dataObj = {};
let flatData = [];
this.load(data, dataObj, flatData);
this.setState({ data, flatData });
}else
//重置选中数据
if(type === 'sels'){
this.resetSelectValue(data, data, true);
}else
//追加数据
if(type === 'append'){
this.append(data);
}else
//清理数据
if(type === 'delete'){
this.del(data);
}else
//自动判断模式
if(type === 'auto'){
this.auto(data);
}
}
append(arr){
let changeData = this.exchangeValue(arr);
this.resetSelectValue(mergeArr(changeData, this.state.sels, this.props.prop), changeData, true);
}
del(arr){
let value = this.props.prop.value;
let sels = this.state.sels;
arr = this.exchangeValue(arr);
arr.forEach(v => {
let index = sels.findIndex(item => item[value] === v[value]);
if(index != -1){
sels.splice(index, 1);
}
});
this.resetSelectValue(sels, arr, false);
}
auto(arr){
let value = this.props.prop.value;
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);
}
//组件将要接收新属性
componentWillReceiveProps(props){
this.init(props, props.updateData);
}
//组件将要被挂载
componentWillMount(){
this.init(this.props, true);
}
render(config, state) {
const { theme, prop, radio, repeat, clickClose, on, max, maxMethod, content, disabled, tree } = config;
const borderStyle = { borderColor: theme.color };
let { data, dataObj, flatData, sels, show, tmpColor } = state;
//组件为禁用状态
if(disabled){
show = false;
}
//最外层边框的属性
const xmSelectProps = {
style: { ...config.style, ...(show ? borderStyle : {}) },
onClick: this.onClick.bind(this),
ua: checkUserAgent(),
size: config.size,
}
if(tmpColor){
xmSelectProps.style.borderColor = tmpColor;
setTimeout(() => {
xmSelectProps.style.borderColor = '';
this.updateBorderColor('');
}, 300);
}
//普通多选数据
const valueProp = prop.value;
const labelProps = { ...config, data, sels, ck: this.itemClick.bind(this), title: sels.map(sel => sel[prop.name]).join(',') }
const bodyProps = { ...config, data, dataObj, flatData, sels, ck: this.itemClick.bind(this), show, onReset: this.onReset.bind(this) }
//渲染组件
let Body = content ? <Custom { ...bodyProps } /> : tree.show ? <Tree { ...bodyProps } /> : <General { ...bodyProps } />;
return (
<xm-select { ...xmSelectProps } >
<input class="xm-select-default" name={ config.name } value={ sels.map(item => item[prop.value]).join(',') }></input>
<i class={ show ? 'xm-icon xm-icon-expand' : 'xm-icon' } />
{ sels.length === 0 && <div class="xm-tips">{ config.tips }</div> }
<Label { ...labelProps } />
<div class={ show ? 'xm-body' : 'xm-body dis' } ref={ ref => this.bodyView = ref}>
{ Body }
</div>
{ disabled && <div class="xm-select-disabled"></div> }
</xm-select>
);
}
//组件完成挂载
componentDidMount(){
this.prepare = true;
}
//此时页面又被重新渲染了
componentDidUpdate(){
let { direction } = this.props;
let rect = this.base.getBoundingClientRect();
if(direction === 'auto'){
//用于控制js获取下拉框的高度
this.bodyView.style.display = 'block';
this.bodyView.style.visibility = 'hidden';
//获取下拉元素的高度
let bodyViewRect = this.bodyView.getBoundingClientRect();
let bodyViewHeight = bodyViewRect.height;
//还原控制效果
this.bodyView.style.display = '';
this.bodyView.style.visibility = '';
//确定下拉框是朝上还是朝下
let y = rect.y || rect.top || 0;
let clientHeight = document.documentElement.clientHeight;
let diff = clientHeight - y - rect.height - 20;
direction = diff > bodyViewHeight || y < diff ? 'down' : 'up';
}
if(direction == 'down'){
this.bodyView.style.top = rect.height + 4 + 'px';
this.bodyView.style.bottom = 'auto';
}else{
this.bodyView.style.top = 'auto';
this.bodyView.style.bottom = rect.height + 4 + 'px';
}
}
}
export default Framework;

View File

@ -1,109 +1,109 @@
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, true);
//阻止父组件上的事件冒泡
e.stopPropagation();
}
scrollFunc(e){
if(e.wheelDeltaX == 0){
let child = this.labelRef.getElementsByClassName('xm-label-block');
let sum = 10;
for(let i = 0; i < child.length; i++){
sum += child[i].getBoundingClientRect().width + 5;
}
let width = this.labelRef.getBoundingClientRect().width;
let max = sum > width ? sum - width : width;
let left = this.labelRef.scrollLeft + e.deltaY;
left < 0 && (left = 0);
left > max && (left = max);
this.labelRef.scrollLeft = left;
}
}
componentDidMount(){
if (this.labelRef.addEventListener) {
this.labelRef.addEventListener('DOMMouseScroll', this.scrollFunc.bind(this), false);
}
if(this.labelRef.attachEvent){
this.labelRef.attachEvent('onmousewheel', this.scrollFunc.bind(this));
}
this.labelRef.onmousewheel = this.scrollFunc.bind(this);
}
render(config) {
const { data, prop, theme, model, sels, autoRow } = config;
const { name, disabled } = prop;
//获取配置项
const label = model.label;
const type = label.type;
const conf = label[type];
//渲染结果
let html = '';
let innerHTML = true;
if(type === 'text'){
html = sels.map(sel => `${conf.left}${sel[name]}${conf.right}`).join(conf.separator)
}else if(type === 'block'){
innerHTML = false;
//已选择的数据
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 xm-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(',')
}
}
const className = ['xm-label', autoRow ? 'auto-row' : 'single-row'].join(' ');
return (
<div class={ className }>
<div class="scroll" ref={ ref => this.labelRef = ref }>
{ innerHTML ?
<div class="label-content" dangerouslySetInnerHTML={{__html: html}}></div> :
<div class="label-content">{ html }</div>
}
</div>
</div>
)
}
}
export default Label;
import { h, Component, render } from 'preact'
/**
* 标签的渲染
*/
class Label extends Component{
constructor(options){
super(options);
}
iconClick(item, selected, disabled, e){
this.props.ck(item, selected, disabled, true);
//阻止父组件上的事件冒泡
e.stopPropagation();
}
scrollFunc(e){
if(e.wheelDeltaX == 0){
let child = this.labelRef.getElementsByClassName('xm-label-block');
let sum = 10;
for(let i = 0; i < child.length; i++){
sum += child[i].getBoundingClientRect().width + 5;
}
let width = this.labelRef.getBoundingClientRect().width;
let max = sum > width ? sum - width : width;
let left = this.labelRef.scrollLeft + e.deltaY;
left < 0 && (left = 0);
left > max && (left = max);
this.labelRef.scrollLeft = left;
}
}
componentDidMount(){
if (this.labelRef.addEventListener) {
this.labelRef.addEventListener('DOMMouseScroll', this.scrollFunc.bind(this), false);
}
if(this.labelRef.attachEvent){
this.labelRef.attachEvent('onmousewheel', this.scrollFunc.bind(this));
}
this.labelRef.onmousewheel = this.scrollFunc.bind(this);
}
render(config) {
const { data, prop, theme, model, sels, autoRow } = config;
const { name, disabled } = prop;
//获取配置项
const label = model.label;
const type = label.type;
const conf = label[type];
//渲染结果
let html = '';
let innerHTML = true;
if(type === 'text'){
html = sels.map(sel => `${conf.left}${sel[name]}${conf.right}`).join(conf.separator)
}else if(type === 'block'){
innerHTML = false;
//已选择的数据
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 xm-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(',')
}
}
const className = ['xm-label', autoRow ? 'auto-row' : 'single-row'].join(' ');
return (
<div class={ className }>
<div class="scroll" ref={ ref => this.labelRef = ref }>
{ innerHTML ?
<div class="label-content" dangerouslySetInnerHTML={{__html: html}}></div> :
<div class="label-content">{ html }</div>
}
</div>
</div>
)
}
}
export default Label;

View File

@ -0,0 +1,32 @@
import { h, Component, render } from 'preact'
/**
* 默认提示
*/
class Custom extends Component{
constructor(options){
super(options);
}
blockClick(e){
e.stopPropagation();
}
shouldComponentUpdate(){
return !this.prepare;
}
render(config) {
this.prepare = true;
return (
<div onClick={ this.blockClick } class="xm-body-custom" >
<div class="scroll-body" style={ {maxHeight: config.height} }>
<div style="margin: 5px 0" dangerouslySetInnerHTML={{ __html: config.content }}></div>
</div>
</div>
)
}
}
export default Custom;

View File

@ -0,0 +1,412 @@
import { h, Component, render } from 'preact'
import { isFunction, isArray, safety, deepMerge, mergeArr, IEVersion } from '@/common/util'
/**
* 普通的多选渲染
*/
class General extends Component{
constructor(options){
super(options);
this.setState({
filterValue: '',
remote: true,
loading: false,
pageIndex: 1,
pageSize: 10,
});
this.searchCid = 0;
this.inputOver = true;
this.__value = '';
this.dynamicInput = false;
}
optionClick(item, selected, disabled, e){
this.props.ck(item, selected, disabled);
//阻止父组件上的事件冒泡
this.blockClick(e);
}
groupClick(item, e){
const { click, children, disabled } = this.props.prop;
let m = item[click], arr = item[children].filter(opt => !opt[disabled]);
if(m === 'SELECT'){
this.props.onReset(arr, 'append');
}else if(m === 'CLEAR'){
this.props.onReset(arr, 'delete');
}else if(m === 'AUTO'){
this.props.onReset(arr, 'auto');
}else if(isFunction(m)){
m(item);
}
//阻止父组件上的事件冒泡
this.blockClick(e);
}
blockClick(e){
e.stopPropagation();
}
pagePrevClick(e){
let index = this.state.pageIndex;
if(index <= 1){
return ;
}
this.changePageIndex(index - 1);
}
pageNextClick(e, size){
let index = this.state.pageIndex;
if(index >= size){
return ;
}
this.changePageIndex(index + 1);
}
changePageIndex(index){
this.setState({
pageIndex: index
})
}
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, remote: true })
}, 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);
}
}
componentWillReceiveProps(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);
}
}
}
componentDidUpdate(){
if(this.callback){
this.callback = false;
let done = this.props.filterDone;
if(isFunction(done)){
done(this.state.filterValue, this.tempData || []);
}
}
}
render(config) {
let { data, flatData, prop, template, theme, radio, sels, empty, filterable, filterMethod, remoteSearch, remoteMethod, delay, searchTips, create } = config
const { name, value, disabled, children, optgroup } = prop;
let arr = deepMerge([], flatData), creator;
//是否开启了搜索
if(filterable){
if(remoteSearch){//是否进行远程搜索
if(this.state.remote){
this.callback = false;
this.setState({ loading: true, remote: false });
//让输入框失去焦点
this.blur();
remoteMethod(this.state.filterValue, result => {
//回调后可以重新聚焦
this.focus();
this.callback = true;
this.setState({ loading: false });
this.props.onReset(result, 'data');
}, this.props.show);
}
}else{
const filterData = (item, index) => {
const isGroup = item[optgroup];
if(isGroup){
delete item.__del;
return true;
}
return filterMethod(this.state.filterValue, item, index, prop);
}
arr = arr.filter(filterData);
for(let i = 0; i < arr.length - 1; i++){
let a = arr[i];
let b = arr[i + 1];
if(a[optgroup] && b[optgroup]){
arr[i].__del = true;
}
}
if(arr.length && arr[arr.length - 1][optgroup]){
arr[arr.length - 1].__del = true;
}
arr = arr.filter(item => !item.__del);
//创建条目
creator = this.state.filterValue && isFunction(create);
}
}
const search = (
<div class='xm-search'>
<i class="xm-iconfont xm-icon-sousuo"></i>
<input type="text" class="xm-input xm-search-input" placeholder={ searchTips }
ref={ input => this.searchInputRef = input }
onClick={ this.blockClick.bind(this) }
onInput={ this.searchInput.bind(this) }
onCompositionStart={ this.handleComposition.bind(this) }
onCompositionUpdate={ this.handleComposition.bind(this) }
onCompositionEnd={ this.handleComposition.bind(this) }
/>
</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){
//计算当前分页的总页码
let size = Math.floor((arr.length - 1) / config.pageSize) + 1;
size <= 0 && (size = 1);
let pageIndex = this.state.pageIndex;
//如果当前页码大于总页码, 重置一下
if(pageIndex > size){
pageIndex = size;
}
//如有总页码>1, 但是因为搜索造成的页码=0的情况
if(size > 0 && pageIndex <= 0){
pageIndex = 1;
}
//实现简单的物理分页
let start = (pageIndex - 1) * config.pageSize;
let end = start + config.pageSize;
arr = arr.slice(start, end);
const disabledStyle = {cursor: 'no-drop', color: '#d2d2d2'};
let prevStyle = {}, nextStyle = {};
pageIndex <= 1 && (prevStyle = disabledStyle);
pageIndex == size && (nextStyle = disabledStyle);
// const defaultCurrClass = {
// position: 'relative',
// borderRadius: '1px',
// }
// {
// ''.padEnd(size, ' ').split('').map((s, i) => (
// <span style={
// this.state.pageIndex == i + 1 ? {
// ...defaultCurrClass,
// backgroundColor: theme.color,
// borderColor: theme.color,
// color: '#FFF',
// } : defaultCurrClass
// }>{ i + 1 }</span>
// ))
// }
this.state.pageIndex !== pageIndex && this.changePageIndex(pageIndex);
paging = (
<div class='xm-paging'>
<span style={ prevStyle } onClick={ this.pagePrevClick.bind(this) }>上一页</span>
<span>{ this.state.pageIndex } / { size }</span>
<span style={ nextStyle } onClick={ e => this.pageNextClick.bind(this, e, size)() }>下一页</span>
</div>
)
}else{
//检查是否设置了显示数量上限
if(config.showCount > 0){
arr = arr.slice(0, config.showCount);
}
}
let newArr = [], group;
arr.forEach(item => {
let g = groupInfo[item[value]];
if(g != group){
group = g;
newArr.push(group);
}
newArr.push(item);
});
arr = newArr;
//查看是否创建了条目
if(creator){
creator = create(this.state.filterValue, deepMerge([], arr));
creator && arr.splice(0, 0, creator);
}
let safetyArr = deepMerge([], arr);
this.tempData = safetyArr;
//工具条操作
const toolbar = (
<div class='xm-toolbar'>
{ config.toolbar.list.map(tool => {
const toolClass = 'toolbar-tag';
const toolStyle = {};
let info, name = config.languageProp.toolbar[tool];
if(tool === 'ALL'){
info = { icon: 'xm-iconfont xm-icon-quanxuan', name, method: (pageData) => {
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) => {
this.props.onReset(sels.filter(item => item[prop.disabled]), 'sels');
} };
}else if(tool === 'REVERSE'){
info = { icon: 'xm-iconfont xm-icon-fanxuan', name, method: (pageData) => {
const { optgroup, disabled } = prop;
const list = pageData.filter(item => !item[optgroup]).filter(item => !item[disabled])
let selectedList = [];
sels.forEach(item => {
let index = list.findIndex(pageItem => pageItem[value] === item[value]);
if(index == -1){
selectedList.push(item);
}else{
list.splice(index, 1);
}
})
this.props.onReset(mergeArr(list, selectedList, prop), 'sels');
} };
}else if(tool === 'SEARCH'){
toolStyle.color = theme.color;
info = { icon: 'xm-iconfont xm-icon-sousuo', name, method: (pageData) => {
} };
}else {
info = tool
}
const hoverChange = e => {
if(e.type === 'mouseenter') e.target.style.color = theme.color;
if(e.type === 'mouseleave') e.target.style.color = '';
}
return (<div class={ toolClass } style={ toolStyle } onClick={ () => {
isFunction(info.method) && info.method(safetyArr)
} } onMouseEnter={ hoverChange } onMouseLeave={ hoverChange }>
{ config.toolbar.showIcon && <i class={ info.icon }></i> }
<span>{ info.name }</span>
</div>)
}).filter(a => a) }
</div>
)
const showIcon = config.model.icon != 'hidden';
const renderItem = item => {
const selected = !!sels.find(sel => sel[value] == item[value])
const iconStyle = selected ? {
color: theme.color,
border: 'none'
} : {
borderColor: theme.color,
};
const itemStyle = {}
if(!showIcon && selected){
itemStyle.backgroundColor = theme.color;
item[disabled] && (itemStyle.backgroundColor = '#C2C2C2');
}
const className = ['xm-option', (item[disabled] ? ' disabled' : ''), (selected ? ' selected' : ''), (showIcon ? 'show-icon' : 'hide-icon') ].join(' ');
const iconClass = ['xm-option-icon xm-iconfont', radio ? 'xm-icon-danx' : 'xm-icon-duox'].join(' ');
return (
<div class={ className } style={ itemStyle } value={ item[value] } onClick={ this.optionClick.bind(this, item, selected, item[disabled]) }>
{ showIcon && <i class={ iconClass } style={ iconStyle }></i> }
<div class='xm-option-content' dangerouslySetInnerHTML={{ __html: template({ data, item, arr: sels, name: item[name], value: item[value] }) }}></div>
</div>
)
}
const renderGroup = item => {
const isGroup = item[optgroup];
if(isGroup){//分组模式
return (
<div class="xm-group">
<div class="xm-group-item" onClick={ this.groupClick.bind(this, item) }>{ item[name] }</div>
</div>
)
}
return renderItem(item);
}
arr = arr.map(renderGroup);
if(!arr.length){
//查看无数据情况下是否显示分页
!config.pageEmptyShow && (paging = '');
arr.push(<div class="xm-select-empty">{ empty }</div>)
}
return (
<div onClick={ this.blockClick }>
<div>
{ config.toolbar.show && toolbar }
{ filterable && search }
<div class="scroll-body" style={ {maxHeight: config.height} }>{ arr }</div>
{ config.paging && paging }
</div>
{ this.state.loading && <div class="loading" >
<span class="loader"></span>
</div> }
</div>
)
}
}
export default General;

View File

@ -0,0 +1,124 @@
import { h, Component, render } from 'preact'
class Tree extends Component{
constructor(options){
super(options);
this.state = {
expandedKeys: [],
}
}
init(props){
const { tree, dataObj, prop } = props;
const { value } = prop
let keys = [];
tree.expandedKeys.forEach(key => {
keys.push(key);
let item = dataObj[key];
while(item){
let pkey = item[value];
keys.findIndex(k => k === pkey) === -1 && (keys.push(pkey))
item = item.__node.parent
}
});
this.setState({ expandedKeys: keys })
}
blockClick(e){
e.stopPropagation();
}
optionClick(item, selected, disabled, type, e){
if(type === 'line'){
let val = item[this.props.prop.value];
let expandedKeys = this.state.expandedKeys;
let index = expandedKeys.findIndex(v => v === val);
index === -1 ? expandedKeys.push(val) : expandedKeys.splice(index, 1);
this.setState({ expandedKeys });
}else if(type === 'checkbox'){
this.props.ck(item, selected, disabled);
}
//阻止父组件上的事件冒泡
this.blockClick(e);
}
//组件将要接收新属性
componentWillReceiveProps(props){
// this.init(props);
}
//组件将要被挂载
componentWillMount(){
this.init(this.props);
}
render(config, { expandedKeys }) {
let { prop, empty, sels, theme, radio, template, data, tree } = config;
let { name, value, disabled, children } = prop;
const showIcon = config.model.icon != 'hidden';
const renderItem = (item, indent, expand) => {
const half = item.__node.half === true;
const selected = !!sels.find(sel => sel[value] == item[value]) || half || item.__node.selected
const dis = item[disabled] || item.__node.disabled;
const iconStyle = selected || half ? {
color: theme.color,
border: 'none'
} : {
borderColor: theme.color,
};
const itemStyle = { paddingLeft: indent + 'px' }
if(!showIcon && selected){
itemStyle.backgroundColor = theme.color;
dis && (itemStyle.backgroundColor = '#C2C2C2');
}
const className = ['xm-option', (dis ? ' disabled' : ''), (selected ? ' selected' : ''), (showIcon ? 'show-icon' : 'hide-icon') ].join(' ');
const iconClass = ['xm-option-icon xm-iconfont', radio ? 'xm-icon-danx' : half ? 'xm-icon-banxuan' : 'xm-icon-duox'].join(' ');
const treeIconClass = ['xm-tree-icon', expand ? 'expand':'', item[children] && item[children].length > 0 ? 'visible':'hidden'].join(' ');
return (
<div class={ className } style={ itemStyle } value={ item[value] } onClick={ this.optionClick.bind(this, item, selected, item[disabled], 'line') }>
{ tree.showFolderIcon && <i class={ treeIconClass }></i> }
{ tree.showFolderIcon && tree.showLine && <i class={ expand ? 'top-line expand' : 'top-line' } style={ { left: indent - tree.indent + 3 + 'px', width: tree.indent + (expand === 0 ? 10 : -2) + 'px' } }></i> }
{ showIcon && <i class={ iconClass } style={ iconStyle } onClick={ this.optionClick.bind(this, item, selected, item[disabled], 'checkbox') }></i> }
<div class='xm-option-content' dangerouslySetInnerHTML={{ __html: template({ data, item, arr: sels, name: item[name], value: item[value] }) }}></div>
</div>
)
}
const renderGroup = (item, indent) => {
const child = item[children];
indent = indent + tree.indent
if(child && child.length > 0){//分组模式
let expand = this.state.expandedKeys.findIndex(k => item[value] === k) !== -1;
return (
<div class="xm-tree">
{ tree.showFolderIcon && tree.showLine && <i class={ expand ? 'left-line expand' : 'left-line' } style={ {left: indent + 3 + 'px'} }></i> }
{ renderItem(item, indent, expand) }
{ expand && <div class="xm-tree-box">{ child.map(c => renderGroup(c, indent)) }</div> }
</div>
)
}
return renderItem(item, indent, 0);
}
let arr = data.map(item => renderGroup(item, 10 - tree.indent));
if(!arr.length){
//查看无数据情况下是否显示分页
arr.push(<div class="xm-select-empty">{ empty }</div>)
}
return (
<div onClick={ this.blockClick } class="xm-body-tree" >
<div class="scroll-body" style={ {maxHeight: config.height} }>{ arr }</div>
</div>
)
}
}
export default Tree;

View File

@ -1,311 +0,0 @@
var e = function() {},
t = {},
n = [],
o = [];
function r(t, r) {
var i, l, a, s, p = arguments,
u = o;
for (s = arguments.length; s-- > 2;) n.push(p[s]);
for (r && null != r.children && (n.length || n.push(r.children), delete r.children); n.length;)
if ((l = n.pop()) && void 0 !== l.pop)
for (s = l.length; s--;) n.push(l[s]);
else "boolean" == typeof l && (l = null), (a = "function" != typeof t) && (null == l ? l = "" : "number" == typeof l ?
l = String(l) : "string" != typeof l && (a = !1)), a && i ? u[u.length - 1] += l : u === o ? u = [l] : u.push(l), i =
a;
var c = new e;
return c.nodeName = t, c.children = u, c.attributes = null == r ? void 0 : r, c.key = null == r ? void 0 : r.key, c
}
function i(e, t) {
for (var n in t) e[n] = t[n];
return e
}
function l(e, t) {
null != e && ("function" == typeof e ? e(t) : e.current = t)
}
var a = "function" == typeof Promise ? Promise.resolve().then.bind(Promise.resolve()) : setTimeout,
s = /acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i,
p = [];
function u(e) {
!e._dirty && (e._dirty = !0) && 1 == p.push(e) && a(c)
}
function c() {
for (var e; e = p.pop();) e._dirty && U(e)
}
function f(e, t) {
return e.normalizedNodeName === t || e.nodeName.toLowerCase() === t.toLowerCase()
}
function d(e) {
var t = i({}, e.attributes);
t.children = e.children;
var n = e.nodeName.defaultProps;
if (void 0 !== n)
for (var o in n) void 0 === t[o] && (t[o] = n[o]);
return t
}
function v(e) {
var t = e.parentNode;
t && t.removeChild(e)
}
function h(e, t, n, o, r) {
if ("className" === t && (t = "class"), "key" === t);
else if ("ref" === t) l(n, null), l(o, e);
else if ("class" !== t || r)
if ("style" === t) {
if (o && "string" != typeof o && "string" != typeof n || (e.style.cssText = o || ""), o && "object" == typeof o) {
if ("string" != typeof n)
for (var i in n) i in o || (e.style[i] = "");
for (var i in o) e.style[i] = "number" == typeof o[i] && !1 === s.test(i) ? o[i] + "px" : o[i]
}
} else if ("dangerouslySetInnerHTML" === t) o && (e.innerHTML = o.__html || "");
else if ("o" == t[0] && "n" == t[1]) {
var a = t !== (t = t.replace(/Capture$/, ""));
t = t.toLowerCase().substring(2), o ? n || e.addEventListener(t, m, a) : e.removeEventListener(t, m, a), (e._listeners ||
(e._listeners = {}))[t] = o
} else if ("list" !== t && "type" !== t && !r && t in e) {
try {
e[t] = null == o ? "" : o
} catch (e) {}
null != o && !1 !== o || "spellcheck" == t || e.removeAttribute(t)
} else {
var p = r && t !== (t = t.replace(/^xlink:?/, ""));
null == o || !1 === o ? p ? e.removeAttributeNS("http://www.w3.org/1999/xlink", t.toLowerCase()) : e.removeAttribute(
t) : "function" != typeof o && (p ? e.setAttributeNS("http://www.w3.org/1999/xlink", t.toLowerCase(), o) : e.setAttribute(
t, o))
} else e.className = o || ""
}
function m(e) {
return this._listeners[e.type](e)
}
var _ = [],
y = 0,
g = !1,
b = !1;
function C() {
for (var e; e = _.shift();) e.componentDidMount && e.componentDidMount()
}
function x(e, t, n, o, r, i) {
y++ || (g = null != r && void 0 !== r.ownerSVGElement, b = null != e && !("__preactattr_" in e));
var l = function e(t, n, o, r, i) {
var l = t,
a = g;
if (null != n && "boolean" != typeof n || (n = ""), "string" == typeof n || "number" == typeof n) return t && void 0 !==
t.splitText && t.parentNode && (!t._component || i) ? t.nodeValue != n && (t.nodeValue = n) : (l = document.createTextNode(
n), t && (t.parentNode && t.parentNode.replaceChild(l, t), N(t, !0))), l.__preactattr_ = !0, l;
var s, p, u = n.nodeName;
if ("function" == typeof u) return function(e, t, n, o) {
for (var r = e && e._component, i = r, l = e, a = r && e._componentConstructor === t.nodeName, s = a, p = d(t); r &&
!s && (r = r._parentComponent);) s = r.constructor === t.nodeName;
return r && s && (!o || r._component) ? (B(r, p, 3, n, o), e = r.base) : (i && !a && (L(i), e = l = null), r = S(
t.nodeName, p, n), e && !r.nextBase && (r.nextBase = e, l = null), B(r, p, 1, n, o), e = r.base, l && e !== l &&
(l._component = null, N(l, !1))), e
}(t, n, o, r);
if (g = "svg" === u || "foreignObject" !== u && g, u = String(u), (!t || !f(t, u)) && (s = u, (p = g ? document.createElementNS(
"http://www.w3.org/2000/svg", s) : document.createElement(s)).normalizedNodeName = s, l = p, t)) {
for (; t.firstChild;) l.appendChild(t.firstChild);
t.parentNode && t.parentNode.replaceChild(l, t), N(t, !0)
}
var c = l.firstChild,
m = l.__preactattr_,
_ = n.children;
if (null == m) {
m = l.__preactattr_ = {};
for (var y = l.attributes, C = y.length; C--;) m[y[C].name] = y[C].value
}
return !b && _ && 1 === _.length && "string" == typeof _[0] && null != c && void 0 !== c.splitText && null == c.nextSibling ?
c.nodeValue != _[0] && (c.nodeValue = _[0]) : (_ && _.length || null != c) && function(t, n, o, r, i) {
var l, a, s, p, u, c, d, h, m = t.childNodes,
_ = [],
y = {},
g = 0,
b = 0,
C = m.length,
x = 0,
w = n ? n.length : 0;
if (0 !== C)
for (var k = 0; k < C; k++) {
var S = m[k],
P = S.__preactattr_;
null != (B = w && P ? S._component ? S._component.__key : P.key : null) ? (g++, y[B] = S) : (P || (void 0 !== S.splitText ?
!i || S.nodeValue.trim() : i)) && (_[x++] = S)
}
if (0 !== w)
for (k = 0; k < w; k++) {
var B;
if (u = null, null != (B = (p = n[k]).key)) g && void 0 !== y[B] && (u = y[B], y[B] = void 0, g--);
else if (b < x)
for (l = b; l < x; l++)
if (void 0 !== _[l] && (c = a = _[l], h = i, "string" == typeof(d = p) || "number" == typeof d ? void 0 !== c.splitText :
"string" == typeof d.nodeName ? !c._componentConstructor && f(c, d.nodeName) : h || c._componentConstructor ===
d.nodeName)) {
u = a, _[l] = void 0, l === x - 1 && x--, l === b && b++;
break
} u = e(u, p, o, r), s = m[k], u && u !== t && u !== s && (null == s ? t.appendChild(u) : u === s.nextSibling ?
v(s) : t.insertBefore(u, s))
}
if (g)
for (var k in y) void 0 !== y[k] && N(y[k], !1);
for (; b <= x;) void 0 !== (u = _[x--]) && N(u, !1)
}(l, _, o, r, b || null != m.dangerouslySetInnerHTML),
function(e, t, n) {
var o;
for (o in n) t && null != t[o] || null == n[o] || h(e, o, n[o], n[o] = void 0, g);
for (o in t) "children" === o || "innerHTML" === o || o in n && t[o] === ("value" === o || "checked" === o ? e[o] :
n[o]) || h(e, o, n[o], n[o] = t[o], g)
}(l, n.attributes, m), g = a, l
}(e, t, n, o, i);
return r && l.parentNode !== r && r.appendChild(l), --y || (b = !1, i || C()), l
}
function N(e, t) {
var n = e._component;
n ? L(n) : (null != e.__preactattr_ && l(e.__preactattr_.ref, null), !1 !== t && null != e.__preactattr_ || v(e), w(e))
}
function w(e) {
for (e = e.lastChild; e;) {
var t = e.previousSibling;
N(e, !0), e = t
}
}
var k = [];
function S(e, t, n) {
var o, r = k.length;
for (e.prototype && e.prototype.render ? (o = new e(t, n), T.call(o, t, n)) : ((o = new T(t, n)).constructor = e, o.render =
P); r--;)
if (k[r].constructor === e) return o.nextBase = k[r].nextBase, k.splice(r, 1), o;
return o
}
function P(e, t, n) {
return this.constructor(e, n)
}
function B(e, n, o, r, i) {
e._disable || (e._disable = !0, e.__ref = n.ref, e.__key = n.key, delete n.ref, delete n.key, void 0 === e.constructor
.getDerivedStateFromProps && (!e.base || i ? e.componentWillMount && e.componentWillMount() : e.componentWillReceiveProps &&
e.componentWillReceiveProps(n, r)), r && r !== e.context && (e.prevContext || (e.prevContext = e.context), e.context =
r), e.prevProps || (e.prevProps = e.props), e.props = n, e._disable = !1, 0 !== o && (1 !== o && !1 === t.syncComponentUpdates &&
e.base ? u(e) : U(e, 1, i)), l(e.__ref, e))
}
function U(e, t, n, o) {
if (!e._disable) {
var r, l, a, s = e.props,
p = e.state,
u = e.context,
c = e.prevProps || s,
f = e.prevState || p,
v = e.prevContext || u,
h = e.base,
m = e.nextBase,
g = h || m,
b = e._component,
w = !1,
k = v;
if (e.constructor.getDerivedStateFromProps && (p = i(i({}, p), e.constructor.getDerivedStateFromProps(s, p)), e.state =
p), h && (e.props = c, e.state = f, e.context = v, 2 !== t && e.shouldComponentUpdate && !1 === e.shouldComponentUpdate(
s, p, u) ? w = !0 : e.componentWillUpdate && e.componentWillUpdate(s, p, u), e.props = s, e.state = p, e.context =
u), e.prevProps = e.prevState = e.prevContext = e.nextBase = null, e._dirty = !1, !w) {
r = e.render(s, p, u), e.getChildContext && (u = i(i({}, u), e.getChildContext())), h && e.getSnapshotBeforeUpdate &&
(k = e.getSnapshotBeforeUpdate(c, f));
var P, T, M = r && r.nodeName;
if ("function" == typeof M) {
var W = d(r);
(l = b) && l.constructor === M && W.key == l.__key ? B(l, W, 1, u, !1) : (P = l, e._component = l = S(M, W, u), l.nextBase =
l.nextBase || m, l._parentComponent = e, B(l, W, 0, u, !1), U(l, 1, n, !0)), T = l.base
} else a = g, (P = b) && (a = e._component = null), (g || 1 === t) && (a && (a._component = null), T = x(a, r, u, n ||
!h, g && g.parentNode, !0));
if (g && T !== g && l !== b) {
var D = g.parentNode;
D && T !== D && (D.replaceChild(T, g), P || (g._component = null, N(g, !1)))
}
if (P && L(P), e.base = T, T && !o) {
for (var E = e, V = e; V = V._parentComponent;)(E = V).base = T;
T._component = E, T._componentConstructor = E.constructor
}
}
for (!h || n ? _.push(e) : w || e.componentDidUpdate && e.componentDidUpdate(c, f, k); e._renderCallbacks.length;) e._renderCallbacks
.pop().call(e);
y || o || C()
}
}
function L(e) {
var t = e.base;
e._disable = !0, e.componentWillUnmount && e.componentWillUnmount(), e.base = null;
var n = e._component;
n ? L(n) : t && (null != t.__preactattr_ && l(t.__preactattr_.ref, null), e.nextBase = t, v(t), k.push(e), w(t)), l(e.__ref,
null)
}
function T(e, t) {
this._dirty = !0, this.context = t, this.props = e, this.state = this.state || {}, this._renderCallbacks = []
}
i(T.prototype, {
setState: function(e, t) {
this.prevState || (this.prevState = this.state), this.state = i(i({}, this.state), "function" == typeof e ? e(this
.state, this.props) : e), t && this._renderCallbacks.push(t), u(this)
},
forceUpdate: function(e) {
e && this._renderCallbacks.push(e), U(this, 2)
},
render: function() {}
});
var M = function(e, t, n, o) {
for (var r = 1; r < t.length; r++) {
var i = t[r++],
l = "number" == typeof i ? n[i] : i;
1 === t[r] ? o[0] = l : 2 === t[r] ? (o[1] = o[1] || {})[t[++r]] = l : 3 === t[r] ? o[1] = Object.assign(o[1] || {},
l) : o.push(t[r] ? e.apply(null, M(e, l, n, ["", null])) : l)
}
return o
},
W = function(e) {
for (var t, n, o = 1, r = "", i = "", l = [0], a = function(e) {
1 === o && (e || (r = r.replace(/^\s*\n\s*|\s*\n\s*$/g, ""))) ? l.push(e || r, 0) : 3 === o && (e || r) ? (l.push(
e || r, 1), o = 2) : 2 === o && "..." === r && e ? l.push(e, 3) : 2 === o && r && !e ? l.push(!0, 2, r) : 4 ===
o && n && (l.push(e || r, 2, n), n = ""), r = ""
}, s = 0; s < e.length; s++) {
s && (1 === o && a(), a(s));
for (var p = 0; p < e[s].length; p++) t = e[s][p], 1 === o ? "<" === t ? (a(), l = [l], o = 3) : r += t : i ? t ===
i ? i = "" : r += t : '"' === t || "'" === t ? i = t : ">" === t ? (a(), o = 1) : o && ("=" === t ? (o = 4, n = r,
r = "") : "/" === t ? (a(), 3 === o && (l = l[0]), o = l, (l = l[0]).push(o, 4), o = 0) : " " === t || "\t" ===
t || "\n" === t || "\r" === t ? (a(), o = 2) : r += t)
}
return a(), l
},
D = "function" == typeof Map,
E = D ? new Map : {},
V = D ? function(e) {
var t = E.get(e);
return t || E.set(e, t = W(e)), t
} : function(e) {
for (var t = "", n = 0; n < e.length; n++) t += e[n].length + "-" + e[n];
return E[t] || (E[t] = W(e))
};
function A(e, t) {
! function(t, n, o) {
x(o, e, {}, !1, n, !1)
}(0, t, t.firstElementChild)
}
var H = function(e) {
var t = M(this, V(e), arguments, []);
return t.length > 1 ? t : t[0]
}.bind(r);
export {
r as h, H as html, A as render, T as Component
};

View File

@ -0,0 +1,158 @@
import { h, Component, render } from 'preact'
import { datas, optionData, childData } from '@/index.js';
import { selector, warn, listenerClose, isArray, deepMerge, exchangeOptionsData } from '@/common/util'
import Framework from '@/components/framework'
import defaultOptions from '@/config/options'
class xmOptions {
constructor(options) {
this.init(options);
}
init(options){
//定义默认值
this.options = defaultOptions(options.language);
//开始渲染数据
this.update(options);
}
/**
* 更新数据 + 重新渲染
*/
update(options = {}){
let updateData = !!options.data;
//记录最新的配置项
this.options = deepMerge(this.options, options);
//如果dom不存在, 则不进行渲染事项
let dom = selector(this.options.el);
if(!dom){
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 ;
}
render(<Framework { ...this.options } updateData={ updateData } />, dom);
//返回多选对象
return this;
}
/**
* 重置多选, 回到初始化的状态
*/
reset(){
const { el } = this.options
//重新渲染
this.init(optionData[el]);
//子组件初始化
childData[el].init(this.options, true);
return this;
}
/**
* 主动打开多选
*/
opened(){
let ref = childData[this.options.el];
!ref.state.show && ref.onClick();
return this;
}
/**
* 主动关闭多选
*/
closed(){
let ref = childData[this.options.el];
ref.state.show && ref.onClick();
return this;
}
/**
* 获取多选选中的数据
*/
getValue(type){
let arr = deepMerge([], childData[this.options.el].state.sels);
if(type === 'name'){
return arr.map(item => item[this.options.prop.name]);
}else
if(type === 'nameStr'){
return arr.map(item => item[this.options.prop.name]).join(',');
}else
if(type === 'value'){
return arr.map(item => item[this.options.prop.value]);
}else
if(type === 'valueStr'){
return arr.map(item => item[this.options.prop.value]).join(',');
}
return arr;
}
/**
* 设置多选数据
*/
setValue(sels, show, listenOn = false){
if(!isArray(sels)){
warn('请传入数组结构...')
return ;
}
childData[this.options.el].value(sels, show, listenOn);
return this;
}
/**
* 追加赋值
*/
append(sels){
if(!isArray(sels)){
warn('请传入数组结构...')
return ;
}
childData[this.options.el].append(sels);
return this;
}
/**
* 删除赋值
*/
delete(sels){
if(!isArray(sels)){
warn('请传入数组结构...')
return ;
}
childData[this.options.el].del(sels);
return this;
}
/**
* 闪烁警告边框
*/
warning(color, sustain = false){
let showColor = color || this.options.theme.maxColor;
sustain === true ? (
childData[this.options.el].base.style.borderColor = showColor
) : (
childData[this.options.el].updateBorderColor(showColor)
)
return this;
}
}
export default xmOptions;

11
src/config/language/en.js Normal file
View File

@ -0,0 +1,11 @@
export default {
tips: 'please selected',
empty: 'no data',
searchTips: 'please search',
toolbar: {
ALL: 'select all',
CLEAR: 'clear',
REVERSE: 'invert select',
SEARCH: 'search',
}
}

11
src/config/language/zn.js Normal file
View File

@ -0,0 +1,11 @@
export default {
tips: '请选择',
empty: '暂无数据',
searchTips: '请选择',
toolbar: {
ALL: '全选',
CLEAR: '清空',
REVERSE: '反选',
SEARCH: '搜索',
}
}

View File

@ -1,134 +1,141 @@
import zn from './language/zn'
import en from './language/en'
const lanSetting = { zn, en }
export default function (lan = 'zn') {
let setting = lanSetting[lan] || zn;
return {
//配置语言
language: lan,
//所有的语言配置
languageProp: setting,
//多选数据
data: [],
//自定义数据
content: '',
//表单提交的name
name: 'select',
//尺寸
size: 'medium',
//是否禁用多选
disabled: false,
//默认选中数据, 优先级大于selected
initValue: null,
//创建条目
create: null,
//默认提示
tips: setting.tips,
//空数据提示
empty: setting.empty,
//搜索延迟 ms
delay: 500,
//搜索默认提示
searchTips: setting.searchTips,
//是否开始本地搜索
filterable: false,
//本地搜索过滤方法
filterMethod: function(val, item, index, prop){
if(!val) return true;
return item[prop.name].indexOf(val) != -1;
},
//是否开启远程搜索
remoteSearch: false,
//远程搜索回调
remoteMethod: function(val, cb){
cb([]);
},
//下拉方向
direction: 'auto',
//自定义样式
style: {},
//默认多选的高度
height: '200px',
//已选中数据是否自动换行显示
autoRow: false,
//是否开启分页
paging: false,
//分页每页的条数
pageSize: 10,
//分页无数据是否展示分页
pageEmptyShow: true,
//是否开启单选模式
radio: false,
//是否开启重复选模式
repeat: false,
//是否点击选项后自动关闭下拉框
clickClose: false,
//多选上限
max: 0,
maxMethod: function(sels, item){},
//选项显示数量
showCount: 0,
//工具条
toolbar: {
show: false,
showIcon: true,
list: [ 'ALL', 'CLEAR' ],
},
//自定义属性名称
prop: {
name: 'name',
value: 'value',
selected: 'selected',
disabled: 'disabled',
children: 'children',
optgroup: 'optgroup',
click: 'click',
},
//主题配置
theme: {
color: '#009688', //默认主题颜色
maxColor: '#e54d42', //多选上限边框闪烁颜色
},
//模型
model: {
label: {
type: 'block',
text: {
left: '',
right: '',
separator: ', ',
},
block: {
showCount: 0,
showIcon: true,
},
count: {
template(data, sels){
return `已选中 ${sels.length} 项, 共 ${data.length}`
}
},
},
icon: 'show',
},
// 展开下拉框
show(){
},
// 隐藏下拉框
hide(){
},
// 模板组成, 当前option数据, 已经选中的数据, name, value
template({ item, sels, name, value }){
return name;
},
//监听选中事件
on({ arr, item, selected }){
}
}
}
import zn from './language/zn'
import en from './language/en'
const lanSetting = { zn, en }
export default function (lan = 'zn') {
let setting = lanSetting[lan] || zn;
return {
//配置语言
language: lan,
//所有的语言配置
languageProp: setting,
//多选数据
data: [],
//自定义数据
content: '',
//表单提交的name
name: 'select',
//尺寸
size: 'medium',
//是否禁用多选
disabled: false,
//默认选中数据, 优先级大于selected
initValue: null,
//创建条目
create: null,
//默认提示
tips: setting.tips,
//空数据提示
empty: setting.empty,
//搜索延迟 ms
delay: 500,
//搜索默认提示
searchTips: setting.searchTips,
//是否开始本地搜索
filterable: false,
//本地搜索过滤方法
filterMethod: function(val, item, index, prop){
if(!val) return true;
return item[prop.name].indexOf(val) != -1;
},
//是否开启远程搜索
remoteSearch: false,
//远程搜索回调
remoteMethod: function(val, cb){
cb([]);
},
//下拉方向
direction: 'auto',
//自定义样式
style: {},
//默认多选的高度
height: '200px',
//已选中数据是否自动换行显示
autoRow: false,
//是否开启分页
paging: false,
//分页每页的条数
pageSize: 10,
//分页无数据是否展示分页
pageEmptyShow: true,
//是否开启单选模式
radio: false,
//是否开启重复选模式
repeat: false,
//是否点击选项后自动关闭下拉框
clickClose: false,
//多选上限
max: 0,
maxMethod: function(sels, item){},
//选项显示数量
showCount: 0,
//工具条
toolbar: {
show: false,
showIcon: true,
list: [ 'ALL', 'CLEAR' ],
},
tree: {
show: false,
showFolderIcon: true,
showLine: true,
indent: 20,
expandedKeys: [],
},
//自定义属性名称
prop: {
name: 'name',
value: 'value',
selected: 'selected',
disabled: 'disabled',
children: 'children',
optgroup: 'optgroup',
click: 'click',
},
//主题配置
theme: {
color: '#009688', //默认主题颜色
maxColor: '#e54d42', //多选上限边框闪烁颜色
},
//模型
model: {
label: {
type: 'block',
text: {
left: '',
right: '',
separator: ', ',
},
block: {
showCount: 0,
showIcon: true,
},
count: {
template(data, sels){
return `已选中 ${sels.length} 项, 共 ${data.length}`
}
},
},
icon: 'show',
},
// 展开下拉框
show(){
},
// 隐藏下拉框
hide(){
},
// 模板组成, 当前option数据, 已经选中的数据, name, value
template({ item, sels, name, value }){
return name;
},
//监听选中事件
on({ arr, item, selected }){
}
}
}

View File

@ -1,59 +1,48 @@
import { name, version } from '../package.json'
import '@/components/common/expand'
import Core from '@/components/core'
import '@/style/index.less'
import '@/style/iconfont.less'
import { selector, warn } from '@/components/common/util'
const object = {}
const xmSelect = {
name,
import { name, version } from '../package.json'
import { selector, warn } from '@/common/util'
import Select from '@/components/xm-select'
export const datas = {};
export const optionData = {};
export const childData = {};
export default {
name,
version,
render(options) {
let instance = new Core(options);
if(instance){
let { el } = options;
let select = object[el];
select !== undefined && (delete object[el]);
object[el] = instance;
}
return instance;
},
get(filter, single){
let type = Object.prototype.toString.call(filter);
let method;
switch (type){
case '[object String]':
filter && (method = item => item === filter);
break;
case '[object RegExp]':
method = item => filter.test(item);
break;
case '[object Function]':
method = filter;
break;
default:
break;
}
let keys = Object.keys(object)
let list = (method ? keys.filter(method) : keys).map(key => object[key]).filter(instance => selector(instance.options.el));
return single ? list[0] : list;
},
batch(filter, method){
let args = [ ...arguments ];
args.splice(0, 2);
return this.get(filter).map(instance => instance[method](...args));
}
render(options) {
let { el } = options;
optionData[el] = options;
let instance = new Select(options);
//已经渲染
if (instance) {
datas[el] = instance;
}
return instance;
},
get(filter, single) {
let type = Object.prototype.toString.call(filter);
let method;
switch (type) {
case '[object String]':
filter && (method = item => item === filter);
break;
case '[object RegExp]':
method = item => filter.test(item);
break;
case '[object Function]':
method = filter;
break;
default:
break;
}
let keys = Object.keys(datas)
let list = (method ? keys.filter(method) : keys).map(key => datas[key]).filter(instance => selector(instance.options.el));
return single ? list[0] : list;
},
batch(filter, method) {
let args = [...arguments];
args.splice(0, 2);
return this.get(filter).map(instance => instance[method](...args));
}
}
if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
module.exports = xmSelect;
} else if (typeof define === 'function' && define.amd) {
define(xmSelect);
} else if (window.layui && layui.define) {
layui.define(function(exports) {
exports('xmSelect', xmSelect);
});
}
window.xmSelect = xmSelect;

24
src/main.js Normal file
View File

@ -0,0 +1,24 @@
import '@/common/expand'
import '@/style/index.less'
import '@/style/iconfont.less'
import { default as xmSelect, datas } from './index.js';
const moduleName = 'xmSelect';
/**
* 监听全页面点击关闭事件
*/
window.addEventListener('click', () => Object.values(datas).forEach(item => item && item.closed && item.closed()))
if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
module.exports = xmSelect;
} else if (typeof define === 'function' && define.amd) {
define(xmSelect);
} else if (window.layui && layui.define) {
layui.define(function(exports) {
exports(moduleName, xmSelect);
});
}
window[moduleName] = xmSelect;

View File

@ -5,7 +5,7 @@
/* IE9*/
src: url('//at.alicdn.com/t/font_792691_qxv28s6g1l9.eot?t=1534240067831#iefix') format('embedded-opentype'),
/* IE6-IE8 */
url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAsYAAsAAAAAEQwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFY8ukovY21hcAAAAYAAAACrAAACPBtV6wxnbHlmAAACLAAABnEAAAmMovtEvWhlYWQAAAigAAAAMQAAADYSctBCaGhlYQAACNQAAAAgAAAAJAgBA69obXR4AAAI9AAAABsAAAAwMCX//WxvY2EAAAkQAAAAGgAAABoN8gwubWF4cAAACSwAAAAeAAAAIAEiAM9uYW1lAAAJTAAAAUUAAAJtPlT+fXBvc3QAAAqUAAAAhAAAALJ1LunfeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2BkYWacwMDKwMHUyXSGgYGhH0IzvmYwYuRgYGBiYGVmwAoC0lxTGByeMbwwZ27438AQw9zMcAQozAiSAwDk4AxmeJzlks0JwzAMhZ8bN/1xD4GU0h2Se26BbJMJOkkn6KmTPbJF8mT5UGg3qMRn0EPIRs8A9gAq0YsIhDcCLF5SQ9YrnLMe8VB9RSMlMjCxYcueIyfOy7CuAFHU7lP9iqApt5L3ksBJbzlgZ9PVkXDUvbWa6x8T/i0u+XyWKtmmHW0NDI55yeRok2DjaKdg65jX7Bzzm71jXnN08vzJkQvg7Ng/WAYH9Qb3wzM/AHicjVVvbFzFEd/Zfbv7/vn9uXf33vl8Pt/dO99BHOzEZ9/DKTImRS0KjUoLDUFCjtpCMGkT1D9qldQmhkiUSv2G1BBB1VYqilGREOIDViWEGzttqkpI/cAXqyL5gFRALVIF+VCJe9fZd+fEpR/o6d3s7G9mZ2dmZ3aJIKR3h0ZYmVgkIjGZJV8mDxECtenOTDOu1UU+hJoD+TCqzcNMk2V8O5OCbDVRPgZhEt4JCNTZ/4HA3+DfuWIxl8pcFFErG3K7oD7fvev8UaMUmEu259lrRjBsfs6cLhYbRfzSbSjGRVAkfQYihUXsyPkHTVyyZDNmXzSHg3Tl+aPKxpJFqbWGdtLl8w8iYDxuDTQIx7yc1YCdIx7Jk3HSwbwQwGBcyMKZVtG0ZCuJxjFJBb+foMSfhJaPOSr4FYgwSwqIx2MHJALtAdBi/7xcSMJL+fxmmBS2guD61tZm96X02mgcj0J1NAaIR9UMmhXIV24FuLUC71+r1AEmK1AYrQHUK/Tly/m8MrOZz2+FSf7jzc3NK9XR9F2lVq+gmRp0r+HK9B+VJmR263Rgd7ALwR/FOFfx/FeJS0YxQh9drakgMJhaBVizkwgqWxLD6eQ0Qo8f7p44fJziSH9x+PjLZUO+/jZ9+K35X37ljn/Rv+yW4Ziuf2nl4PfS5/LrP47OHTsFJULYjf369UZAEBmSqEOSJmG4Me6LeznA0BFkcDoJlGynVzmH2vY21DhPr25v9DjvbfTp2TXG1s5mlK0q4S7lT++6obbRox/s6CHF2LMEsHvoFfSFQIKnKQMZJVFCD6WH0p0PVvvcRx8uph8eUks0jOFNtskOkpDsJ18k9+NqVRg3qqMCSSerjyRuYUi1/vFH7YIqikGVcD+ehFl/pqPSPKZ6DG6mHisljFhBFvU/PoRkSNd/JHO6Ja5JOXcfwIGJbm/igBq/hn8Kfb57YbYUxyX4cwkLKH1u4gD9GVSL6USxCjjCO2p8VdcvH9XRYIQWqUblu3pR/v2BvXMAc3tTmJiDAQ895B9NL0C9BFdKqqRKczDX/Whg7O1irVbcqZ8/sbfYBOZwihC+6wSDzszUf+dF7rRO1O+fKaDO+nXOr6+vf8L5J44Qe4UvnlyRntwrxMoKzpFdeRJBNb9dGyiur1+nE59R+uwi9M1G395jb9KP0bcK2YM9nJB5cojcS75OFskxclzdc+pW699z8iYbtf14BGKf77ruZNyXKC0e50OEBI+V/Aug5Dex/9WjJfipuqnS00gfybjXbNe1f762tXmRPp3Bdl/l6g5JXyqXR0bK8J3PR+jvwYs8/GBnTM+kr8FX4ZknwC16XtG9iH9QfNn1vDHPe2GAj3ieV3XdF2+IPdeteh62Ra+HfQrsKWKSBtlHSOBgM7KkKQBLWnZoq1mVwotCLRGhOtSkMzMuqq2ml3SqUehdnZtynbtPLB88/Dy9dDrYVzoy/MTT6Svnlpd/AHueon5wpnGsEae/PZm+d3Jp6SSUTy7R3xw4f9/B5RN3O+5t3VNncjm6Cnt+uLx8DpedGj4yvD84HceNxTcG6ku4VPmZ9n6nNdj95BHyB3IJKxBPsKm6rpn4QopmqzlFm1MwqdxO5rPGnIc7aSfCGg1Vqyo6nUlQhnh7WiFhXzgGhVC4qjPRki9xdGCc4zXeSWb9BG1ktlqz2Q5Y7S2sIJfivkpVKCCDpyCWdbQzECj76qMVqvyJ/LxyI2rTv1bTC25lSM9xAUJ4Lc+U0wXTsKXDmaA8tHX+hvDt4Wa9IHLcMUBz9VwpL4xi2aGasAPPKNUbbmD/2jAtk0uXY4eJx8zRgj9iAnVNt5X+BL5vlHTOaiOmG7g6+7ZBNUOaefNXuJF3u25RjVvBLeW8E4wV7ZJBpbAXXGnqrwgupWVTAKqZjq5HbW44fMguNJhgwmw8oOk8GCqE8F3GhLB0uS/UDVt4lgjtqGxK/rpwuaDAqKHZNuWmJjVKuWUxbpg2B9DtoRdN3TKF9B0hw4p41C5i3CI9w4civP3aQLlmLMK3wpJpaI7BvmlhPtH3nPWCKQAdE2hK9zyuUeAm921qCA2kvqY8N1yDMq4beJlG+4XQqHDCQnqPlJIyyN579S4tIGcRv/82BbFfK9SgnVHkZzMeaSQjqR5/fP5XF2Chh+sW0g0gn27snqXv3/bsszsfJbCAIiTdjRTVCBL6jV0K5D8H/8xVAAAAeJxjYGRgYADi16c/vIvnt/nKwM3CAALXZxxzhtH///23YVFhbgZyORiYQKIAm34OJQAAAHicY2BkYGBu+N/AEMOi/P/f//8sKgxAERTAAwCmuAa3eJxjYWBgYAFhRiiNFf//z6L8/x+IDQAkCQRQAAAAAAAAjAEAATgBfgGaAiACbgMMA2AEhATGAAB4nGNgZGBg4GE4DMQgwATEXEDIwPAfzGcAAB2tAfIAAHicZY9NTsMwEIVf+gekEqqoYIfkBWIBKP0Rq25YVGr3XXTfpk6bKokjx63UA3AejsAJOALcgDvwSCebNpbH37x5Y08A3OAHHo7fLfeRPVwyO3INF7gXrlN/EG6QX4SbaONVuEX9TdjHM6bCbXRheYPXuGL2hHdhDx18CNdwjU/hOvUv4Qb5W7iJO/wKt9Dx6sI+5l5XuI1HL/bHVi+cXqnlQcWhySKTOb+CmV7vkoWt0uqca1vEJlODoF9JU51pW91T7NdD5yIVWZOqCas6SYzKrdnq0AUb5/JRrxeJHoQm5Vhj/rbGAo5xBYUlDowxQhhkiMro6DtVZvSvsUPCXntWPc3ndFsU1P9zhQEC9M9cU7qy0nk6T4E9XxtSdXQrbsuelDSRXs1JErJCXta2VELqATZlV44RelzRiT8oZ0j/AAlabsgAAAB4nG2L3QqCQBCFZ9RWU7sOfAeh8IFi3N10EHYUG1p8+gSjqz44F+cPEjgo4T81Jphihic0mGOBZyyxwhovUCxKIe4ylthRuDqV+I22UcLQ6+QH4ubWdZZkU3m4o/0tUqtSvT33TPLits12fzc+zhRcvoquo0o281OLhcMw7Q+AD8sULE0=') format('woff'),
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAksAAsAAAAAEYAAAAjdAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCEUgqTXI8lATYCJAM0CxwABCAFhG0HgTwbZQ4jEbaCkVIj+4sD3pR1GFAIp4fcnExVznDkY6poTaP8+woHw+EnHMKNfx8836/9zn2yu1/EgGTS1ROhmYfkmVCZjoeiFUKEJB4yw9Op/w7VIXHBVNhnuwzCYWJuctqf/TUplM2JBwVtNxeeFQx2AiDNB/4P17SEuttU1NxT62pHHh0FLvkr5IKlv59TW4obkWUQatb9n+IL9BoYMarW7aYmNPmkDAMFbkZvwqsJoWdiWzFhTVpHrPQCa/bkkkMAP2WakcHXARTwMAhKsGENuYnAqwmYSLbgmZ1AUINAq/HDU6XqEcCx/335AZ3iARRWA5HS7ELPKaD3HXzK2/3fHaMPOHq+bmAhBxpoBsyCvQ5aTkHLLlfj346yC0gTpY847xAcSUAsQydd36d9yv8doE36aWJRSJOVRP6fPPBhcQmi0BiEAB5+HBAHgA6mV05q4jvQHL4dA4HDgsHB4YIhoeUyAnAoMGJwaDDp4DBgMkBxLqYTKMB0BYcHZhrq4IdPOcPXUYe254F20C7YVxCTvQ7224IspxVBtMQtU1AoRFlCNJYt4AWdhkSIBEQDkSCCUIBajocT8z+QgxgIAbq6bO3aSk0FRpQ51eXzie22O5F0tOgRJY1Hhv+jGMNySErrQ+SzskZNRdmIlkXF6NhTKKc6lS7XprOVmjSKYek5RFkdgNXNF5A/EIFYWpJQYnsTgM0NtTYLm4wpQwk8miQV6nJRPI+H8fN6Wb7bPcLjYnVdDWWoU27ae0Pleki5H9HeJ6zncfYf8GyZ2027XOMGgPuwxct6PAtZhpJFIymaHVEZyiS32SOR6JY9thDj3HcwizEbL7fmVV2MhDdcysKBmebXXolBOt43C8bsLRCiOZBM2prDYomqi4tNzgTCXhGOWHff4e2dYbOvCeNPZO50flUHoEy1jnptCEtD574hRkkaHRje9z2dWk8VclIcxkaOxpDZhG6Nz4qDaRRGMhxMwNQ2h8a+fSIWs8W17VM43eMvup6dXH6ZazFT0ZDgvc54llOuPNp9jzXtTaWbtZ0PaCa5ljOefNa7gnbnzb4H7/ZgQ0WwJQLRSXQ1wYbgQWkaOYRZgyXEWvmepBwhyfLaRL1NqpcqRMttiYnaEIejG0lTMk0n4lqp7Z1qIyYzeQFmk4TSORO224Nhia6c0VVNmqhlboeQ9ql6vcMYcjo+GLpAV0Uw4/B7gB6fBctt26sStgcn2ZNCENw3jEnKdGchu5EiT0yiK3WoXuATzaS3hdX66wH+6r6XBEQOjhCAzMZgEiJUOExA5IyOFN2BoTqxTGdaVe2O8l/vyhTUeKIDNnnlIwEfujH2m0iZoBRZKS6BwxK/Cbh4TpBMKeOVwpz5iCKBE8WiXZL+gTEYWKY0PC7MzHGN7983OuylYZW1QXkGI8uWdK1oePeuweEAH5TPJGnSxE1rwBtBp8vlR492lw8/dDRTnnX48HB59yNHEuXxH98fOXzksPA66oQs6s+ouOjYg7KDsaSMsCaZiiUlWkLSFyXReYSM0EQ/ge5eFOXTl6OlUbD3IroIeuEzBmjA1KkDIAMhZwMNqH2Ks3dEz8Cl/l33zTs3Szy6tmWJZ31e/3HtZ78NAzJEfQ2VydBrEllsjOUWctuBA+jv3yhMB1KMI+mSp8tghwOGaVmKYUx3g765v3717fvrF00Lfz3rOxYIsn3B30N3c6HKY0dHsPM3nlWGKBcvVggXbmHu3OJCFW0eDwHDcdNmaLMJ983m1kOpiqRiCpe1Ojb8ZHjs6lN4a1Dg7M2mEmGAz7nn+QLOB7wNdYe+DQCkvBb5+BGtldzHD6YH/fChlP7wkUxjBEwjLaT/XyqGpwqmNh5hKcgAJpShEO7R7eRAWH3xHl+IjygmrDAZlIkNJt6EvNmzvMh5ZNDhQY4izZziPb9D+2fufuP2O47fc6fpaFREJP/A7pjdB2ZYVjQR/olR4ZGCA7tlu1pmWHlFgpZdss8EtzeX/mHgDSa7dldNn67q3pUcwDNmHFqTnRP7bg2dG5o6Z6FGReWpVHmUim7B7NRQNR0K4nKy/xn/T/y40TWzuMgki5sVacj/HuDicBnHv3JikWgA5Tdr2LBPU78bFTE9jSWNU+/0S6Qjeo2uX9KjZh/NqyocKug2NLT7DS2U+Wxh8Lq//TWLGq6LMkfUp39Ur45LeJLetMlaaqww91TcHegXIL1FK6ZYT/SAbfoiNPKx8fnUgn/mg6A1i7qnjJvkV25+Gv8qO27ShLJg/9YlCvPflo0WcyG0VzBvnk2U2cfxZ27Vv5dkD3OqVmuF0+j9Xe4GGJSVDrqHQuFsCYVgidx0U6lUyHoWXul6rLlnZl1AEhM7bHUCyPV1EWMgEwLeFu5SHw6hzhbTcSMB2jxQv+3ShR/JTzrfRuYxzD++oM0CwL0FAPg6oACJ9LHlohCSDwAASB/4JMDXjBxBuiXFJzqApC95WDP8wZeCmtNc4/t9JZqADJ9XowDpMsV0Bq40ht8ez+/wKRD/Jzpx7WvWAI/5yg7k+eegHgp2uukjZ+ojio17gxBDZtuPEX+6xuPwaENde4b+EA/TGqUCv7SCKeNgnJfrsCm2bnLMpspyhUsJdMhwX2CIaC63BOgGh4iecj9NjIQOkGAHjZggAI0coVyIclGuCHMDGsQTGBDP5ZY0fyYH6aLL/cxJIsoARzwKzp4C8ASKiStDSVarjjTLNr6DyQceyDBz9w0hIlnWlPVx4Q0shHP4iCezTkkzHejIXhMvcDgQc4F2IFPZYt5tq0qvfJaSjp0ZTwF4stUVQ1xboySr706z1s+/g8kHHiIn7lp/Q4j4cEZDSc1QvtGWdeK9bI8nsyZRt2Z6f6Aj45W64SBnieHCjnYgU0k7YtptqegmzaXL67PH35zu/Hynii9YihItRqw44oonPvFLQIISkjCT7cztRbscSY6K25XKdGkmfWvJGpH3YDg+1JuN5HTL9Kcixqjvvsw0PwMK5JSwKAZ1L80ILo5bNY6UY5vIDRzqPPFozZ4tjsVQvtMBAAA=') format('woff2'),
url('//at.alicdn.com/t/font_792691_qxv28s6g1l9.ttf?t=1534240067831') format('truetype'),
/* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
url('//at.alicdn.com/t/font_792691_qxv28s6g1l9.svg?t=1534240067831#iconfont') format('svg');
@ -59,3 +59,7 @@
.xm-icon-expand:before {
content: "\e641";
}
.xm-icon-banxuan:before {
content: "\e60d";
}

View File

@ -13,31 +13,31 @@
}
@-webkit-keyframes loader {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes loader {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.userselect(@v){
user-select: @v;
-ms-user-select: @v;
-moz-user-select: @v;
-webkit-user-select: @v;
user-select: @v;
-ms-user-select: @v;
-moz-user-select: @v;
-webkit-user-select: @v;
}
xm-select{
@ -67,10 +67,10 @@ xm-select{
& > .xm-tips{
color: #999999;
padding: 0 10px;
position: absolute;
position: absolute;
display: flex;
height: 100%;
align-items: center;
height: 100%;
align-items: center;
}
& > .xm-icon{
@ -96,30 +96,30 @@ xm-select{
}
& > .xm-label{
&.single-row{
position: absolute;
top: 0;
bottom: 0px;
left: 0px;
right: 30px;
overflow: auto hidden;
.scroll{
overflow-y: hidden;
}
.label-content{
flex-wrap: nowrap;
}
}
&.auto-row{
.label-content{
flex-wrap: wrap;
}
}
&.single-row{
position: absolute;
top: 0;
bottom: 0px;
left: 0px;
right: 30px;
overflow: auto hidden;
.scroll{
overflow-y: hidden;
}
.label-content{
flex-wrap: nowrap;
}
}
&.auto-row{
.label-content{
flex-wrap: wrap;
}
}
.scroll{
.label-content{
display: flex;
padding: 3px 30px 3px 10px;
padding: 3px 30px 3px 10px;
}
}
@ -135,7 +135,7 @@ xm-select{
& > span{
display: flex;
color: #FFF;
white-space: nowrap;
white-space: nowrap;
}
& > i{
@ -163,48 +163,47 @@ xm-select{
padding: 5px 0;
z-index: 999;
width: 100%;
min-width: fit-content;
min-width: fit-content;
border: @border;
// max-height: 300px;
// overflow-y: auto;
background-color: #fff;
border-radius: 2px;
box-shadow: 0 2px 4px rgba(0, 0, 0, .12);
animation-fill-mode: both;
animation-name: xm-upbit;
animation-duration: .3s;
animation-fill-mode: both;
.scroll-body{
overflow: auto;
.scroll-body{
overflow: auto;
.scrollBorder() {
-webkit-border-radius: 2em;
-moz-border-radius: 2em;
-ms-border-radius: 2em;
border-radius:2em;
}
.scrollBorder() {
-webkit-border-radius: 2em;
-moz-border-radius: 2em;
-ms-border-radius: 2em;
border-radius:2em;
}
&::-webkit-scrollbar{ width: 8px; }
&::-webkit-scrollbar-track{ .scrollBorder(); background-color: #FFF; }
&::-webkit-scrollbar-thumb{ .scrollBorder(); background-color: #C2C2C2; }
}
&::-webkit-scrollbar{ width: 8px; }
&::-webkit-scrollbar-track{ .scrollBorder(); background-color: #FFF; }
&::-webkit-scrollbar-thumb{ .scrollBorder(); background-color: #C2C2C2; }
}
&.up{
top: auto;
bottom: 42px;
}
.xm-group{
cursor: default;
&-item{
display: inline-block;
cursor: pointer;
padding: 0 10px;
color: #999;
font-size: 12px;
}
}
.xm-group{
cursor: default;
&-item{
display: inline-block;
cursor: pointer;
padding: 0 10px;
color: #999;
font-size: 12px;
}
}
.xm-option{
display: flex;
@ -238,12 +237,12 @@ xm-select{
width: calc(100% - 20px);
}
&.hide-icon .xm-option-content{
padding-left: 0;
}
&.selected.hide-icon .xm-option-content{
color: #FFF !important;
}
&.hide-icon .xm-option-content{
padding-left: 0;
}
&.selected.hide-icon .xm-option-content{
color: #FFF !important;
}
}
.xm-select-empty{
@ -277,7 +276,7 @@ xm-select{
&>i{
position: absolute;
color: @fontColor;
color: @fontColor;
}
&-input{
@ -314,45 +313,95 @@ xm-select{
}
}
.xm-toolbar{
padding: 0 10px;
display: flex;
margin: -3px 0;
cursor: default;
.xm-toolbar{
padding: 0 10px;
display: flex;
margin: -3px 0;
cursor: default;
.toolbar-tag{
cursor: pointer;
display: flex;
margin-right: 20px;
color: @fontColor;
align-items: baseline;
.toolbar-tag{
cursor: pointer;
display: flex;
margin-right: 20px;
color: @fontColor;
align-items: baseline;
&:hover{
opacity: .8;
}
&:active{
opacity: 1;
}
&:hover{
opacity: .8;
}
&:active{
opacity: 1;
}
&>i{
margin-right: 2px;
font-size: 14px;
}
&>i{
margin-right: 2px;
font-size: 14px;
}
&:last-child{
margin-right: 0;
}
}
}
&:last-child{
margin-right: 0;
}
}
}
.xm-body-custom{
line-height: initial;
cursor: default;
.xm-body-custom{
line-height: initial;
cursor: default;
*{
box-sizing: initial;
}
}
.xm-tree{
position: relative;
&-icon{
display: inline-block;
margin-right: 3px;
cursor: pointer;
border: 6px dashed transparent;
border-left-color: #C2C2C2;
border-left-style: solid;
transition: all .3s;
-webkit-transition: all .3s;
z-index: 2;
visibility: hidden;
&.expand{
margin-top: 3px;
margin-right: 5px;
margin-left: -2px;
transform: rotate(90deg);
}
&.visible{
visibility: visible;
}
}
.left-line{
position: absolute;
left: 13px;
width: 0;
z-index: 1;
border-left: 1px dotted #c0c4cc !important;
}
.top-line{
position: absolute;
left: 13px;
height: 0;
z-index: 1;
border-top: 1px dotted #c0c4cc !important;
}
&-box{
&.dis{
}
}
}
.scroll-body>.xm-tree>.xm-option>.top-line{
width: 0 !important;
}
*{
box-sizing: initial;
}
}
}
.xm-input{
@ -368,7 +417,7 @@ xm-select{
line-height: 1.3;
padding-left: 10px;
outline: 0;
.userselect(text);
.userselect(text);
}
.dis{
@ -403,72 +452,94 @@ xm-select{
}
}
.xm-select-default{
display: none !important;
}
.xm-select-default{
display: none !important;
}
.xm-select-disabled{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
cursor: no-drop;
z-index: 2;
opacity: 0.3;
background-color: #FFF;
}
.xm-select-disabled{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
cursor: no-drop;
z-index: 2;
opacity: 0.3;
background-color: #FFF;
}
}
//不同尺寸下的数据调整
.mixin(@size){
@height: @size;
@heightLabel: @height - 6px;
@heightItem: @heightLabel - 4px;
@iconSize: @size / 2;
@height: @size;
@heightLabel: @height - 6px;
@heightItem: @heightLabel - 4px;
@iconSize: @size / 2;
min-height: @height;
line-height: @height;
.xm-input{
height: @height;
}
.xm-label{
.scroll .label-content{
line-height: @heightLabel;
}
.xm-label-block{
height: @heightItem;
line-height: @heightItem;
}
}
.xm-body .xm-option .xm-option-icon{
height: @iconSize;
width: @iconSize;
font-size: @iconSize;
}
.xm-paging>span{
height: @heightLabel;
line-height: @heightLabel;
}
min-height: @height;
line-height: @height;
.xm-input{
height: @height;
}
.xm-label{
.scroll .label-content{
line-height: @heightLabel;
}
.xm-label-block{
height: @heightItem;
line-height: @heightItem;
}
}
.xm-body .xm-option .xm-option-icon{
height: @iconSize;
width: @iconSize;
font-size: @iconSize;
}
.xm-paging>span{
height: @heightLabel;
line-height: @heightLabel;
}
.xm-tree{
.left-line{
height: calc(100% - @size);
top: @size / 2;
bottom: @size / 2;
&.expand{
height: 100%;
bottom: 0;
}
}
&:last-child{
.left-line{
height: calc(100% - @size);
}
}
.xm-tree-icon.hidden+.top-line{
top: @size / 2 - 1px;
}
.xm-tree-icon+.top-line{
margin-left: 1px;
}
}
}
xm-select[size='large']{
.mixin(40px)
.mixin(40px)
}
xm-select{//[size='medium']
.mixin(36px)
.mixin(36px)
}
xm-select[size='small']{
.mixin(32px)
.mixin(32px)
}
xm-select[size='mini']{
.mixin(28px)
.mixin(28px)
}
//layui的一些样式兼容
.layui-form-pane{
xm-select{
margin: -1px -1px -1px 0;
}
xm-select{
margin: -1px -1px -1px 0;
}
}