From 1e9d58f0e6f5c4b402bc9940ced9e6b5e75d4247 Mon Sep 17 00:00:00 2001 From: maplemei Date: Tue, 19 Nov 2019 20:13:50 +0800 Subject: [PATCH] v1.1.0 --- .babelrc | 8 +- .editorconfig | 32 +- .gitee/ISSUE_TEMPLATE.zh-CN.md | 26 +- .gitee/PULL_REQUEST_TEMPLATE.zh-CN.md | 30 +- .gitignore | 4 +- CHANGELOG.md | 419 +-- LICENSE | 402 +-- README.md | 49 +- build/md-loader/containers.js | 48 +- build/md-loader/index.js | 134 +- build/md-loader/util.js | 8 +- build/webpack.config.js | 2 +- dist/index.html | 12 +- dist/static/2.js | 2 +- dist/static/3.js | 2 +- dist/static/docs.js | 10 +- dist/xm-select.js | 2 +- docs/App.vue | 90 +- docs/assets/common.less | 491 +-- docs/entry.js | 2 +- docs/index.ejs | 62 +- docs/mds/XM01.md | 52 +- docs/mds/XM02.md | 54 +- docs/mds/XM03.md | 94 +- docs/mds/XM04.md | 128 +- docs/mds/XM05.md | 366 +- docs/mds/XM06.md | 138 +- docs/mds/XM07.md | 98 +- docs/mds/XM08.md | 352 +- docs/mds/XM09.md | 158 +- docs/mds/XM10.md | 166 +- docs/mds/XM11.md | 70 +- docs/mds/XM12.md | 658 ++-- docs/mds/XM13.md | 126 +- docs/mds/XM14.md | 356 +- docs/mds/XM15.md | 88 +- docs/mds/XM16.md | 157 +- docs/mds/XM17.md | 114 +- docs/mds/XM18.md | 140 +- docs/mds/XM19.md | 310 +- docs/mds/XM20.md | 78 +- docs/mds/XM21.md | 268 +- docs/mds/XM22.md | 214 +- docs/mds/XM23.md | 152 +- docs/mds/XM24.md | 122 +- docs/mds/XM25.md | 176 +- docs/mds/XM26.md | 180 +- docs/mds/XM27.md | 156 +- docs/mds/ZM01.md | 208 +- docs/mds/ZM02.md | 98 +- docs/mds/ZM03.md | 118 +- docs/mds/ZM04.md | 72 +- docs/mds/ZM05.md | 112 +- docs/mds/ZM06.md | 66 +- docs/mds/ZM07.md | 158 +- docs/mds/ZM08.md | 122 +- docs/mds/ZP01.md | 128 +- docs/mds/ZP02.md | 142 +- docs/mds/ZP03.md | 138 +- docs/mds/ZTEST.md | 58 +- docs/mds/es6.md | 292 +- docs/mds/install.md | 32 +- docs/mds/options.md | 442 +-- docs/mds/question.md | 120 +- docs/plugins/eleTree/eleTree.css | 334 +- docs/plugins/eleTree/eleTree.js | 3108 ++++++++--------- docs/plugins/index.js | 2 +- docs/router.js | 237 +- package.json | 3 +- src/{components => }/common/expand.js | 0 src/common/util.js | 166 + src/components/common/util.js | 172 - src/components/config/language/en.js | 11 - src/components/config/language/zn.js | 11 - src/components/core/index.js | 179 - src/components/element/framework.js | 283 -- src/components/element/model/custom.js | 32 - src/components/element/model/general.js | 412 --- src/components/element/tips.js | 20 - src/components/framework/index.js | 384 ++ .../{element/label.js => label/index.js} | 218 +- src/components/plugin/custom.js | 32 + src/components/plugin/general.js | 412 +++ src/components/plugin/tree.js | 124 + src/components/preact/index.js | 311 -- src/components/xm-select/index.js | 158 + src/config/language/en.js | 11 + src/config/language/zn.js | 11 + src/{components => }/config/options.js | 275 +- src/index.js | 103 +- src/main.js | 24 + src/style/iconfont.less | 6 +- src/style/index.less | 385 +- 93 files changed, 8300 insertions(+), 8236 deletions(-) rename src/{components => }/common/expand.js (100%) create mode 100644 src/common/util.js delete mode 100644 src/components/common/util.js delete mode 100644 src/components/config/language/en.js delete mode 100644 src/components/config/language/zn.js delete mode 100644 src/components/core/index.js delete mode 100644 src/components/element/framework.js delete mode 100644 src/components/element/model/custom.js delete mode 100644 src/components/element/model/general.js delete mode 100644 src/components/element/tips.js create mode 100644 src/components/framework/index.js rename src/components/{element/label.js => label/index.js} (56%) create mode 100644 src/components/plugin/custom.js create mode 100644 src/components/plugin/general.js create mode 100644 src/components/plugin/tree.js delete mode 100644 src/components/preact/index.js create mode 100644 src/components/xm-select/index.js create mode 100644 src/config/language/en.js create mode 100644 src/config/language/zn.js rename src/{components => }/config/options.js (64%) create mode 100644 src/main.js diff --git a/.babelrc b/.babelrc index 9c8e353..dad5a1c 100644 --- a/.babelrc +++ b/.babelrc @@ -1,5 +1,5 @@ -{ - "plugins": [ - ["transform-react-jsx", { "pragma":"h" }] - ] +{ + "plugins": [ + ["transform-react-jsx", { "pragma":"h" }] + ] } \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index 6d9db03..3a2aeba 100644 --- a/.editorconfig +++ b/.editorconfig @@ -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 diff --git a/.gitee/ISSUE_TEMPLATE.zh-CN.md b/.gitee/ISSUE_TEMPLATE.zh-CN.md index f09d98d..0992470 100644 --- a/.gitee/ISSUE_TEMPLATE.zh-CN.md +++ b/.gitee/ISSUE_TEMPLATE.zh-CN.md @@ -1,13 +1,13 @@ -### 该问题是怎么引起的? - - - -### 重现步骤 - - - -### 报错信息 - - - - +### 该问题是怎么引起的? + + + +### 重现步骤 + + + +### 报错信息 + + + + diff --git a/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md index 1e5b8d3..069a80b 100644 --- a/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md +++ b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md @@ -1,15 +1,15 @@ -### 相关的Issue - - -### 原因(目的、解决的问题等) - - -### 描述(做了什么,变更了什么) - - -### 测试用例 - - - - - +### 相关的Issue + + +### 原因(目的、解决的问题等) + + +### 描述(做了什么,变更了什么) + + +### 测试用例 + + + + + diff --git a/.gitignore b/.gitignore index a76066d..2ce1aa7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -.DS_Store -node_modules/* +.DS_Store +node_modules/* yarn.lock \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f36831..1136f54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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布局 +- 展开下拉选时, 自动聚焦搜索框 diff --git a/LICENSE b/LICENSE index 4e7217c..7115505 100644 --- a/LICENSE +++ b/LICENSE @@ -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. diff --git a/README.md b/README.md index 363f9c7..89d044b 100644 --- a/README.md +++ b/README.md @@ -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 // ... ``` + +#### 相关 + +> 支持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的一种情怀 ^_^ +``` + diff --git a/build/md-loader/containers.js b/build/md-loader/containers.js index 4be9010..b032b77 100755 --- a/build/md-loader/containers.js +++ b/build/md-loader/containers.js @@ -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 ` - ${description ? `
${md.render(description)}
` : ''} - - `; - } - return '
'; - } - }); - - 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 ` + ${description ? `
${md.render(description)}
` : ''} + + `; + } + return '
'; + } + }); + + md.use(mdContainer, 'tip'); + md.use(mdContainer, 'warning'); +}; diff --git a/build/md-loader/index.js b/build/md-loader/index.js index 80529df..136a10d 100755 --- a/build/md-loader/index.js +++ b/build/md-loader/index.js @@ -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 = ''; - 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(``); - 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 = ``; - } else if (content.indexOf('') + ''.length; - pageScript = content.slice(0, start); - } - - output.push(content.slice(start)); - return ` - - ${pageScript} - `; -}; +const { + stripScript, + stripTemplate, + genInlineComponentText +} = require('./util'); +const md = require('./config'); + +module.exports = function(source) { + const content = md.render(source); + + const startTag = ''; + 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(``); + 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 = ``; + } else if (content.indexOf('') + ''.length; + pageScript = content.slice(0, start); + } + + output.push(content.slice(start)); + return ` + + ${pageScript} + `; +}; diff --git a/build/md-loader/util.js b/build/md-loader/util.js index b138830..f987fd8 100755 --- a/build/md-loader/util.js +++ b/build/md-loader/util.js @@ -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; } diff --git a/build/webpack.config.js b/build/webpack.config.js index 10c6b44..fbf9806 100644 --- a/build/webpack.config.js +++ b/build/webpack.config.js @@ -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: { diff --git a/dist/index.html b/dist/index.html index 4d0f7a1..02646d9 100644 --- a/dist/index.html +++ b/dist/index.html @@ -1,7 +1,7 @@ -xm-select
\ No newline at end of file diff --git a/dist/static/2.js b/dist/static/2.js index dcdae8c..dad2bde 100644 --- a/dist/static/2.js +++ b/dist/static/2.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{697:function(e,t,n){e.exports=n.p+"static/wx.f391ad4.jpg"},698:function(e,t){e.exports="data:image/png;base64,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"},700:function(e,t,n){"use strict";n.r(t);var a=function(){var e=this.$createElement,t=this._self._c||e;return t("section",{staticClass:"content element-doc"},[this._m(0),this._m(1),t("demo-block",[t("template",{slot:"source"},[t("element-demo0")],1),t("template",{slot:"highlight"},[t("pre",{pre:!0},[t("code",{pre:!0,attrs:{class:"html"}},[this._v("
\n\n - <% for (var chunk in htmlWebpackPlugin.files.css) { %> - - <% } %> - <% for (var chunk in htmlWebpackPlugin.files.chunks) { %> - - <% } %> - - - xm-select - - - - - - -
- - - + + + + + <% for (var chunk in htmlWebpackPlugin.files.css) { %> + + <% } %> + <% for (var chunk in htmlWebpackPlugin.files.chunks) { %> + + <% } %> + + + xm-select + + + + + + +
+ + + diff --git a/docs/mds/XM01.md b/docs/mds/XM01.md index 26d9ee1..9708616 100644 --- a/docs/mds/XM01.md +++ b/docs/mds/XM01.md @@ -1,26 +1,26 @@ -## 基础使用 - -:::tip -只需引入`xm-select.js`, 剩下的就只有渲染了 -::: - - -### 一个小栗子 - -:::demo `el`绑定的不一定是id, 也可以是其他css选择器 -```html -
- - -``` -::: - +## 基础使用 + +:::tip +只需引入`xm-select.js`, 剩下的就只有渲染了 +::: + + +### 一个小栗子 + +:::demo `el`绑定的不一定是id, 也可以是其他css选择器 +```html +
+ + +``` +::: + diff --git a/docs/mds/XM02.md b/docs/mds/XM02.md index b56a22e..6822dbf 100644 --- a/docs/mds/XM02.md +++ b/docs/mds/XM02.md @@ -1,28 +1,28 @@ -## 国际化 - - -### 英语 - -:::demo 目前仅支持`中文`和`英文`, 如需更多语言, 可以`clone`代码进行二次开发 -```html -
-
- - -``` +## 国际化 + + +### 英语 + +:::demo 目前仅支持`中文`和`英文`, 如需更多语言, 可以`clone`代码进行二次开发 +```html +
+
+ + +``` ::: \ No newline at end of file diff --git a/docs/mds/XM03.md b/docs/mds/XM03.md index 816fbcf..a389e73 100644 --- a/docs/mds/XM03.md +++ b/docs/mds/XM03.md @@ -1,47 +1,47 @@ -## 默认选中 - - - -### 使用`selected`属性 - -:::demo 当然`selected`是选中, `disabled`是禁用 -```html -
- - -``` -::: - - - -### 使用initValue进行初始化 - -:::demo `initValue`的优先级大于选项中的`selected` -```html -
- - -``` -::: - +## 默认选中 + + + +### 使用`selected`属性 + +:::demo 当然`selected`是选中, `disabled`是禁用 +```html +
+ + +``` +::: + + + +### 使用initValue进行初始化 + +:::demo `initValue`的优先级大于选项中的`selected` +```html +
+ + +``` +::: + diff --git a/docs/mds/XM04.md b/docs/mds/XM04.md index b6810b4..b5a63be 100644 --- a/docs/mds/XM04.md +++ b/docs/mds/XM04.md @@ -1,64 +1,64 @@ -## 修改提示 - - - -### 修改选项提示文字 - -:::demo -```html -
- - -``` -::: - - -### 修改空数据提示文字 - -:::demo -```html -
- - -``` -::: - - -### 修改搜索提示文字 - -:::demo -```html -
- - -``` -::: +## 修改提示 + + + +### 修改选项提示文字 + +:::demo +```html +
+ + +``` +::: + + +### 修改空数据提示文字 + +:::demo +```html +
+ + +``` +::: + + +### 修改搜索提示文字 + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/XM05.md b/docs/mds/XM05.md index bda9fb2..a2b4a24 100644 --- a/docs/mds/XM05.md +++ b/docs/mds/XM05.md @@ -1,183 +1,183 @@ -## 搜索模式 - - - -### 默认搜索 - -:::demo 默认按照`name`进行搜索 -```html -
- - -``` -::: - - -### 重写搜索方法 - -:::demo -```html -
- - -``` -::: - - -### 搜索延迟 - -为了提高有效搜索, 当停止输入`500ms`后才开始进行过滤搜索, 当然这个`500`你也可以进行修改 - -:::demo `delay: 2000` 输入停止2s后进行搜索过滤 -```html -
- - -``` -::: - - -### 自定义搜索 (远程搜索) - -第一步: 需要先开启搜索 `filterable: true,` - -第二步: 开启自定义搜索 `remoteSearch: true` - -第三部: 重写搜索回调 - -简单吧, 记得Star ^_^ - -:::demo `render`后, 就会进行一次回调, 用于渲染第一次数据 -```html -
- - -``` -::: - - -### 远程搜索 - -第一步: 需要先开启搜索 `filterable: true,` - -第二步: 开启自定义搜索 `remoteSearch: true` - -第三部: 重写搜索回调 - -简单吧, 记得Star ^_^ - -:::demo `render`后, 就会进行一次回调, 用于渲染第一次数据 -```html -
- - -``` -::: - - -### 搜索完成回调 - -:::demo -```html -
- - -``` -::: +## 搜索模式 + + + +### 默认搜索 + +:::demo 默认按照`name`进行搜索 +```html +
+ + +``` +::: + + +### 重写搜索方法 + +:::demo +```html +
+ + +``` +::: + + +### 搜索延迟 + +为了提高有效搜索, 当停止输入`500ms`后才开始进行过滤搜索, 当然这个`500`你也可以进行修改 + +:::demo `delay: 2000` 输入停止2s后进行搜索过滤 +```html +
+ + +``` +::: + + +### 自定义搜索 (远程搜索) + +第一步: 需要先开启搜索 `filterable: true,` + +第二步: 开启自定义搜索 `remoteSearch: true` + +第三部: 重写搜索回调 + +简单吧, 记得Star ^_^ + +:::demo `render`后, 就会进行一次回调, 用于渲染第一次数据 +```html +
+ + +``` +::: + + +### 远程搜索 + +第一步: 需要先开启搜索 `filterable: true,` + +第二步: 开启自定义搜索 `remoteSearch: true` + +第三部: 重写搜索回调 + +简单吧, 记得Star ^_^ + +:::demo `render`后, 就会进行一次回调, 用于渲染第一次数据 +```html +
+ + +``` +::: + + +### 搜索完成回调 + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/XM06.md b/docs/mds/XM06.md index 85c7e9a..c234a30 100644 --- a/docs/mds/XM06.md +++ b/docs/mds/XM06.md @@ -1,69 +1,69 @@ -## 下拉方向 - - -### 自动`auto` - -:::demo -```html -
占位div, 演示效果使用, 底部空间不足时会自动向上展开
- -
- - -``` -::: - - -### 打卡向上`up` - -:::demo -```html -
- - -``` -::: - - -### 打开向下`down` - -:::demo -```html -
- - -``` -::: +## 下拉方向 + + +### 自动`auto` + +:::demo +```html +
占位div, 演示效果使用, 底部空间不足时会自动向上展开
+ +
+ + +``` +::: + + +### 打卡向上`up` + +:::demo +```html +
+ + +``` +::: + + +### 打开向下`down` + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/XM07.md b/docs/mds/XM07.md index 3169923..4494f65 100644 --- a/docs/mds/XM07.md +++ b/docs/mds/XM07.md @@ -1,49 +1,49 @@ -## 自定义样式 - -### 随便试试 - -修改一下外边距, 加上圆角, 更改一下高度 - -:::demo -```html -
- - -``` -::: - - -### 修改下拉框的最大高度 - - -:::demo -```html -
- - -``` -::: +## 自定义样式 + +### 随便试试 + +修改一下外边距, 加上圆角, 更改一下高度 + +:::demo +```html +
+ + +``` +::: + + +### 修改下拉框的最大高度 + + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/XM08.md b/docs/mds/XM08.md index 2987735..0e82e41 100644 --- a/docs/mds/XM08.md +++ b/docs/mds/XM08.md @@ -1,176 +1,176 @@ -## 分页 - -### 启用分页 - -``` -xmSelect.render({ - //... - paging: true, -}) -``` - -:::demo -```html -
- - -``` -::: - - -### 自定义条数 - -每页3条 - -``` -xmSelect.render({ - //... - paging: true, - pageSize: 3, -}) -``` - -:::demo -```html -
- - -``` -::: - - -### 搜索+分页 - -``` -xmSelect.render({ - //... - paging: true, - pageSize: 5, - filterable: true, -}) -``` - -:::demo -```html -
- - - - - -``` -::: - - -### 搜索 + 分页 无数据 不展示分页 - -``` -xmSelect.render({ - //... - paging: true, - pageSize: 3, - filterable: true, - pageEmptyShow: false, -}) -``` - -:::demo -```html -
- - -``` -::: +## 分页 + +### 启用分页 + +``` +xmSelect.render({ + //... + paging: true, +}) +``` + +:::demo +```html +
+ + +``` +::: + + +### 自定义条数 + +每页3条 + +``` +xmSelect.render({ + //... + paging: true, + pageSize: 3, +}) +``` + +:::demo +```html +
+ + +``` +::: + + +### 搜索+分页 + +``` +xmSelect.render({ + //... + paging: true, + pageSize: 5, + filterable: true, +}) +``` + +:::demo +```html +
+ + + + + +``` +::: + + +### 搜索 + 分页 无数据 不展示分页 + +``` +xmSelect.render({ + //... + paging: true, + pageSize: 3, + filterable: true, + pageEmptyShow: false, +}) +``` + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/XM09.md b/docs/mds/XM09.md index dd4da53..2c59c61 100644 --- a/docs/mds/XM09.md +++ b/docs/mds/XM09.md @@ -1,79 +1,79 @@ -## 单选 - -### 开启单选 - - -:::demo -```html -
- - -``` -::: - - -### 单选完关闭下拉 - -:::demo -```html -
- - -``` -::: - - -### 更换显示方式 - -:::demo -```html -
- - -``` -::: +## 单选 + +### 开启单选 + + +:::demo +```html +
+ + +``` +::: + + +### 单选完关闭下拉 + +:::demo +```html +
+ + +``` +::: + + +### 更换显示方式 + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/XM10.md b/docs/mds/XM10.md index 3e7d856..316eb7f 100644 --- a/docs/mds/XM10.md +++ b/docs/mds/XM10.md @@ -1,83 +1,83 @@ -## 重复选 - -### 开启重复选 - - -:::demo -```html -
- - -``` -::: - - -### 重复选完关闭下拉 - -:::demo -```html -
- - -``` -::: - - -### 更换显示方式 - -:::demo 好像这样只能增不能减了~~ 有待完善 -```html -
- - -``` -::: +## 重复选 + +### 开启重复选 + + +:::demo +```html +
+ + +``` +::: + + +### 重复选完关闭下拉 + +:::demo +```html +
+ + +``` +::: + + +### 更换显示方式 + +:::demo 好像这样只能增不能减了~~ 有待完善 +```html +
+ + +``` +::: diff --git a/docs/mds/XM11.md b/docs/mds/XM11.md index 0de31d2..c1cdf06 100644 --- a/docs/mds/XM11.md +++ b/docs/mds/XM11.md @@ -1,35 +1,35 @@ -## 自定义属性 - -### 更换属性key - -也许你的数据库返回的并不是`name`和`value`, 也许你提交的时候不止`name`和`value`, 怎么办? 自定义就行 - - -:::demo 我的`name`是`label`, 我的`value`是`id`, 我有其他属性`group` -```html -
- -

-
-
-```
-:::
+## 自定义属性
+
+### 更换属性key
+
+也许你的数据库返回的并不是`name`和`value`, 也许你提交的时候不止`name`和`value`, 怎么办? 自定义就行
+
+
+:::demo 我的`name`是`label`, 我的`value`是`id`, 我有其他属性`group`
+```html
+
+ +

+
+
+```
+:::
diff --git a/docs/mds/XM12.md b/docs/mds/XM12.md
index 7a53333..d9af38a 100644
--- a/docs/mds/XM12.md
+++ b/docs/mds/XM12.md
@@ -1,329 +1,329 @@
-## 主题
-
-### 经典绿 ( #009688 )
-
-:::demo 
-```html
-
- - -``` -::: - - -### 嫣红 ( #e54d42 ) - -:::demo -```html -
- - -``` -::: - - -### 桔橙 ( #f37b1d ) - -:::demo -```html -
- - -``` -::: - - -### 明黄 ( #fbbd08 ) - -:::demo -```html -
- - -``` -::: - - -### 橄榄 ( #8dc63f ) - -:::demo -```html -
- - -``` -::: - - -### 天青 ( #1cbbb4 ) - -:::demo -```html -
- - -``` -::: - - -### 海蓝 ( #0081ff ) - -:::demo -```html -
- - -``` -::: - - -### 姹紫 ( #6739b6 ) - -:::demo -```html -
- - -``` -::: - - -### 木槿 ( #9c26b0 ) - -:::demo -```html -
- - -``` -::: - - -### 桃粉 ( #e03997 ) - -:::demo -```html -
- - -``` -::: - - -### 棕褐 ( #a5673f ) - -:::demo -```html -
- - -``` -::: - - -### 玄灰 ( #8799a3 ) - -:::demo -```html -
- - -``` -::: - - -### 草灰 ( #aaaaaa ) - -:::demo -```html -
- - -``` -::: - - -### 墨黑 ( #333333 ) - -:::demo -```html -
- - -``` -::: - - - - - - - -:::warning -颜色值来源于[ColorUI](https://github.com/weilanwl/ColorUI), 有兴趣的可以看看 -::: +## 主题 + +### 经典绿 ( #009688 ) + +:::demo +```html +
+ + +``` +::: + + +### 嫣红 ( #e54d42 ) + +:::demo +```html +
+ + +``` +::: + + +### 桔橙 ( #f37b1d ) + +:::demo +```html +
+ + +``` +::: + + +### 明黄 ( #fbbd08 ) + +:::demo +```html +
+ + +``` +::: + + +### 橄榄 ( #8dc63f ) + +:::demo +```html +
+ + +``` +::: + + +### 天青 ( #1cbbb4 ) + +:::demo +```html +
+ + +``` +::: + + +### 海蓝 ( #0081ff ) + +:::demo +```html +
+ + +``` +::: + + +### 姹紫 ( #6739b6 ) + +:::demo +```html +
+ + +``` +::: + + +### 木槿 ( #9c26b0 ) + +:::demo +```html +
+ + +``` +::: + + +### 桃粉 ( #e03997 ) + +:::demo +```html +
+ + +``` +::: + + +### 棕褐 ( #a5673f ) + +:::demo +```html +
+ + +``` +::: + + +### 玄灰 ( #8799a3 ) + +:::demo +```html +
+ + +``` +::: + + +### 草灰 ( #aaaaaa ) + +:::demo +```html +
+ + +``` +::: + + +### 墨黑 ( #333333 ) + +:::demo +```html +
+ + +``` +::: + + + + + + + +:::warning +颜色值来源于[ColorUI](https://github.com/weilanwl/ColorUI), 有兴趣的可以看看 +::: diff --git a/docs/mds/XM13.md b/docs/mds/XM13.md index 1bbed3f..bb79996 100644 --- a/docs/mds/XM13.md +++ b/docs/mds/XM13.md @@ -1,63 +1,63 @@ -## 显示与隐藏 - - -### 主动打开/关闭下拉框 - -:::demo -```html -
- - - - -``` -::: - -### 监听打开/关闭下拉框 - -:::demo -```html -
- - -``` -::: +## 显示与隐藏 + + +### 主动打开/关闭下拉框 + +:::demo +```html +
+ + + + +``` +::: + +### 监听打开/关闭下拉框 + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/XM14.md b/docs/mds/XM14.md index c4c8f2b..bb9b249 100644 --- a/docs/mds/XM14.md +++ b/docs/mds/XM14.md @@ -1,178 +1,178 @@ -## 显示方式 - - -### 方块形状 - -:::demo -```html -
- - -``` -::: - - -### 方块形状, 隐藏删除图标 - -:::demo -```html -
- - -``` -::: - - -### 方块形状, 超过1个隐藏 - -:::demo -```html -
- - -``` -::: - - -### 简单拼接形式 - -:::demo -```html -
- - -``` -::: - - -### 自定义显示 - -:::demo -```html -
- - -``` -::: - - -### 自定义显示HTML - -:::demo -```html -
- - -``` -::: +## 显示方式 + + +### 方块形状 + +:::demo +```html +
+ + +``` +::: + + +### 方块形状, 隐藏删除图标 + +:::demo +```html +
+ + +``` +::: + + +### 方块形状, 超过1个隐藏 + +:::demo +```html +
+ + +``` +::: + + +### 简单拼接形式 + +:::demo +```html +
+ + +``` +::: + + +### 自定义显示 + +:::demo +```html +
+ + +``` +::: + + +### 自定义显示HTML + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/XM15.md b/docs/mds/XM15.md index cfe1a1c..ea65237 100644 --- a/docs/mds/XM15.md +++ b/docs/mds/XM15.md @@ -1,44 +1,44 @@ -## 构建选项 - - -### 默认渲染 - -:::demo -```html -
- - -``` -::: - - -### 自定义渲染 - -:::demo -```html -
- - -``` -::: +## 构建选项 + + +### 默认渲染 + +:::demo +```html +
+ + +``` +::: + + +### 自定义渲染 + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/XM16.md b/docs/mds/XM16.md index e0774b5..f518e62 100644 --- a/docs/mds/XM16.md +++ b/docs/mds/XM16.md @@ -1,76 +1,81 @@ -## 监听选择 - - -### 实时监听 - -实时监听多选的选中状态变化 - -:::demo -```html -
- -

- - - - -``` -::: - - -### 监听+动态赋值 - -选中北京后, 不能选中上海, 二者互斥 - -:::demo -```html -
- - -``` -::: +## 监听选择 + + +### 实时监听 + +实时监听多选的选中状态变化 + +:::demo +```html +
+ +

+ + + + +``` +::: + + +### 监听+动态赋值 + +选中北京后, 不能选中上海, 二者互斥 + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/XM17.md b/docs/mds/XM17.md index 1a61723..c71ac2a 100644 --- a/docs/mds/XM17.md +++ b/docs/mds/XM17.md @@ -1,57 +1,57 @@ -## 性能测试 - - -### 数据渲染耗时测试 - - -:::demo 事实证明分页是好使的 ^_^ -```html -
- - - -

-
-
-```
-:::
+## 性能测试
+
+
+### 数据渲染耗时测试
+
+
+:::demo 事实证明分页是好使的 ^_^
+```html
+
+ + + +

+
+
+```
+:::
diff --git a/docs/mds/XM18.md b/docs/mds/XM18.md
index 3bc5b0d..2fcf191 100644
--- a/docs/mds/XM18.md
+++ b/docs/mds/XM18.md
@@ -1,70 +1,70 @@
-## 多选上限
-
-
-### 最多选择2个
-
-:::demo 
-```html
-
- - -``` -::: - - -### 自定义选超的提示 - -:::demo -```html -
- - -``` -::: - - -### 自定义选超的闪烁颜色 - -:::demo -```html -
- - -``` -::: +## 多选上限 + + +### 最多选择2个 + +:::demo +```html +
+ + +``` +::: + + +### 自定义选超的提示 + +:::demo +```html +
+ + +``` +::: + + +### 自定义选超的闪烁颜色 + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/XM19.md b/docs/mds/XM19.md index dcc5a85..5229451 100644 --- a/docs/mds/XM19.md +++ b/docs/mds/XM19.md @@ -1,156 +1,156 @@ -## 工具条 - - -### 默认工具条 - -:::demo -```html -
- - -``` -::: - - -### 隐藏图标 - -:::demo -```html -
- - -``` -::: - - -### 自定义工具条 - -:::demo -```html -
- - -``` -::: - - -### 全部工具条 - -``` -//全选, 清空, 反选 -xmSelect.render({ - toolbar: { - show: true, - list: [ 'ALL', 'CLEAR', 'REVERSE' ] - }, -}) -``` - -:::demo -```html -
- - -``` +## 工具条 + + +### 默认工具条 + +:::demo +```html +
+ + +``` +::: + + +### 隐藏图标 + +:::demo +```html +
+ + +``` +::: + + +### 自定义工具条 + +:::demo +```html +
+ + +``` +::: + + +### 全部工具条 + +``` +//全选, 清空, 反选 +xmSelect.render({ + toolbar: { + show: true, + list: [ 'ALL', 'CLEAR', 'REVERSE' ] + }, +}) +``` + +:::demo +```html +
+ + +``` ::: \ No newline at end of file diff --git a/docs/mds/XM20.md b/docs/mds/XM20.md index 6111751..f81f18b 100644 --- a/docs/mds/XM20.md +++ b/docs/mds/XM20.md @@ -1,39 +1,39 @@ -## 选项显示数量 - - - -:::tip -当数量量过大时, 又不想使用分页的形式, 就可以控制显示数量, 用搜索的方式把最适合的数据展示出来 - -!!! 此处与分页配置互斥, 开启分页后, 此配置无效 - -!!! 使用此配置时建议开启搜索模式, 否则无法显示全部数据 -::: - -:::demo -```html -
-
可以搜索 1, 2, 3看看效果
- - -``` -::: +## 选项显示数量 + + + +:::tip +当数量量过大时, 又不想使用分页的形式, 就可以控制显示数量, 用搜索的方式把最适合的数据展示出来 + +!!! 此处与分页配置互斥, 开启分页后, 此配置无效 + +!!! 使用此配置时建议开启搜索模式, 否则无法显示全部数据 +::: + +:::demo +```html +
+
可以搜索 1, 2, 3看看效果
+ + +``` +::: diff --git a/docs/mds/XM21.md b/docs/mds/XM21.md index 9e5032c..6d60af0 100644 --- a/docs/mds/XM21.md +++ b/docs/mds/XM21.md @@ -1,164 +1,104 @@ -## 分组 - - -### optgroup模式 - -:::demo 指定选项中的`optgroup`为`true` -```html -
- - -``` -::: - - -### children模式 - -:::demo 选项中的`children`为数组 -```html -
- - -``` -::: - - -### 混合模式 - -如果自己感觉舒服的话, 也可以这么用... - -:::demo -```html - -
- - -``` -::: - - -### 分组的单击事件 - -:::demo -```html -
- - -``` -::: - - -### 带有分页的分组 - -:::demo -```html -
- - -``` -::: +## 分组 + + +### children模式 + +:::demo 选项中的`children`为数组 +```html +
+ + +``` +::: + + +### 分组的单击事件 + +:::demo +```html +
+ + +``` +::: + + +### 带有分页的分组 + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/XM22.md b/docs/mds/XM22.md index d7f4fe5..709f04f 100644 --- a/docs/mds/XM22.md +++ b/docs/mds/XM22.md @@ -1,107 +1,107 @@ -## 自动换行 - - - -:::tip -当需要选择很多选项时, 横向滚动满足不了你的需求, 可以开启自动换行 -::: - - -### 开启换行 - -:::demo `autoRow` = `true` -```html -
- - -``` -::: - - -### Layui风格 - -前面的label居中 需要 **自行** 加一段css, 这里就没有内置到插件中了, 避免样式污染, 当前或许你有更好的css解决方案 ^_^ -```css -.layui-form-pane .layui-form-label{ - display: flex; - align-items: center; - justify-content: center; -} -``` - -:::demo -```html -
-
- -
-
-
-
-
- -
-
- -
-
-
-
-
- - -``` -::: +## 自动换行 + + + +:::tip +当需要选择很多选项时, 横向滚动满足不了你的需求, 可以开启自动换行 +::: + + +### 开启换行 + +:::demo `autoRow` = `true` +```html +
+ + +``` +::: + + +### Layui风格 + +前面的label居中 需要 **自行** 加一段css, 这里就没有内置到插件中了, 避免样式污染, 当前或许你有更好的css解决方案 ^_^ +```css +.layui-form-pane .layui-form-label{ + display: flex; + align-items: center; + justify-content: center; +} +``` + +:::demo +```html +
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
+
+ + +``` +::: diff --git a/docs/mds/XM23.md b/docs/mds/XM23.md index 7907b35..2d0f9f7 100644 --- a/docs/mds/XM23.md +++ b/docs/mds/XM23.md @@ -1,76 +1,76 @@ -## 隐藏图标 - - -### 隐藏单选图标 - -:::demo -```html -
-
- - -``` -::: - - -### 隐藏多选图标 - -:::demo -```html -
- - -``` -::: +## 隐藏图标 + + +### 隐藏单选图标 + +:::demo +```html +
+
+ + +``` +::: + + +### 隐藏多选图标 + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/XM24.md b/docs/mds/XM24.md index d74c7c1..be040f4 100644 --- a/docs/mds/XM24.md +++ b/docs/mds/XM24.md @@ -1,61 +1,61 @@ -## 尺寸 - - -### 四种尺寸变换 - - - -:::demo `large`, `medium`, `small`, `mini` -```html -
-
-
-
- - -``` -::: +## 尺寸 + + +### 四种尺寸变换 + + + +:::demo `large`, `medium`, `small`, `mini` +```html +
+
+
+
+ + +``` +::: diff --git a/docs/mds/XM25.md b/docs/mds/XM25.md index 5945caf..9195d2f 100644 --- a/docs/mds/XM25.md +++ b/docs/mds/XM25.md @@ -1,88 +1,88 @@ -## 警告 - - -### 警告提示 - -放下她, 让我来!!! 默认颜色`#e54d42`, 多选上限的样色 - -``` -/* - * COLOR: 自定义颜色, 默认是 options.theme.maxColor的颜色 - * SUSTAIN: 是否持续显示, 默认为false - */ -xmSelectObj.warning(COLOR, SUSTAIN); -``` - - -:::demo -```html -
- - - -``` -::: - - -### 自定义闪烁颜色 - -:::demo -```html -
- - - -``` -::: - - -### 持续显示 - -:::demo -```html -
- - - -``` -::: - +## 警告 + + +### 警告提示 + +放下她, 让我来!!! 默认颜色`#e54d42`, 多选上限的样色 + +``` +/* + * COLOR: 自定义颜色, 默认是 options.theme.maxColor的颜色 + * SUSTAIN: 是否持续显示, 默认为false + */ +xmSelectObj.warning(COLOR, SUSTAIN); +``` + + +:::demo +```html +
+ + + +``` +::: + + +### 自定义闪烁颜色 + +:::demo +```html +
+ + + +``` +::: + + +### 持续显示 + +:::demo +```html +
+ + + +``` +::: + diff --git a/docs/mds/XM26.md b/docs/mds/XM26.md index 1ebba1f..66a1472 100644 --- a/docs/mds/XM26.md +++ b/docs/mds/XM26.md @@ -1,90 +1,90 @@ -## 禁用 - - -### 渲染禁用 - -``` -xmSelect.render({ - //... - disabled: true -}) -``` - -:::demo -```html -
- - -``` -::: - - -### 动态启用禁用 - -:::demo -```html -
- - - - -``` -::: - - -### 选完`张三`后禁用 - -:::demo -```html -
- - - -``` -::: +## 禁用 + + +### 渲染禁用 + +``` +xmSelect.render({ + //... + disabled: true +}) +``` + +:::demo +```html +
+ + +``` +::: + + +### 动态启用禁用 + +:::demo +```html +
+ + + + +``` +::: + + +### 选完`张三`后禁用 + +:::demo +```html +
+ + + +``` +::: diff --git a/docs/mds/XM27.md b/docs/mds/XM27.md index ae1494d..baa34fe 100644 --- a/docs/mds/XM27.md +++ b/docs/mds/XM27.md @@ -1,78 +1,78 @@ -## 创建条目 - - -### 搜索不存在则创建条目 - -``` -//想创建就必须要开启本地搜索 -xmSelect.render({ - //... - filterable: true, - create: function(val){ - //返回一个创建成功的对象, val是搜索的数据 - return { - name: '创建-' + val, - value: val - } - } -}) -``` - -:::demo -```html -
- - -``` -::: - - -### 单选创建 - -:::demo -```html -
- - -``` -::: +## 创建条目 + + +### 搜索不存在则创建条目 + +``` +//想创建就必须要开启本地搜索 +xmSelect.render({ + //... + filterable: true, + create: function(val){ + //返回一个创建成功的对象, val是搜索的数据 + return { + name: '创建-' + val, + value: val + } + } +}) +``` + +:::demo +```html +
+ + +``` +::: + + +### 单选创建 + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/ZM01.md b/docs/mds/ZM01.md index 32a60fd..be5d185 100644 --- a/docs/mds/ZM01.md +++ b/docs/mds/ZM01.md @@ -1,104 +1,104 @@ -## 赋值与取值 - - -### 给多选赋值 - -函数`setValue(array)`, 动态赋值多选选中的数据, array可以是value数组, 也可以是完整的object数组 - -:::demo -```html -
-

- - - -

- - -

-
-
-```
-:::
-
-
-### 取值
-
-函数`getValue(type)`, type类型 name, nameStr, value, valueStr
-
-:::demo 
-```html
-
- - -

- - - - - - -

-
-
-
-```
-:::
+## 赋值与取值
+
+
+### 给多选赋值
+
+函数`setValue(array)`, 动态赋值多选选中的数据, array可以是value数组, 也可以是完整的object数组
+
+:::demo 
+```html
+
+

+ + + +

+ + +

+
+
+```
+:::
+
+
+### 取值
+
+函数`getValue(type)`, type类型 name, nameStr, value, valueStr
+
+:::demo 
+```html
+
+ + +

+ + + + + + +

+
+
+
+```
+:::
diff --git a/docs/mds/ZM02.md b/docs/mds/ZM02.md
index b7fe88d..837f9aa 100644
--- a/docs/mds/ZM02.md
+++ b/docs/mds/ZM02.md
@@ -1,50 +1,50 @@
-## 表单提交
-
-
-### 默认表单提交
-
-:::demo 
-```html
-
-
- -
- - -``` -::: - - -### 修改name - -:::demo -```html -
-
- -
- - -``` +## 表单提交 + + +### 默认表单提交 + +:::demo +```html +
+
+ +
+ + +``` +::: + + +### 修改name + +:::demo +```html +
+
+ +
+ + +``` ::: \ No newline at end of file diff --git a/docs/mds/ZM03.md b/docs/mds/ZM03.md index 3109a91..b6383ec 100644 --- a/docs/mds/ZM03.md +++ b/docs/mds/ZM03.md @@ -9,65 +9,65 @@
-``` -::: +## 远程搜索 + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/ZM05.md b/docs/mds/ZM05.md index 41d1a35..63e4d06 100644 --- a/docs/mds/ZM05.md +++ b/docs/mds/ZM05.md @@ -1,56 +1,56 @@ -## 动态数据 - - -### 本地数据动态赋值 - -:::demo -```html -
- - -``` -::: - - -### 远程数据动态赋值 - -:::demo -```html -
- - -``` -::: +## 动态数据 + + +### 本地数据动态赋值 + +:::demo +```html +
+ + +``` +::: + + +### 远程数据动态赋值 + +:::demo +```html +
+ + +``` +::: diff --git a/docs/mds/ZM06.md b/docs/mds/ZM06.md index c82ea3b..429e151 100644 --- a/docs/mds/ZM06.md +++ b/docs/mds/ZM06.md @@ -1,33 +1,33 @@ -## 远程搜索 - - -### layer弹出框 - -:::demo -```html - - - -``` -::: +## 远程搜索 + + +### layer弹出框 + +:::demo +```html + + + +``` +::: diff --git a/docs/mds/ZM07.md b/docs/mds/ZM07.md index 5c776e7..c88814e 100644 --- a/docs/mds/ZM07.md +++ b/docs/mds/ZM07.md @@ -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 -
-
-
- -
-
-
-
-
- - -``` -::: +## 获取实例对象 + + +### 全局方法 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 +
+
+
+ +
+
+
+
+
+ + +``` +::: diff --git a/docs/mds/ZM08.md b/docs/mds/ZM08.md index e2e2356..c540e7e 100644 --- a/docs/mds/ZM08.md +++ b/docs/mds/ZM08.md @@ -1,61 +1,61 @@ -## 批量操作 - - -### 批量操作已渲染实例 - -``` -//filter, 同get方法 -//method, 需要执行的方法 -//args, 执行方法的参数 -xmSelect.batch(filter, method, ...args); -``` - -:::demo -```html -
-
-
- -
-
-
-
- -

-
-
-```
-:::
+## 批量操作
+
+
+### 批量操作已渲染实例
+
+```
+//filter, 同get方法
+//method, 需要执行的方法
+//args, 执行方法的参数
+xmSelect.batch(filter, method, ...args);
+```
+
+:::demo 
+```html
+
+
+
+ +
+
+
+
+ +

+
+
+```
+:::
diff --git a/docs/mds/ZP01.md b/docs/mds/ZP01.md
index e79986d..7abfd2b 100644
--- a/docs/mds/ZP01.md
+++ b/docs/mds/ZP01.md
@@ -1,53 +1,75 @@
-## 下拉自定义
-
-
-
-### 下拉表格
-
-至于能干什么, 就看你们的想象了~~
-
-:::demo 
-```html
-
-
- - -``` -::: +## 下拉自定义 + + + +### 下拉表格 + +至于能干什么, 就看你们的想象了~~ + +:::demo +```html + +
+ + +``` +::: diff --git a/docs/mds/ZP02.md b/docs/mds/ZP02.md index 405c3f5..ee4ca26 100644 --- a/docs/mds/ZP02.md +++ b/docs/mds/ZP02.md @@ -1,8 +1,23 @@ ## 下拉树 -### eleTree +### tree -结合 `layui` 插件中心的 `eleTree`, 传送门 +默认配置 + +``` +tree: { + //是否显示树状结构 + show: false, + //是否展示三角图标 + showFolderIcon: true, + //是否显示虚线 + showLine: false, + //间距 + indent: 20, + //默认展开节点的数组 + expandedKeys: [], +}, +``` :::demo @@ -10,60 +25,81 @@
+
+
+ + +
+ +
间距
+
+ + ``` ::: diff --git a/docs/mds/ZP03.md b/docs/mds/ZP03.md index c2e4abb..af56068 100644 --- a/docs/mds/ZP03.md +++ b/docs/mds/ZP03.md @@ -1,65 +1,85 @@ -## 下拉树 +## 下拉日期多选 + +### laydate -### layuiTree +``` +//css调整部分 +xm-select .scroll-body{ + text-align: center; +} -结合 `layui` 的 `tree`, 传送门 - -:::demo -```html - -
- - -``` -::: +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'); + }); +} + +//这里仅仅提供一个演示, 更多的想法由你自己来创造 + + +``` +::: diff --git a/docs/mds/ZTEST.md b/docs/mds/ZTEST.md index 7e1b0a5..30ba3b8 100644 --- a/docs/mds/ZTEST.md +++ b/docs/mds/ZTEST.md @@ -9,36 +9,36 @@ ``` ::: diff --git a/docs/mds/es6.md b/docs/mds/es6.md index 371c1a1..7ca79ad 100644 --- a/docs/mds/es6.md +++ b/docs/mds/es6.md @@ -1,146 +1,146 @@ -## es6语法说明 - -:::warning -文档中会存在es6语法, 这里简单说明一下, 其中`IE`不支持`es6`语法 -::: - -### 概览 - -- let const -- 模板字符串 -- 对象中属性方法简写 -- 箭头函数 -- 解构 - -这里只是简单说明, 有兴趣可以看大神阮一峰的资料 - - -### 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 +- 模板字符串 +- 对象中属性方法简写 +- 箭头函数 +- 解构 + +这里只是简单说明, 有兴趣可以看大神阮一峰的资料 + + +### 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; +} +``` + +至于更多的就自己去找学习资料吧 diff --git a/docs/mds/install.md b/docs/mds/install.md index ab7216e..ee784ee 100644 --- a/docs/mds/install.md +++ b/docs/mds/install.md @@ -13,12 +13,12 @@ - [Fly社区交流贴](https://fly.layui.com/jie/57776/) - QQ交流群: `660408068` -> 作者: maplemei, 热爱前端的Java程序猿, 如果喜欢作者的插件, 可以请作者吃雪糕 ^_^ - -

- - 打赏 - +> 作者: maplemei, 热爱前端的Java程序猿, 如果喜欢作者的插件, 可以请作者吃雪糕 ^_^ + +

+ + 打赏 +

@@ -52,19 +52,19 @@ $ npm install && npm run dev diff --git a/docs/mds/options.md b/docs/mds/options.md index a638e35..733d943 100644 --- a/docs/mds/options.md +++ b/docs/mds/options.md @@ -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会转化为 - 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会转化为 + 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: 是否持续显示) | diff --git a/docs/mds/question.md b/docs/mds/question.md index e1d1a79..b214b8f 100644 --- a/docs/mds/question.md +++ b/docs/mds/question.md @@ -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, +}) + + +``` diff --git a/docs/plugins/eleTree/eleTree.css b/docs/plugins/eleTree/eleTree.css index ee5598c..ebb6add 100755 --- a/docs/plugins/eleTree/eleTree.css +++ b/docs/plugins/eleTree/eleTree.css @@ -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 */ \ No newline at end of file diff --git a/docs/plugins/eleTree/eleTree.js b/docs/plugins/eleTree/eleTree.js index dba9a9c..f9ffb04 100755 --- a/docs/plugins/eleTree/eleTree.js +++ b/docs/plugins/eleTree/eleTree.js @@ -1,1554 +1,1554 @@ -/** - * @Name: 基于layui的tree重写 - * @Author: 李祥 - * @License:MIT - * 最近修改时间: 2019/09/24 - */ - -layui.define(["jquery","laytpl"], function (exports) { - var $ = layui.jquery; - var laytpl = layui.laytpl; - var hint = layui.hint(); - - var MOD_NAME="eleTree"; - - //外部接口 - var eleTree={ - //事件监听 - on: function(events, callback){ - return layui.onevent.call(this, MOD_NAME, events, callback); - }, - render: function(options) { - var inst = new Class(options); - return thisTree.call(inst); - } - } - - var thisTree=function() { - var _self=this; - var options = _self.config; - - // 暴漏外面的方法 - return { - // 接收两个参数,1. 节点 key 2. 节点数据的数组 - updateKeyChildren: function(key,data) { - if(options.data.length===0) return; - return _self.updateKeyChildren.call(_self,key,data); - }, - updateKeySelf: function(key,data) { - if(options.data.length===0) return; - return _self.updateKeySelf.call(_self,key,data); - }, - remove: function(key) { - if(options.data.length===0) return; - return _self.remove.call(_self,key); - }, - append: function(key,data) { - if(options.data.length===0) return; - return _self.append.call(_self,key,data); - }, - insertBefore: function(key,data) { - if(options.data.length===0) return; - return _self.insertBefore.call(_self,key,data); - }, - insertAfter: function(key,data) { - if(options.data.length===0) return; - return _self.insertAfter.call(_self,key,data); - }, - // 接收两个 boolean 类型的参数,1. 是否只是叶子节点,默认值为 false 2. 是否包含半选节点,默认值为 false - getChecked: function(leafOnly, includeHalfChecked) { - if(options.data.length===0) return; - return _self.getChecked.call(_self,leafOnly, includeHalfChecked); - }, - // 接收勾选节点数据的数组 - setChecked: function(data,isReset) { - if(options.data.length===0) return; - return _self.setChecked.call(_self,data,isReset); - }, - // 取消选中 - unCheckNodes: function() { - if(options.data.length===0) return; - return _self.unCheckNodes.call(_self); - }, - unCheckArrNodes: function(data) { - if(options.data.length===0) return; - return _self.unCheckArrNodes.call(_self,data); - }, - expandAll: function() { - if(options.data.length===0) return; - return _self.expandAll.call(_self); - }, - expandNode: function(key) { - if(options.data.length===0) return; - return _self.expandNode.call(_self,key); - }, - unExpandNode: function(key) { - if(options.data.length===0) return; - return _self.unExpandNode.call(_self,key); - }, - toggleExpandNode: function(key) { - if(options.data.length===0) return; - return _self.toggleExpandNode.call(_self,key); - }, - unExpandAll: function() { - if(options.data.length===0) return; - return _self.unExpandAll.call(_self); - }, - reload: function(options) { - return _self.reload.call(_self,options); - }, - search: function(value) { - return _self.search.call(_self,value); - }, - getAllNodeData: function() { - return _self.getAllNodeData.call(_self); - } - } - } - - // 模板渲染 - var TPL_ELEM=function(options,floor,parentStatus) { - return [ - '{{# for(var i=0;i', - function() { - // 是否显示连线 - if(!options.showLine) return ''; - if(floor!==0){ - var s=''+ - ''; - return s; - }else{ - var s=''+ - ''; - return s; - } - }(), - '
', - '', - '', - '{{# }else{ }}', - 'leaf-icon" style="color: transparent;" >', - '{{# } }}' - ].join(""); - return str; - } - return ['{{# if(!d[i]["'+options.request.children+'"] || d[i]["'+options.request.children+'"].length===0){ }}', - 'leaf-icon" style="color: transparent;"', - '{{# } }}', - '">' - ].join(""); - }(), - '', - function() { - if(options.showCheckbox){ - var status=""; - if(options.checkStrictly){ - status='"0"'; - }else if(parentStatus==="1"){ - status='"1" checked'; - }else if(parentStatus==="2"){ - status='"2"'; - }else{ - status='"0"'; - } - return [ - '{{# if(d[i]["'+options.request.checked+'"]) { }}', - '' - ].join(""); - } - return '' - }(), - '', - '
', - '', - '', - '{{# } }}' - ].join(""); - } - - var TPL_NoText=function() { - return '

{{d.emptText}}

'; - } - - var Class=function(options) { - options.response=$.extend({}, this.config.response, options.response); - options.request=$.extend({}, this.config.request, options.request); - this.config = $.extend({}, this.config, options); - this.config.customKey=this.customKeyInit(); - this.prevClickEle=null; - this.nameIndex=1; - this.isRenderAllDom=false; - this.render(); - }; - - Class.prototype={ - constructor: Class, - config: { - elem: "", - data: [], - emptText: "暂无数据", // 内容为空的时候展示的文本 - renderAfterExpand: true, // 是否在第一次展开某个树节点后才渲染其子节点 - highlightCurrent: false, // 是否高亮当前选中节点,默认值是 false。 - defaultExpandAll: false, // 是否默认展开所有节点 - expandOnClickNode: true, // 是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。 - checkOnClickNode: false, // 是否在点击节点的时候选中节点,默认值为 false,即只有在点击复选框时才会选中节点。 - defaultExpandedKeys: [], // 默认展开的节点的 key 的数组 - autoExpandParent: true, // 展开子节点的时候是否自动展开父节点 - showCheckbox: false, // 节点是否可被选择 - checkStrictly: false, // 在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false - defaultCheckedKeys: [], // 默认勾选的节点的 key 的数组 - accordion: false, // 是否每次只打开一个同级树节点展开(手风琴效果) - indent: 16, // 相邻级节点间的水平缩进,单位为像素 - lazy: false, // 是否懒加载子节点,需与 load 方法结合使用 - load: function() {}, // 加载子树数据的方法,仅当 lazy 属性为true 时生效 - draggable: false, // 是否开启拖拽节点功能 - contextmenuList: [], // 启用右键菜单,支持的操作有:"copy","add","edit","remove" - searchNodeMethod: null, // 对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏 - showLine: false, // 是否显示连线,默认false - - method: "get", - url: "", - contentType: "", - headers: {}, - done: null, - - response: { - statusName: "code", - statusCode: 0, - dataName: "data" - }, - request: { - name: "label", - key: "id", - children: "children", - disabled: "disabled", - checked: "checked", - isLeaf: "isLeaf" - }, - customKey: "id", // 自定义key转义,即appKey=>app-id - }, - render: function() { - if(this.config.indent>30){ - this.config.indent=30; - }else if(this.config.indent<10){ - this.config.indent=10; - } - var options=this.config; - options.where=options.where || {}; - if(!options.elem) return hint.error("缺少elem参数"); - options.elem=typeof options.elem === "string" ? $(options.elem) : options.elem; - this.filter=options.elem.attr("lay-filter"); - // load加载框 - options.elem.append('
') - - // 判断加载方式 - if(options.data.length===0){ - this.ajaxGetData(); - }else{ - this.renderData(); - } - }, - renderData: function() { - var options=this.config; - $(this.config.elem).off(); // 取消事件绑定,防止多次绑定事件 - // 渲染第一层 - laytpl(TPL_ELEM(options,0)).render(options.data, function(string){ - options.elem.html(string); - }); - // 懒加载 > 展开所有 > 初始展开项 > 初始渲染所有子节点 > 初始选中项 > 每次点击只渲染当前层(默认) - // 判断所有dom是否全部加载 - if(!options.lazy){ - if(!options.renderAfterExpand || options.defaultExpandAll || options.defaultExpandedKeys.length>0 || options.defaultCheckedKeys.length>0){ - this.initialExpandAll(options.data,[],1); - } - } - - this.eleTreeEvent(); - this.checkboxRender(); - this.checkboxEvent(); - this.defaultChecked(); - this.nodeEvent(); - this.rightClickMenu(); - if(!options.checkStrictly){ - this.checkboxInit(); - } - }, - ajaxGetData: function() { - var options=this.config; - var _self=this; - if(!options.url) { - laytpl(TPL_NoText()).render(options, function(string){ - options.elem.html(string); - }); - return; - } - var data = $.extend({}, options.where); - if(options.contentType && options.contentType.indexOf("application/json") == 0){ //提交 json 格式 - data = JSON.stringify(data); - } - - $.ajax({ - type: options.method || 'get' - ,url: options.url - ,contentType: options.contentType - ,data: data - ,dataType: 'json' - ,headers: options.headers || {} - ,success: function(res){ - if(res[options.response.statusName] != options.response.statusCode || !res[options.response.dataName]){ - hint.error("请检查数据格式是否符合规范"); - typeof options.done === 'function' && options.done(res); - return; - } - options.data=res[options.response.dataName]; - _self.renderData(); - typeof options.done === 'function' && options.done(res); - } - }); - }, - reload: function(options) { - var _self=this; - if(this.config.data && this.config.data.constructor === Array) this.config.data=[]; - this.config = $.extend({}, this.config, options); - // $(this.config.elem).off(); // 取消事件绑定,防止多次绑定事件 - // reload记录选中的数据 - // this.getChecked().forEach(function(val) { - // if($.inArray(val.key,this.config.defaultCheckedKeys)===-1){ - // this.config.defaultCheckedKeys.push(val.key); - // } - // },this); - return eleTree.render(this.config) - }, - // 自定义data属性修改,即 appId=>app-id,解决key包含大写的问题 - customKeyInit: function() { - var options=this.config; - var key=""; - for(var i=0;i.eleTree-node-content-icon"; - options.elem.on("click",expandOnClickNode,function(e) { - e.stopPropagation(); - var eleTreeNodeContent=$(this).parent(".eleTree-node").length===0?$(this).parent(".eleTree-node-content"):$(this); - var eleNode=eleTreeNodeContent.parent(".eleTree-node"); - var sibNode=eleTreeNodeContent.siblings(".eleTree-node-group"); - var el=eleTreeNodeContent.children(".eleTree-node-content-icon").children(".layui-icon"); - - if(el.hasClass("icon-rotate")){ - // 合并 - sibNode.hide("fast"); - el.removeClass("icon-rotate"); - return; - } - - if(sibNode.children(".eleTree-node").length===0){ - var floor=Number(eleNode.attr("eletree-floor"))+1; - - // 选择祖父 - var selectParentsFn=function() { - if(!options.checkStrictly){ - var eleNode1=sibNode.children(".eleTree-node").eq(0); - if(eleNode1.length!==0){ - var siblingNode1=eleNode1.siblings(".eleTree-node"); - var item1=eleNode1.children(".eleTree-node-content").children(".eleTree-hideen").get(0); - _self.selectParents(item1,eleNode1,siblingNode1); - } - } - } - - var data=_self.reInitData(eleNode); - var d=data.currentData; - // 是否懒加载 - if(options.lazy && el.hasClass("lazy-icon")){ - el.removeClass("layui-icon-triangle-r").addClass("layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"); - options.load(d,function(getData) { - // 如果原来有数据则合并,没有则赋值 - if(d[options.request.children]){ - d[options.request.children]=d[options.request.children].concat(getData); - }else{ - d[options.request.children]=getData; - } - var eletreeStatus=eleTreeNodeContent.children("input.eleTree-hideen").attr("eletree-status"); - if(d[options.request.children] && d[options.request.children].length>0){ - // 只渲染获取到的数据 - laytpl(TPL_ELEM(options,floor,eletreeStatus)).render(getData, function(string){ - sibNode.append(string).show("fast"); - }); - }else{ - el.css("color","transparent").addClass("leaf-icon"); - } - el.removeClass("lazy-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop").addClass("layui-icon-triangle-r icon-rotate"); - - // 懒加载子元素选择祖父 - selectParentsFn(); - _self.checkboxRender(); - }) - }else{ - var eletreeStatus=eleTreeNodeContent.children("input.eleTree-hideen").attr("eletree-status"); - if(d[options.request.children] && d[options.request.children].length>0){ - laytpl(TPL_ELEM(options,floor,eletreeStatus)).render(d[options.request.children], function(string){ - sibNode.append(string).show("fast"); - el.addClass("icon-rotate"); - }); - // 选择祖父 - selectParentsFn(); - _self.checkboxRender(); - } - } - }else{ - // 有子节点则展开子节点 - sibNode.show("fast"); - el.addClass("icon-rotate"); - } - - // 手风琴效果 - if(options.accordion){ - var node=eleTreeNodeContent.parent(".eleTree-node").siblings(".eleTree-node"); - node.children(".eleTree-node-group").hide("fast"); - node.children(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").removeClass("icon-rotate"); - } - }) - }, - // checkbox选中 - checkboxEvent: function() { - var options=this.config; - var _self=this; - var checkOnClickNode=options.checkOnClickNode?".eleTree-node-content":".eleTree-checkbox"; - // input添加属性eleTree-status:即input的三种状态,"0":未选中,"1":选中,"2":子孙部分选中 - options.elem.on("click",checkOnClickNode,function(e) { - e.stopPropagation(); - var eleTreeNodeContent=$(this).parent(".eleTree-node").length===0?$(this).parent(".eleTree-node-content"):$(this); - var checkbox=eleTreeNodeContent.children(".eleTree-checkbox"); - if(checkbox.hasClass("eleTree-checkbox-disabled")) return; - // 获取点击所在数据 - var node=eleTreeNodeContent.parent(".eleTree-node"); - // var d=_self.reInitData(node).currentData; - // 实际的input - var inp=checkbox.siblings(".eleTree-hideen").get(0); - var childNode=eleTreeNodeContent.siblings(".eleTree-node-group").find("input[name='eleTree-node']"); - - // 添加active背景 - if(_self.prevClickEle) _self.prevClickEle.removeClass("eleTree-node-content-active"); - if(options.highlightCurrent) eleTreeNodeContent.addClass("eleTree-node-content-active"); - _self.prevClickEle=eleTreeNodeContent; - - if(!inp) return; - - if(inp.checked){ - // 反选自身 - $(inp).prop("checked",false).attr("eleTree-status","0").removeAttr("data-checked"); - // 点击祖父层选中子孙层 - if(!options.checkStrictly){ - childNode.prop("checked",false).attr("eleTree-status","0").removeAttr("data-checked"); - } - - }else{ - // 反选自身 - $(inp).prop("checked",true).attr("eleTree-status","1"); - // 点击祖父层选中子孙层 - if(!options.checkStrictly){ - childNode.prop("checked",true).attr("eleTree-status","1"); - } - } - - var eleNode=eleTreeNodeContent.parent(".eleTree-node"); - // 点击子孙层选中祖父层(递归) - if(!options.checkStrictly){ - var siblingNode=eleNode.siblings(".eleTree-node"); - // 点击子孙层选中祖父层(递归) - _self.selectParents(inp,eleNode,siblingNode); - } - - _self.checkboxRender(); - - layui.event.call(inp, MOD_NAME, 'nodeChecked('+ _self.filter +')', { - node: eleNode, - data: _self.reInitData(eleNode), - isChecked: inp.checked - }); - }) - }, - // 对后台数据有 checked:true 的默认选中项渲染父子层 - checkboxInit: function() { - var options=this.config; - var _self=this; - options.elem.find("input[data-checked]").each(function(index,item) { - var checkboxEl=$(item).siblings(".eleTree-checkbox"); - var childNode=checkboxEl.parent(".eleTree-node-content").siblings(".eleTree-node-group").find("input[name='eleTree-node']"); - // 选择当前 - $(item).prop("checked","checked").attr("eleTree-status","1"); - checkboxEl.addClass("eleTree-checkbox-checked"); - checkboxEl.children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line"); - if(options.checkStrictly) return; - // 选择子孙 - childNode.prop("checked","checked").attr("eleTree-status","1"); - childNode.siblings(".eleTree-checkbox").addClass("eleTree-checkbox-checked"); - childNode.siblings(".eleTree-checkbox").children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line"); - - // 选择祖父 - var eleNode=checkboxEl.parent(".eleTree-node-content").parent(".eleTree-node"); - var siblingNode=eleNode.siblings(".eleTree-node"); - _self.selectParents(item,eleNode,siblingNode); - }) - _self.checkboxRender(); - }, - // 通过子元素选中祖父元素 - selectParents: function(inp,eleNode,siblingNode) { - // inp: 实际input(dom元素) - // eleNode: input父层类(.eleTree-node) - // siblingNode: 父层同级兄弟 - while (Number(eleNode.attr("eletree-floor"))!==0) { - // 同级input状态存入数组 - var arr=[]; - arr.push($(inp).attr("eleTree-status")); - siblingNode.each(function(index,item) { - var siblingIsChecked=$(item).children(".eleTree-node-content").children("input[name='eleTree-node']").attr("eleTree-status"); - arr.push(siblingIsChecked); - }) - // 父元素的实际input - var parentInput=eleNode.parent(".eleTree-node-group").siblings(".eleTree-node-content").children("input[name='eleTree-node']"); - // 父元素的checkbox替代 - var parentCheckbox=parentInput.siblings(".eleTree-checkbox"); - // 子都选中则选中父 - if(arr.every(function(val) { - return val==="1"; - })){ - parentInput.prop("checked",true).attr("eleTree-status","1"); - } - // 子有一个未选中则checkbox第三种状态 - if(arr.some(function(val) { - return val==="0" || val==="2"; - })){ - parentInput.attr("eleTree-status","2"); - } - // 子全部未选中则取消父选中(并且取消第三种状态) - if(arr.every(function(val) { - return val==="0"; - })){ - parentInput.prop("checked",false); - parentInput.attr("eleTree-status","0"); - } - - var parentNode=eleNode.parents("[eletree-floor='"+(Number(eleNode.attr("eletree-floor"))-1)+"']"); - var parentCheckbox=parentNode.children(".eleTree-node-content").children("input[name='eleTree-node']").get(0); - var parentSiblingNode=parentNode.siblings(".eleTree-node"); - eleNode=parentNode; - inp=parentCheckbox; - siblingNode=parentSiblingNode; - } - }, - // 初始展开所有 - initialExpandAll: function(data,arr,floor,isMethodsExpandAll) { - var options=this.config; - var _self=this; - this.isRenderAllDom=true; - data.forEach(function(val,index) { - arr.push(index); - if(val[options.request.children] && val[options.request.children].length>0){ - var el=options.elem.children(".eleTree-node").eq(arr[0]).children(".eleTree-node-group"); - for(var i=1;i0) { - // 继续展开祖父层 - var f=function(eleP) { - if(options.autoExpandParent){ - eleP.parents(".eleTree-node").each(function(i,item) { - if($(item).data(options.request.key)){ - $(item).children(".eleTree-node-group").show().siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").addClass("icon-rotate"); - } - }) - } - } - // 展开指定id项 - var id=el.parent(".eleTree-node").data(options.request.key); - if($.inArray(id,options.defaultExpandedKeys)!==-1){ - // 直接展开子节点 - el.show().siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").addClass("icon-rotate"); - // 展开子项是否继续展开祖父项 - f(el.parent(".eleTree-node[data-"+options.customKey+"]")); - }else{ - // 如当前节点的子节点有展开项,则展开当前子节点的祖父层 - el.children(".eleTree-node").each(function(index, item) { - var id=$(item).data(options.request.key); - if($.inArray(id,options.defaultExpandedKeys)!==-1){ - f($(item)); - return false; - } - }) - } - } - }); - floor++; - _self.initialExpandAll(val[options.request.children],arr,floor,isMethodsExpandAll); - floor--; - } - // 重置数组索引 - arr.pop(); - }) - }, - // 选中单个节点 - checkedOneNode: function(nodeContent){ - var options=this.config; - var inp=nodeContent.children("input.eleTree-hideen").get(0); - $(inp).prop("checked",true).attr("eleTree-status","1"); - - if(options.checkStrictly) return; - - // 点击祖父层选中子孙层 - var childNode=nodeContent.siblings(".eleTree-node-group").find("input[name='eleTree-node']"); - childNode.prop("checked",true).attr("eleTree-status","1"); - - var eleNode=nodeContent.parent(".eleTree-node"); - var siblingNode=eleNode.siblings(".eleTree-node"); - // 点击子孙层选中祖父层(递归) - this.selectParents(inp,eleNode,siblingNode); - }, - // 初始默认选中 - defaultChecked: function(dataChecked) { - var options=this.config; - var _self=this; - var arr=dataChecked || options.defaultCheckedKeys; - if(arr.length===0){ - return false; - } - arr.forEach(function(val,index) { - var nodeContent=options.elem.find("[data-"+options.customKey+"='"+val+"']").children(".eleTree-node-content"); - nodeContent.length>0 && _self.checkedOneNode(nodeContent); - }) - this.checkboxInit(); - }, - // 自定义checkbox解析 - checkboxRender: function() { - var options=this.config; - options.elem.find(".eleTree-checkbox").remove(); - options.elem.find("input.eleTree-hideen[type=checkbox]").each(function(index,item){ - if($(item).hasClass("eleTree-disabled")){ - $(item).after('
'); - }else{ - $(item).after('
'); - } - - var checkbox=$(item).siblings(".eleTree-checkbox"); - if($(item).attr("eletree-status")==="1"){ - checkbox.addClass("eleTree-checkbox-checked"); - checkbox.children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line"); - }else if($(item).attr("eletree-status")==="0"){ - checkbox.removeClass("eleTree-checkbox-checked"); - checkbox.children("i").removeClass("layui-icon-ok eleTree-checkbox-line"); - }else if($(item).attr("eletree-status")==="2"){ - checkbox.addClass("eleTree-checkbox-checked"); - checkbox.children("i").removeClass("layui-icon-ok").addClass("eleTree-checkbox-line"); - } - - }) - }, - // 通过dom节点找对应数据 - reInitData: function(node) { - var options=this.config; - var i=node.index(); - var floor=Number(node.attr("eletree-floor")); - var arr=[]; // 节点对应的index - while (floor>=0) { - arr.push(i); - floor=floor-1; - node=node.parents("[eletree-floor='"+floor+"']"); - i=node.index(); - } - arr=arr.reverse(); - var oData=this.config.data; - // 当前节点的父节点数据 - var parentData=oData[arr[0]]; - // 当前节点的data数据 - var d = oData[arr[0]]; - for(var j = 1; j0){ - fn(data[obj.i][options.request.children]); - } - }else{ - callback(data,obj); - } - } - } - fn(options.data); - }, - updateKeyChildren: function(key,data) { - var options=this.config; - var node=options.elem.find("[data-"+options.customKey+"='"+key+"']"); - var floor=Number(node.attr("eletree-floor"))+1; - var _self=this; - - this.keySearchToOpera(key,function(d,obj) { - // 数据更新 - d[obj.i][options.request.children]=data; - // dom更新 - node.length!==0 && laytpl(TPL_ELEM(options,floor)).render(data, function(string){ - $(node).children(".eleTree-node-group").empty().append(string); - options.defaultExpandAll && $(node).children(".eleTree-node-group").show(); - }); - _self.unCheckNodes(true); - _self.defaultChecked(); - }); - }, - updateKeySelf: function(key,data) { - var options=this.config; - var node=options.elem.find("[data-"+options.customKey+"='"+key+"']").children(".eleTree-node-content"); - var floor=Number(node.attr("eletree-floor"))+1; - data[options.request.name] && node.children(".eleTree-node-content-label").text(data[options.request.name]); - data[options.request.disabled] && node.children(".eleTree-hideen").addClass("eleTree-disabled") - .siblings(".eleTree-checkbox").addClass("eleTree-checkbox-disabled"); - // 数据更新 - var getData=this.keySearchToOpera(key,function(d,obj) { - data[options.request.key]=d[obj.i][options.request.key]; - data[options.request.children]=d[obj.i][options.request.children]; - d[obj.i]=$.extend({},d[obj.i],data); - console.log(options.data); - }); - }, - remove: function(key) { - var options=this.config; - var node=options.elem.find("[data-"+options.customKey+"='"+key+"']"); - var pElem=node.parent(".eleTree-node-group"); - // 数据删除 - this.keySearchToOpera(key,function(data,obj) { - data.splice(obj.i,1); - obj.i--; - obj.len--; - - node.length!==0 && options.elem.find("[data-"+options.customKey+"='"+key+"']").remove(); - if(pElem.children(".eleTree-node").length===0){ - pElem.siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").css("color", "transparent"); - } - }); - this.unCheckNodes(true); - this.defaultChecked(); - this.checkboxInit(); - }, - append: function(key,data) { - var options=this.config; - // 如果不传key,则直接添加到根节点 - if(typeof key==="object" && key!==null){ - data=key; - key=null; - } - if(key===null || key===""){ - options.data.push(data); - laytpl(TPL_ELEM(options,0,"0")).render([data], function(string){ - $(options.elem).append(string); - $(options.elem).children(".eleTree-node:last").show(); - }); - this.checkboxRender(); - return; - } - // 传key则添加到子节点 - var node=options.elem.find("[data-"+options.customKey+"='"+key+"']"); - var floor=Number(node.attr("eletree-floor"))+1; - // 数据更新 - this.keySearchToOpera(key,function(d,obj) { - if(d[obj.i][options.request.children]){ - d[obj.i][options.request.children].push(data); - }else{ - d[obj.i][options.request.children]=[data]; - } - var arr=d[obj.i][options.request.children]; - var icon=node.children(".eleTree-node-content").find(".eleTree-node-content-icon .layui-icon"); - // 添加之后长度为1,则原来没有三角,添加三角 - if(arr.length===1){ - icon.removeAttr("style"); - } - // 判断原来是否没有展开 - if(!icon.hasClass("icon-rotate")){ - var expandOnClickNode=options.expandOnClickNode?node.children(".eleTree-node-content"):node.children(".eleTree-node-content").children(".eleTree-node-content-icon"); - expandOnClickNode.trigger("click"); - } - // 判断节点是否已存在 - var isExist=false; - node.children(".eleTree-node-group").children(".eleTree-node").each(function(index,item){ - if(data[options.request.key]==$(item).data(options.request.key)){ - isExist=true; - } - }) - if(!isExist){ - var len=arr.length; - var eletreeStatus=node.children(".eleTree-node-content").children("input.eleTree-hideen").attr("eletree-status"); - eletreeStatus=eletreeStatus==="2" ? "0" : eletreeStatus; - node.length!==0 && laytpl(TPL_ELEM(options,floor,eletreeStatus)).render([arr[len-1]], function(string){ - node.children(".eleTree-node-group").append(string).show(); - }); - } - - }); - this.checkboxRender(); - }, - insertBefore: function(key,data) { - var options=this.config; - var node=options.elem.find("[data-"+options.customKey+"='"+key+"']"); - var floor=Number(node.attr("eletree-floor")); - // 数据更新 - this.keySearchToOpera(key,function(d,obj) { - d.splice(obj.i,0,data); - obj.i++; - obj.len++; - var eletreeStatus=node.parent(".eleTree-node-group").length===0 ? "0" : node.parent(".eleTree-node-group").parent(".eleTree-node") - .children(".eleTree-node-content").children("input.eleTree-hideen").attr("eletree-status"); - eletreeStatus=eletreeStatus==="2" ? "0" : eletreeStatus; - node.length!==0 && laytpl(TPL_ELEM(options,floor,eletreeStatus)).render([data], function(string){ - node.before(string).prev(".eleTree-node"); - }); - }); - this.checkboxRender(); - }, - insertAfter: function(key,data) { - var options=this.config; - var node=options.elem.find("[data-"+options.customKey+"='"+key+"']"); - var floor=Number(node.attr("eletree-floor")); - // 数据更新 - this.keySearchToOpera(key,function(d,obj) { - d.splice(obj.i+1,0,data); - obj.i++; - obj.len++; - var eletreeStatus=node.parent(".eleTree-node-group").length===0 ? "0" : node.parent(".eleTree-node-group").parent(".eleTree-node") - .children(".eleTree-node-content").children("input.eleTree-hideen").attr("eletree-status"); - eletreeStatus=eletreeStatus==="2" ? "0" : eletreeStatus; - node.length!==0 && laytpl(TPL_ELEM(options,floor,eletreeStatus)).render([data], function(string){ - $(node).after(string).next(".eleTree-node"); - }); - }); - this.checkboxRender(); - // if(!options.lazy){ - // if(!options.renderAfterExpand || options.defaultExpandAll || options.defaultExpandedKeys.length>0){ - // this.initialExpandAll(options.data,[],1); - // } - // } - }, - getChecked: function(leafOnly, includeHalfChecked) { - var options=this.config - ,el - ,arr=[]; - leafOnly=leafOnly || false; - includeHalfChecked=includeHalfChecked || false; - if(leafOnly){ - el=options.elem.find(".layui-icon.leaf-icon").parent(".eleTree-node-content-icon") - .siblings("input.eleTree-hideen[eletree-status='1']"); - }else if(includeHalfChecked){ - el=options.elem.find("input.eleTree-hideen[eletree-status='1'],input.eleTree-hideen[eletree-status='2']"); - }else{ - el=options.elem.find("input.eleTree-hideen[eletree-status='1']"); - } - el.each(function(index,item) { - var obj={}; - var id=$(item).parent(".eleTree-node-content").parent(".eleTree-node").data(options.request.key); - var label=$(item).siblings(".eleTree-node-content-label").text(); - obj[options.request.key]=id; - obj[options.request.name]=label; - obj.elem=item; - obj.othis=$(item).siblings(".eleTree-checkbox").get(0) - arr.push(obj); - }) - return arr; - }, - setChecked: function(arr,isReset) { - var options=this.config; - isReset=isReset || false; - if(isReset){ - this.unCheckNodes(); - options.defaultCheckedKeys=$.extend([],arr); - }else{ - this.unCheckNodes(true); - arr.forEach(function(val) { - if($.inArray(val,options.defaultCheckedKeys)===-1){ - options.defaultCheckedKeys.push(val); - } - }) - } - this.defaultChecked(); - }, - unCheckNodes: function(_internal) { - _internal=_internal || false; // _internal: 是否内部调用 - var options=this.config; - options.elem.find("input.eleTree-hideen[eletree-status='1'],input.eleTree-hideen[eletree-status='2']").each(function(index,item) { - $(item).attr("eletree-status","0").prop("checked",false); - // 如果外部的取消选中,则所有的记录全部取消 - if(!_internal){ - $(item).removeAttr("data-checked"); - } - }); - this.checkboxRender(); - }, - unCheckArrNodes: function(arr) { - var options=this.config; - var dataChecked=[]; - options.elem.find(".eleTree-hideen[eletree-status='1']").each(function(index,item) { - var id=$(item).parent(".eleTree-node-content").parent(".eleTree-node").data(options.request.key); - // 获取所有被选中项,并去除arr中包含的数据 - if(arr.some(function(val) { - return val==id; - })){ - // 如果id在arr数组中,则清除dom上面的checked数据 - $(item).removeAttr("data-checked"); - return; - } - dataChecked.push(id); - }) - - // 更新defaultCheckedKeys数据 - for(var j=0;j.layui-icon").addClass("icon-rotate") - .parent(".eleTree-node-content-icon").parent(".eleTree-node-content") - .siblings(".eleTree-node-group").show(); - } - options.elem.children(".eleTree-node").children(".eleTree-node-group").empty(); - this.initialExpandAll(options.data,[],1,true); - this.unCheckNodes(true); - this.defaultChecked(); - this.checkboxInit(); - }, - // 展开某节点的所有子节点 - expandNode: function(key) { - var options=this.config; - var parentsEl=options.elem.find("[data-"+options.customKey+"='"+key+"']"); - var isExpand=parentsEl.children(".eleTree-node-content").find(".eleTree-node-content-icon>.layui-icon.layui-icon-triangle-r").hasClass("icon-rotate"); - var parentGroup=parentsEl.find(".eleTree-node-group"); - // 判断是否已经展开 - if(isExpand) return false; - // 判断子节点是否已经渲染(目前只判断所有子节点是否已经全部渲染,而不是当前子节点是否全部渲染) - if(this.isRenderAllDom){ - parentGroup.show("fast"); - parentsEl.find(".layui-icon.layui-icon-triangle-r").addClass("icon-rotate"); - return false; - } - if(options.lazy) return hint.error("展开所有子节点方法暂不支持懒加载"); - - var data=this.reInitData(parentsEl); - var d=data.currentData; - var floor=Number(parentsEl.attr("eletree-floor"))+1; - var fn=function(data,arr,floor) { - data.forEach(function(val,index) { - arr.push(index); - if(val[options.request.children] && val[options.request.children].length>0){ - var el=parentsEl.children(".eleTree-node-group"); - for(var i=1;i.layui-icon.layui-icon-triangle-r").hasClass("icon-rotate"); - // 判断是否已经合并 - if(!isExpand) return false; - parentsEl.find(".eleTree-node-group").hide("fast"); - parentsEl.find(".layui-icon.layui-icon-triangle-r").removeClass("icon-rotate"); - }, - // 切换某节点的所有子节点的展开合并状态 - toggleExpandNode: function(key) { - var options=this.config; - var parentsEl=options.elem.find("[data-"+options.customKey+"='"+key+"']"); - var isExpand=parentsEl.children(".eleTree-node-content").find(".eleTree-node-content-icon>.layui-icon.layui-icon-triangle-r").hasClass("icon-rotate"); - if(isExpand){ - this.unExpandNode(key); - }else{ - this.expandNode(key); - } - }, - // 节点事件 - nodeEvent: function() { - var _self=this; - var options=this.config; - // 节点被点击的回调事件 - options.elem.on("click",".eleTree-node-content",function(e) { - var eleNode=$(this).parent(".eleTree-node"); - var eleTreeNodeContent=eleNode.children(".eleTree-node-content"); - // 添加active背景 - if(_self.prevClickEle) _self.prevClickEle.removeClass("eleTree-node-content-active"); - if(options.highlightCurrent) eleTreeNodeContent.addClass("eleTree-node-content-active"); - _self.prevClickEle=eleTreeNodeContent; - - $("#tree-menu").hide().remove(); - layui.event.call(eleNode, MOD_NAME, 'nodeClick('+ _self.filter +')', { - node: eleNode, - data: _self.reInitData(eleNode), - event: e - }); - }) - // 节点右键的回调事件 - options.elem.on("contextmenu",".eleTree-node-content",function(e) { - var eleNode=$(this).parent(".eleTree-node"); - layui.event.call(eleNode, MOD_NAME, 'nodeContextmenu('+ _self.filter +')', { - node: eleNode, - data: _self.reInitData(eleNode), - event: e - }); - }) - // 节点被拖拽的回调事件 - options.draggable && options.elem.on("mousedown",".eleTree-node-content",function(e) { - var time=0; - var eleNode=$(this).parent(".eleTree-node"); - var eleFloor=Number(eleNode.attr("eletree-floor")); - var groupNode=eleNode.parent(".eleTree-node-group"); - - e.stopPropagation(); - options.elem.css("user-select","none"); - var cloneNode=eleNode.clone(true); - var temNode=eleNode.clone(true); - - var x=e.clientX-options.elem.offset().left; - var y=e.clientY-options.elem.offset().top; - options.elem.append(cloneNode); - cloneNode.css({ - "display": "none", - "opacity": 0.7, - "position": "absolute", - "background-color": "#f5f5f5", - "width": "100%" - }) - - var currentData=_self.reInitData(eleNode); - - var isStop=false; - - $(document).on("mousemove",function(e) { - // t为了区别click事件 - time++; - if(time>2){ - var xx=e.clientX-options.elem.offset().left+10; - var yy=e.clientY-options.elem.offset().top+$(document).scrollTop()-5; // 加上浏览器滚动高度 - - cloneNode.css({ - display: "block", - left: xx+"px", - top: yy+"px" - }) - } - }).on("mouseup",function(e) { - $(document).off("mousemove").off("mouseup"); - var target=$(e.target).parents(".eleTree-node").eq(0); - cloneNode.remove(); - options.elem.css("user-select","auto"); - - - // 当前点击的是否时最外层 - var isCurrentOuterMost=eleNode.parent().get(0).isEqualNode(options.elem.get(0)) - // 目标是否时最外层 - var isTargetOuterMost=$(e.target).get(0).isEqualNode(options.elem.get(0)) - if(isTargetOuterMost){ - target=options.elem; - } - // 判断是否超出边界 - if(target.parents(options.elem).length===0 && !isTargetOuterMost){ - return; - } - // 判断初始与结束是否是同一个节点 - if(target.get(0).isEqualNode(eleNode.get(0))){ - return; - } - // 判断是否是父节点放到子节点 - var tFloor=target.attr("eletree-floor"); - var isInChild=false; - eleNode.find("[eletree-floor='"+tFloor+"']").each(function() { - if(this.isEqualNode(target.get(0))){ - isInChild=true; - } - }) - if(isInChild){ - return; - } - - var targetData=_self.reInitData(target); - layui.event.call(target, MOD_NAME, 'nodeDrag('+ _self.filter +')', { - current: { - node: eleNode, - data: currentData - }, - target: { - node: target, - data: targetData - }, - stop: function() { - isStop=true; - } - }); - // 拖拽是否取消 - if(isStop){ - return false; - } - - // 数据更改 - var currList=currentData.parentData.data[options.request.children] - var currIndex=currentData.parentData.childIndex - var currData=currentData.currentData; - var tarData=targetData.currentData; - // 当前是否是最外层 - isCurrentOuterMost ? options.data.splice(currIndex,1) : currList.splice(currIndex,1) - // 目标是否是最外层 - isTargetOuterMost ? options.data.push(currData) : (function() { - !tarData[options.request.children] ? tarData[options.request.children]=[] : ""; - tarData[options.request.children].push(currData); - })() - - // dom互换 - eleNode.remove(); - var floor=null; - // 最外层判断 - if(isTargetOuterMost){ - target.append(temNode); - floor=0; - }else{ - target.children(".eleTree-node-group").append(temNode); - floor=Number(target.attr("eletree-floor"))+1; - } - // 加floor和padding - temNode.attr("eletree-floor",String(floor)); - temNode.children(".eleTree-node-content").css("padding-left",floor*options.indent+"px"); - // 计算线条的left - if(options.showLine){ - // 判断目标是否是最外层,是的话隐藏线条 - if(floor===0){ - temNode.children(".eleTree-node-verticalline,.eleTree-node-horizontalline").hide(); - }else{ - temNode.children(".eleTree-node-verticalline,.eleTree-node-horizontalline").css("left",options.indent*(floor-1)+9+"px").show(); - } - } - // 通过floor差值计算子元素的floor - var countFloor=eleFloor-floor; - temNode.find(".eleTree-node").each(function(index,item) { - var f=Number($(item).attr("eletree-floor"))-countFloor; - $(item).attr("eletree-floor",String(f)); - $(item).children(".eleTree-node-content").css("padding-left",f*options.indent+"px"); - options.showLine && $(item).children(".eleTree-node-verticalline,.eleTree-node-horizontalline").css("left",options.indent*(f-1)+9+"px").show(); - }) - // 原dom去三角 - var leaf=groupNode.children(".eleTree-node").length===0; - leaf && groupNode.siblings(".eleTree-node-content") - .children(".eleTree-node-content-icon").children(".layui-icon") - .removeClass("icon-rotate").css("color","transparent"); - // 当前的增加三角 - var cLeaf=target.children(".eleTree-node-group").children(".eleTree-node").length===1; - cLeaf && target.children(".eleTree-node-content") - .children(".eleTree-node-content-icon").children(".layui-icon") - .addClass("icon-rotate").removeAttr("style"); - // 判断当前是否需要显示 - var isShowNode=target.children(".eleTree-node-content").find(".layui-icon").hasClass("icon-rotate"); - (isTargetOuterMost || isShowNode) && target.children(".eleTree-node-group").show(); - - _self.unCheckNodes(true); - _self.defaultChecked(); - _self.checkboxInit(); - }) - }) - }, - rightClickMenu: function() { - var _self=this; - var options=this.config; - if(options.contextmenuList.length<=0){ - return; - } - $(document).on("click",function() { - $("#tree-menu").hide().remove(); - }); - - var customizeMenu=[]; // 用户自定义的 - var internalMenu=["copy","add","add.async","insertBefore","insertAfter","append","edit","edit.async","remove","remove.async"]; // 系统自带的 - var customizeStr=''; - options.contextmenuList.forEach(function(val) { - if($.inArray(val,internalMenu)===-1){ - customizeMenu.push(val); - customizeStr+='
  • '+(val.text || val)+'
  • '; - } - }) - var menuStr=['
      ' - ,$.inArray("copy",options.contextmenuList)!==-1?'
    • 复制
    • ':'' - ,($.inArray("add",options.contextmenuList)!==-1 || $.inArray("add.async",options.contextmenuList)!==-1)?'
    • 新增
    • '+ - '
    • 插入节点前
    • '+ - '
    • 插入节点后
    • '+ - '
    • 插入子节点
    • ' : "" - ,($.inArray("edit",options.contextmenuList)!==-1 || $.inArray("edit.async",options.contextmenuList)!==-1)?'
    • 修改
    • ':'' - ,($.inArray("remove",options.contextmenuList)!==-1 || $.inArray("remove.async",options.contextmenuList)!==-1)?'
    • 删除
    • ':'' - ,customizeStr - ,'
    '].join(""); - this.treeMenu=$(menuStr); - options.elem.off("contextmenu").on("contextmenu",".eleTree-node-content",function(e) { - var that=this; - e.stopPropagation(); - e.preventDefault(); - // 添加active背景 - if(_self.prevClickEle) _self.prevClickEle.removeClass("eleTree-node-content-active"); - $(this).addClass("eleTree-node-content-active"); - var eleNode=$(this).parent(".eleTree-node"); - var nodeData=_self.reInitData(eleNode); - - // 菜单位置 - $(document.body).after(_self.treeMenu); - $("#tree-menu").find("li.append,li.insertAfter,li.insertBefore").hide(); - $("#tree-menu").find(":not(li.append,li.insertAfter,li.insertBefore)").show(); - $("#tree-menu").css({ - left: e.clientX+$(document).scrollLeft(), - top: e.clientY+$(document).scrollTop() - }).show(); - // 复制 - $("#tree-menu li.copy").off().on("click",function() { - var el = $(that).children(".eleTree-node-content-label").get(0); - var selection = window.getSelection(); - var range = document.createRange(); - range.selectNodeContents(el); - selection.removeAllRanges(); - selection.addRange(range); - document.execCommand('Copy', 'false', null); - selection.removeAllRanges(); - }); - // 新增 - $("#tree-menu li.add").off().on("click",function(e) { - e.stopPropagation(); - $(this).hide().siblings("li:not(.append,.insertAfter,.insertBefore)").hide(); - $(this).siblings(".append,li.insertAfter,li.insertBefore").show(); - }) - // 添加的默认数据 - var obj={}; - obj[options.request.key]=Date.now(); - obj[options.request.name]="未命名"+_self.nameIndex; - if(options.lazy){ - obj[options.request.isLeaf]=true; - } - - var arr=["Append","InsertBefore","InsertAfter"]; - arr.forEach(function(val) { - var s=val[0].toLocaleLowerCase()+val.slice(1,val.length); - $("#tree-menu li."+s).off().on("click",function(e) { - var node=$(that).parent(".eleTree-node"); - var key=node.data(options.request.key); - var isStop=false; - var s=val[0].toLocaleLowerCase()+val.slice(1,val.length); - // 每次只能添加一条数据,不可以批量添加 - _self[s](key,obj); - var nodeArr=[]; - node.children(".eleTree-node-group").children(".eleTree-node").each(function(i,itemNode) { - nodeArr.push(itemNode); - }) - node.siblings(".eleTree-node").each(function(i,itemNode) { - nodeArr.push(itemNode); - }) - $.each(nodeArr, function(i,itemNode) { - if(obj[options.request.key]===$(itemNode).data(options.request.key)){ - var label=$(itemNode).children(".eleTree-node-content").children(".eleTree-node-content-label").hide(); - var text=label.text(); - var inp=""; - label.after(inp); - - label.siblings(".eleTree-node-content-input").focus().select().off().on("blur",function() { - var v=$(this).val(); - obj[options.request.name]=v; - var inpThis=this; - - layui.event.call(node, MOD_NAME, 'node'+val+'('+ _self.filter +')', { - node: node, - data: nodeData.currentData, - newData: obj, - // 重新设置数据 - setData: function(o) { - // obj[options.request.key]=Date.now(); - obj[options.request.name]=v; - if(options.lazy){ - obj[options.request.isLeaf]=true; - } - var newObj=$.extend({},obj,o); - this.newData=newObj; - // 修改数据 - var d=_self.reInitData($(itemNode)).currentData; - d[options.request.name]=newObj[options.request.name]; - d[options.request.key]=newObj[options.request.key]; - // 修改dom - $(inpThis).siblings(".eleTree-node-content-label").text(newObj[options.request.name]).show(); - $(itemNode).attr("data-"+options.customKey,newObj[options.request.key]); // 改变页面上面的显示的key,之后可以获取dom - $(itemNode).data(options.request.key,newObj[options.request.key]); // 改变data数据,之后可以通过data获取key - $(inpThis).remove(); - - _self.nameIndex++; - isStop=true; - }, - // 停止添加 - stop: function() { - isStop=true; - this.newData={}; - _self.remove(obj[options.request.key]); - } - }); - - // 不是异步添加 - if($.inArray("add.async",options.contextmenuList)===-1){ - if(isStop) return; - // 修改数据 - _self.reInitData($(itemNode)).currentData[options.request.name]=v; - // 修改dom - $(this).siblings(".eleTree-node-content-label").text(v).show(); - $(this).remove(); - - _self.nameIndex++; - } - }).on("mousedown",function(e) { - // 防止input拖拽 - e.stopPropagation(); - }).on("click",function(e) { - e.stopPropagation(); - }) - } - }) - }) - }) - - // 编辑 - $("#tree-menu li.edit").off().on("click",function(e) { - e.stopPropagation(); - $("#tree-menu").hide().remove(); - var node=$(that).parent(".eleTree-node"); - var key=node.data(options.request.key); - var label=$(that).children(".eleTree-node-content-label").hide(); - var text=label.text(); - var inp=""; - label.after(inp); - label.siblings(".eleTree-node-content-input").focus().select().off().on("blur",function() { - var val=$(this).val(); - var isStop=false; - var inpThis=this; - layui.event.call(node, MOD_NAME, 'nodeEdit('+ _self.filter +')', { - node: node, - value: val, - data: nodeData.currentData, - // 停止添加 - stop: function() { - isStop=true; - $(inpThis).siblings(".eleTree-node-content-label").show(); - $(inpThis).remove(); - }, - async: function() { - if(isStop) return; - // 修改数据 - _self.reInitData(eleNode).currentData[options.request.name]=val; - // 修改dom - $(inpThis).siblings(".eleTree-node-content-label").text(val).show(); - $(inpThis).remove(); - } - }); - // 不是异步 - if($.inArray("edit.async",options.contextmenuList)===-1){ - if(isStop) return; - // 修改数据 - _self.reInitData(eleNode).currentData[options.request.name]=val; - // 修改dom - $(this).siblings(".eleTree-node-content-label").text(val).show(); - $(this).remove(); - } - - }).on("mousedown",function(e) { - // 防止input拖拽 - e.stopPropagation(); - }) - }) - // 删除 - $("#tree-menu li.remove").off().on("click",function(e) { - var node=$(that).parent(".eleTree-node"); - var key=node.data(options.request.key); - var isStop=false; - layui.event.call(node, MOD_NAME, 'nodeRemove('+ _self.filter +')', { - node: node, - data: nodeData.currentData, - // 停止添加 - stop: function() { - isStop=true; - return this; - }, - async: function() { - if(isStop) return; - _self.remove(key); - return this; - } - }); - // 不是异步 - if($.inArray("remove.async",options.contextmenuList)===-1){ - if(isStop) return; - _self.remove(key); - } - - }) - - // 自定义菜单回调 - customizeMenu.forEach(function(val) { - var text=val.eventName || val; - $("#tree-menu li."+text).off().on("click",function() { - var node=$(that).parent(".eleTree-node"); - var isStop=false; - layui.event.call(node, MOD_NAME, 'node'+text.replace(text.charAt(0),text.charAt(0).toUpperCase())+'('+ _self.filter +')', { - node: node, - data: nodeData.currentData, - }); - }); - }) - - _self.prevClickEle=$(this); - }) - }, - search: function(value) { - var options=this.config; - if(!options.searchNodeMethod || typeof options.searchNodeMethod !== "function"){ - return; - } - var data=options.data; - // 数据递归 - var traverse=function(data) { - data.forEach(function(val,index) { - // 所有查找到的节点增加属性 - val.visible=options.searchNodeMethod(value,val); - if(val[options.request.children] && val[options.request.children].length>0){ - traverse(val[options.request.children]); - } - //如果当前节点属性为隐藏,判断其子节点是否有显示的,如果有,则当前节点改为显示 - if(!val.visible){ - var childSomeShow = false; - if(val[options.request.children] && val[options.request.children].length>0){ - childSomeShow=val[options.request.children].some(function(v,i) { - return v.visible; - }) - } - val.visible = childSomeShow; - } - // 通过节点的属性,显示隐藏各个节点,并添加删除搜索类 - var el=options.elem.find("[data-"+options.customKey+"='"+val[options.request.key]+"']"); - if(val.visible){ - el.removeClass("eleTree-search-hide"); - // 判断父节点是否展开,如果父节点没有展开,则子节点也不要显示 - var parentEl=el.parent(".eleTree-node-group").parent(".eleTree-node"); - var isParentOpen=parentEl.children(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon.layui-icon-triangle-r").hasClass("icon-rotate") - if((parentEl.length>0 && isParentOpen) || parentEl.length===0){ - el.show(); - } - }else{ - el.hide().addClass("eleTree-search-hide"); - } - // 删除子层属性 - // if(val[options.request.children] && val[options.request.children].length>0){ - // val[options.request.children].forEach(function(v,i) { - // delete v.visible; - // }) - // } - }) - } - traverse(data); - // 删除最外层属性 - var arr=data.map(function (val) { - var v=val.visible; - // delete val.visible; - return v; - }); - var isNotext=options.elem.children(".eleTree-noText"); - // 如果第一层的所有的都隐藏,则显示文本 - if(arr.every(function(v) { - return v===false; - })){ - if(isNotext.length===0){ - laytpl(TPL_NoText()).render(options, function(string){ - options.elem.append(string); - }); - } - }else{ - isNotext.remove(); - } - }, - getAllNodeData: function() { - var options=this.config; - return options.data; - } - } - - exports(MOD_NAME,eleTree); -}) +/** + * @Name: 基于layui的tree重写 + * @Author: 李祥 + * @License:MIT + * 最近修改时间: 2019/09/24 + */ + +layui.define(["jquery","laytpl"], function (exports) { + var $ = layui.jquery; + var laytpl = layui.laytpl; + var hint = layui.hint(); + + var MOD_NAME="eleTree"; + + //外部接口 + var eleTree={ + //事件监听 + on: function(events, callback){ + return layui.onevent.call(this, MOD_NAME, events, callback); + }, + render: function(options) { + var inst = new Class(options); + return thisTree.call(inst); + } + } + + var thisTree=function() { + var _self=this; + var options = _self.config; + + // 暴漏外面的方法 + return { + // 接收两个参数,1. 节点 key 2. 节点数据的数组 + updateKeyChildren: function(key,data) { + if(options.data.length===0) return; + return _self.updateKeyChildren.call(_self,key,data); + }, + updateKeySelf: function(key,data) { + if(options.data.length===0) return; + return _self.updateKeySelf.call(_self,key,data); + }, + remove: function(key) { + if(options.data.length===0) return; + return _self.remove.call(_self,key); + }, + append: function(key,data) { + if(options.data.length===0) return; + return _self.append.call(_self,key,data); + }, + insertBefore: function(key,data) { + if(options.data.length===0) return; + return _self.insertBefore.call(_self,key,data); + }, + insertAfter: function(key,data) { + if(options.data.length===0) return; + return _self.insertAfter.call(_self,key,data); + }, + // 接收两个 boolean 类型的参数,1. 是否只是叶子节点,默认值为 false 2. 是否包含半选节点,默认值为 false + getChecked: function(leafOnly, includeHalfChecked) { + if(options.data.length===0) return; + return _self.getChecked.call(_self,leafOnly, includeHalfChecked); + }, + // 接收勾选节点数据的数组 + setChecked: function(data,isReset) { + if(options.data.length===0) return; + return _self.setChecked.call(_self,data,isReset); + }, + // 取消选中 + unCheckNodes: function() { + if(options.data.length===0) return; + return _self.unCheckNodes.call(_self); + }, + unCheckArrNodes: function(data) { + if(options.data.length===0) return; + return _self.unCheckArrNodes.call(_self,data); + }, + expandAll: function() { + if(options.data.length===0) return; + return _self.expandAll.call(_self); + }, + expandNode: function(key) { + if(options.data.length===0) return; + return _self.expandNode.call(_self,key); + }, + unExpandNode: function(key) { + if(options.data.length===0) return; + return _self.unExpandNode.call(_self,key); + }, + toggleExpandNode: function(key) { + if(options.data.length===0) return; + return _self.toggleExpandNode.call(_self,key); + }, + unExpandAll: function() { + if(options.data.length===0) return; + return _self.unExpandAll.call(_self); + }, + reload: function(options) { + return _self.reload.call(_self,options); + }, + search: function(value) { + return _self.search.call(_self,value); + }, + getAllNodeData: function() { + return _self.getAllNodeData.call(_self); + } + } + } + + // 模板渲染 + var TPL_ELEM=function(options,floor,parentStatus) { + return [ + '{{# for(var i=0;i', + function() { + // 是否显示连线 + if(!options.showLine) return ''; + if(floor!==0){ + var s=''+ + ''; + return s; + }else{ + var s=''+ + ''; + return s; + } + }(), + '
    ', + '', + '', + '{{# }else{ }}', + 'leaf-icon" style="color: transparent;" >', + '{{# } }}' + ].join(""); + return str; + } + return ['{{# if(!d[i]["'+options.request.children+'"] || d[i]["'+options.request.children+'"].length===0){ }}', + 'leaf-icon" style="color: transparent;"', + '{{# } }}', + '">' + ].join(""); + }(), + '', + function() { + if(options.showCheckbox){ + var status=""; + if(options.checkStrictly){ + status='"0"'; + }else if(parentStatus==="1"){ + status='"1" checked'; + }else if(parentStatus==="2"){ + status='"2"'; + }else{ + status='"0"'; + } + return [ + '{{# if(d[i]["'+options.request.checked+'"]) { }}', + '' + ].join(""); + } + return '' + }(), + '', + '
    ', + '', + '', + '{{# } }}' + ].join(""); + } + + var TPL_NoText=function() { + return '

    {{d.emptText}}

    '; + } + + var Class=function(options) { + options.response=$.extend({}, this.config.response, options.response); + options.request=$.extend({}, this.config.request, options.request); + this.config = $.extend({}, this.config, options); + this.config.customKey=this.customKeyInit(); + this.prevClickEle=null; + this.nameIndex=1; + this.isRenderAllDom=false; + this.render(); + }; + + Class.prototype={ + constructor: Class, + config: { + elem: "", + data: [], + emptText: "暂无数据", // 内容为空的时候展示的文本 + renderAfterExpand: true, // 是否在第一次展开某个树节点后才渲染其子节点 + highlightCurrent: false, // 是否高亮当前选中节点,默认值是 false。 + defaultExpandAll: false, // 是否默认展开所有节点 + expandOnClickNode: true, // 是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。 + checkOnClickNode: false, // 是否在点击节点的时候选中节点,默认值为 false,即只有在点击复选框时才会选中节点。 + defaultExpandedKeys: [], // 默认展开的节点的 key 的数组 + autoExpandParent: true, // 展开子节点的时候是否自动展开父节点 + showCheckbox: false, // 节点是否可被选择 + checkStrictly: false, // 在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false + defaultCheckedKeys: [], // 默认勾选的节点的 key 的数组 + accordion: false, // 是否每次只打开一个同级树节点展开(手风琴效果) + indent: 16, // 相邻级节点间的水平缩进,单位为像素 + lazy: false, // 是否懒加载子节点,需与 load 方法结合使用 + load: function() {}, // 加载子树数据的方法,仅当 lazy 属性为true 时生效 + draggable: false, // 是否开启拖拽节点功能 + contextmenuList: [], // 启用右键菜单,支持的操作有:"copy","add","edit","remove" + searchNodeMethod: null, // 对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏 + showLine: false, // 是否显示连线,默认false + + method: "get", + url: "", + contentType: "", + headers: {}, + done: null, + + response: { + statusName: "code", + statusCode: 0, + dataName: "data" + }, + request: { + name: "label", + key: "id", + children: "children", + disabled: "disabled", + checked: "checked", + isLeaf: "isLeaf" + }, + customKey: "id", // 自定义key转义,即appKey=>app-id + }, + render: function() { + if(this.config.indent>30){ + this.config.indent=30; + }else if(this.config.indent<10){ + this.config.indent=10; + } + var options=this.config; + options.where=options.where || {}; + if(!options.elem) return hint.error("缺少elem参数"); + options.elem=typeof options.elem === "string" ? $(options.elem) : options.elem; + this.filter=options.elem.attr("lay-filter"); + // load加载框 + options.elem.append('
    ') + + // 判断加载方式 + if(options.data.length===0){ + this.ajaxGetData(); + }else{ + this.renderData(); + } + }, + renderData: function() { + var options=this.config; + $(this.config.elem).off(); // 取消事件绑定,防止多次绑定事件 + // 渲染第一层 + laytpl(TPL_ELEM(options,0)).render(options.data, function(string){ + options.elem.html(string); + }); + // 懒加载 > 展开所有 > 初始展开项 > 初始渲染所有子节点 > 初始选中项 > 每次点击只渲染当前层(默认) + // 判断所有dom是否全部加载 + if(!options.lazy){ + if(!options.renderAfterExpand || options.defaultExpandAll || options.defaultExpandedKeys.length>0 || options.defaultCheckedKeys.length>0){ + this.initialExpandAll(options.data,[],1); + } + } + + this.eleTreeEvent(); + this.checkboxRender(); + this.checkboxEvent(); + this.defaultChecked(); + this.nodeEvent(); + this.rightClickMenu(); + if(!options.checkStrictly){ + this.checkboxInit(); + } + }, + ajaxGetData: function() { + var options=this.config; + var _self=this; + if(!options.url) { + laytpl(TPL_NoText()).render(options, function(string){ + options.elem.html(string); + }); + return; + } + var data = $.extend({}, options.where); + if(options.contentType && options.contentType.indexOf("application/json") == 0){ //提交 json 格式 + data = JSON.stringify(data); + } + + $.ajax({ + type: options.method || 'get' + ,url: options.url + ,contentType: options.contentType + ,data: data + ,dataType: 'json' + ,headers: options.headers || {} + ,success: function(res){ + if(res[options.response.statusName] != options.response.statusCode || !res[options.response.dataName]){ + hint.error("请检查数据格式是否符合规范"); + typeof options.done === 'function' && options.done(res); + return; + } + options.data=res[options.response.dataName]; + _self.renderData(); + typeof options.done === 'function' && options.done(res); + } + }); + }, + reload: function(options) { + var _self=this; + if(this.config.data && this.config.data.constructor === Array) this.config.data=[]; + this.config = $.extend({}, this.config, options); + // $(this.config.elem).off(); // 取消事件绑定,防止多次绑定事件 + // reload记录选中的数据 + // this.getChecked().forEach(function(val) { + // if($.inArray(val.key,this.config.defaultCheckedKeys)===-1){ + // this.config.defaultCheckedKeys.push(val.key); + // } + // },this); + return eleTree.render(this.config) + }, + // 自定义data属性修改,即 appId=>app-id,解决key包含大写的问题 + customKeyInit: function() { + var options=this.config; + var key=""; + for(var i=0;i.eleTree-node-content-icon"; + options.elem.on("click",expandOnClickNode,function(e) { + e.stopPropagation(); + var eleTreeNodeContent=$(this).parent(".eleTree-node").length===0?$(this).parent(".eleTree-node-content"):$(this); + var eleNode=eleTreeNodeContent.parent(".eleTree-node"); + var sibNode=eleTreeNodeContent.siblings(".eleTree-node-group"); + var el=eleTreeNodeContent.children(".eleTree-node-content-icon").children(".layui-icon"); + + if(el.hasClass("icon-rotate")){ + // 合并 + sibNode.hide("fast"); + el.removeClass("icon-rotate"); + return; + } + + if(sibNode.children(".eleTree-node").length===0){ + var floor=Number(eleNode.attr("eletree-floor"))+1; + + // 选择祖父 + var selectParentsFn=function() { + if(!options.checkStrictly){ + var eleNode1=sibNode.children(".eleTree-node").eq(0); + if(eleNode1.length!==0){ + var siblingNode1=eleNode1.siblings(".eleTree-node"); + var item1=eleNode1.children(".eleTree-node-content").children(".eleTree-hideen").get(0); + _self.selectParents(item1,eleNode1,siblingNode1); + } + } + } + + var data=_self.reInitData(eleNode); + var d=data.currentData; + // 是否懒加载 + if(options.lazy && el.hasClass("lazy-icon")){ + el.removeClass("layui-icon-triangle-r").addClass("layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"); + options.load(d,function(getData) { + // 如果原来有数据则合并,没有则赋值 + if(d[options.request.children]){ + d[options.request.children]=d[options.request.children].concat(getData); + }else{ + d[options.request.children]=getData; + } + var eletreeStatus=eleTreeNodeContent.children("input.eleTree-hideen").attr("eletree-status"); + if(d[options.request.children] && d[options.request.children].length>0){ + // 只渲染获取到的数据 + laytpl(TPL_ELEM(options,floor,eletreeStatus)).render(getData, function(string){ + sibNode.append(string).show("fast"); + }); + }else{ + el.css("color","transparent").addClass("leaf-icon"); + } + el.removeClass("lazy-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop").addClass("layui-icon-triangle-r icon-rotate"); + + // 懒加载子元素选择祖父 + selectParentsFn(); + _self.checkboxRender(); + }) + }else{ + var eletreeStatus=eleTreeNodeContent.children("input.eleTree-hideen").attr("eletree-status"); + if(d[options.request.children] && d[options.request.children].length>0){ + laytpl(TPL_ELEM(options,floor,eletreeStatus)).render(d[options.request.children], function(string){ + sibNode.append(string).show("fast"); + el.addClass("icon-rotate"); + }); + // 选择祖父 + selectParentsFn(); + _self.checkboxRender(); + } + } + }else{ + // 有子节点则展开子节点 + sibNode.show("fast"); + el.addClass("icon-rotate"); + } + + // 手风琴效果 + if(options.accordion){ + var node=eleTreeNodeContent.parent(".eleTree-node").siblings(".eleTree-node"); + node.children(".eleTree-node-group").hide("fast"); + node.children(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").removeClass("icon-rotate"); + } + }) + }, + // checkbox选中 + checkboxEvent: function() { + var options=this.config; + var _self=this; + var checkOnClickNode=options.checkOnClickNode?".eleTree-node-content":".eleTree-checkbox"; + // input添加属性eleTree-status:即input的三种状态,"0":未选中,"1":选中,"2":子孙部分选中 + options.elem.on("click",checkOnClickNode,function(e) { + e.stopPropagation(); + var eleTreeNodeContent=$(this).parent(".eleTree-node").length===0?$(this).parent(".eleTree-node-content"):$(this); + var checkbox=eleTreeNodeContent.children(".eleTree-checkbox"); + if(checkbox.hasClass("eleTree-checkbox-disabled")) return; + // 获取点击所在数据 + var node=eleTreeNodeContent.parent(".eleTree-node"); + // var d=_self.reInitData(node).currentData; + // 实际的input + var inp=checkbox.siblings(".eleTree-hideen").get(0); + var childNode=eleTreeNodeContent.siblings(".eleTree-node-group").find("input[name='eleTree-node']"); + + // 添加active背景 + if(_self.prevClickEle) _self.prevClickEle.removeClass("eleTree-node-content-active"); + if(options.highlightCurrent) eleTreeNodeContent.addClass("eleTree-node-content-active"); + _self.prevClickEle=eleTreeNodeContent; + + if(!inp) return; + + if(inp.checked){ + // 反选自身 + $(inp).prop("checked",false).attr("eleTree-status","0").removeAttr("data-checked"); + // 点击祖父层选中子孙层 + if(!options.checkStrictly){ + childNode.prop("checked",false).attr("eleTree-status","0").removeAttr("data-checked"); + } + + }else{ + // 反选自身 + $(inp).prop("checked",true).attr("eleTree-status","1"); + // 点击祖父层选中子孙层 + if(!options.checkStrictly){ + childNode.prop("checked",true).attr("eleTree-status","1"); + } + } + + var eleNode=eleTreeNodeContent.parent(".eleTree-node"); + // 点击子孙层选中祖父层(递归) + if(!options.checkStrictly){ + var siblingNode=eleNode.siblings(".eleTree-node"); + // 点击子孙层选中祖父层(递归) + _self.selectParents(inp,eleNode,siblingNode); + } + + _self.checkboxRender(); + + layui.event.call(inp, MOD_NAME, 'nodeChecked('+ _self.filter +')', { + node: eleNode, + data: _self.reInitData(eleNode), + isChecked: inp.checked + }); + }) + }, + // 对后台数据有 checked:true 的默认选中项渲染父子层 + checkboxInit: function() { + var options=this.config; + var _self=this; + options.elem.find("input[data-checked]").each(function(index,item) { + var checkboxEl=$(item).siblings(".eleTree-checkbox"); + var childNode=checkboxEl.parent(".eleTree-node-content").siblings(".eleTree-node-group").find("input[name='eleTree-node']"); + // 选择当前 + $(item).prop("checked","checked").attr("eleTree-status","1"); + checkboxEl.addClass("eleTree-checkbox-checked"); + checkboxEl.children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line"); + if(options.checkStrictly) return; + // 选择子孙 + childNode.prop("checked","checked").attr("eleTree-status","1"); + childNode.siblings(".eleTree-checkbox").addClass("eleTree-checkbox-checked"); + childNode.siblings(".eleTree-checkbox").children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line"); + + // 选择祖父 + var eleNode=checkboxEl.parent(".eleTree-node-content").parent(".eleTree-node"); + var siblingNode=eleNode.siblings(".eleTree-node"); + _self.selectParents(item,eleNode,siblingNode); + }) + _self.checkboxRender(); + }, + // 通过子元素选中祖父元素 + selectParents: function(inp,eleNode,siblingNode) { + // inp: 实际input(dom元素) + // eleNode: input父层类(.eleTree-node) + // siblingNode: 父层同级兄弟 + while (Number(eleNode.attr("eletree-floor"))!==0) { + // 同级input状态存入数组 + var arr=[]; + arr.push($(inp).attr("eleTree-status")); + siblingNode.each(function(index,item) { + var siblingIsChecked=$(item).children(".eleTree-node-content").children("input[name='eleTree-node']").attr("eleTree-status"); + arr.push(siblingIsChecked); + }) + // 父元素的实际input + var parentInput=eleNode.parent(".eleTree-node-group").siblings(".eleTree-node-content").children("input[name='eleTree-node']"); + // 父元素的checkbox替代 + var parentCheckbox=parentInput.siblings(".eleTree-checkbox"); + // 子都选中则选中父 + if(arr.every(function(val) { + return val==="1"; + })){ + parentInput.prop("checked",true).attr("eleTree-status","1"); + } + // 子有一个未选中则checkbox第三种状态 + if(arr.some(function(val) { + return val==="0" || val==="2"; + })){ + parentInput.attr("eleTree-status","2"); + } + // 子全部未选中则取消父选中(并且取消第三种状态) + if(arr.every(function(val) { + return val==="0"; + })){ + parentInput.prop("checked",false); + parentInput.attr("eleTree-status","0"); + } + + var parentNode=eleNode.parents("[eletree-floor='"+(Number(eleNode.attr("eletree-floor"))-1)+"']"); + var parentCheckbox=parentNode.children(".eleTree-node-content").children("input[name='eleTree-node']").get(0); + var parentSiblingNode=parentNode.siblings(".eleTree-node"); + eleNode=parentNode; + inp=parentCheckbox; + siblingNode=parentSiblingNode; + } + }, + // 初始展开所有 + initialExpandAll: function(data,arr,floor,isMethodsExpandAll) { + var options=this.config; + var _self=this; + this.isRenderAllDom=true; + data.forEach(function(val,index) { + arr.push(index); + if(val[options.request.children] && val[options.request.children].length>0){ + var el=options.elem.children(".eleTree-node").eq(arr[0]).children(".eleTree-node-group"); + for(var i=1;i0) { + // 继续展开祖父层 + var f=function(eleP) { + if(options.autoExpandParent){ + eleP.parents(".eleTree-node").each(function(i,item) { + if($(item).data(options.request.key)){ + $(item).children(".eleTree-node-group").show().siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").addClass("icon-rotate"); + } + }) + } + } + // 展开指定id项 + var id=el.parent(".eleTree-node").data(options.request.key); + if($.inArray(id,options.defaultExpandedKeys)!==-1){ + // 直接展开子节点 + el.show().siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").addClass("icon-rotate"); + // 展开子项是否继续展开祖父项 + f(el.parent(".eleTree-node[data-"+options.customKey+"]")); + }else{ + // 如当前节点的子节点有展开项,则展开当前子节点的祖父层 + el.children(".eleTree-node").each(function(index, item) { + var id=$(item).data(options.request.key); + if($.inArray(id,options.defaultExpandedKeys)!==-1){ + f($(item)); + return false; + } + }) + } + } + }); + floor++; + _self.initialExpandAll(val[options.request.children],arr,floor,isMethodsExpandAll); + floor--; + } + // 重置数组索引 + arr.pop(); + }) + }, + // 选中单个节点 + checkedOneNode: function(nodeContent){ + var options=this.config; + var inp=nodeContent.children("input.eleTree-hideen").get(0); + $(inp).prop("checked",true).attr("eleTree-status","1"); + + if(options.checkStrictly) return; + + // 点击祖父层选中子孙层 + var childNode=nodeContent.siblings(".eleTree-node-group").find("input[name='eleTree-node']"); + childNode.prop("checked",true).attr("eleTree-status","1"); + + var eleNode=nodeContent.parent(".eleTree-node"); + var siblingNode=eleNode.siblings(".eleTree-node"); + // 点击子孙层选中祖父层(递归) + this.selectParents(inp,eleNode,siblingNode); + }, + // 初始默认选中 + defaultChecked: function(dataChecked) { + var options=this.config; + var _self=this; + var arr=dataChecked || options.defaultCheckedKeys; + if(arr.length===0){ + return false; + } + arr.forEach(function(val,index) { + var nodeContent=options.elem.find("[data-"+options.customKey+"='"+val+"']").children(".eleTree-node-content"); + nodeContent.length>0 && _self.checkedOneNode(nodeContent); + }) + this.checkboxInit(); + }, + // 自定义checkbox解析 + checkboxRender: function() { + var options=this.config; + options.elem.find(".eleTree-checkbox").remove(); + options.elem.find("input.eleTree-hideen[type=checkbox]").each(function(index,item){ + if($(item).hasClass("eleTree-disabled")){ + $(item).after('
    '); + }else{ + $(item).after('
    '); + } + + var checkbox=$(item).siblings(".eleTree-checkbox"); + if($(item).attr("eletree-status")==="1"){ + checkbox.addClass("eleTree-checkbox-checked"); + checkbox.children("i").addClass("layui-icon-ok").removeClass("eleTree-checkbox-line"); + }else if($(item).attr("eletree-status")==="0"){ + checkbox.removeClass("eleTree-checkbox-checked"); + checkbox.children("i").removeClass("layui-icon-ok eleTree-checkbox-line"); + }else if($(item).attr("eletree-status")==="2"){ + checkbox.addClass("eleTree-checkbox-checked"); + checkbox.children("i").removeClass("layui-icon-ok").addClass("eleTree-checkbox-line"); + } + + }) + }, + // 通过dom节点找对应数据 + reInitData: function(node) { + var options=this.config; + var i=node.index(); + var floor=Number(node.attr("eletree-floor")); + var arr=[]; // 节点对应的index + while (floor>=0) { + arr.push(i); + floor=floor-1; + node=node.parents("[eletree-floor='"+floor+"']"); + i=node.index(); + } + arr=arr.reverse(); + var oData=this.config.data; + // 当前节点的父节点数据 + var parentData=oData[arr[0]]; + // 当前节点的data数据 + var d = oData[arr[0]]; + for(var j = 1; j0){ + fn(data[obj.i][options.request.children]); + } + }else{ + callback(data,obj); + } + } + } + fn(options.data); + }, + updateKeyChildren: function(key,data) { + var options=this.config; + var node=options.elem.find("[data-"+options.customKey+"='"+key+"']"); + var floor=Number(node.attr("eletree-floor"))+1; + var _self=this; + + this.keySearchToOpera(key,function(d,obj) { + // 数据更新 + d[obj.i][options.request.children]=data; + // dom更新 + node.length!==0 && laytpl(TPL_ELEM(options,floor)).render(data, function(string){ + $(node).children(".eleTree-node-group").empty().append(string); + options.defaultExpandAll && $(node).children(".eleTree-node-group").show(); + }); + _self.unCheckNodes(true); + _self.defaultChecked(); + }); + }, + updateKeySelf: function(key,data) { + var options=this.config; + var node=options.elem.find("[data-"+options.customKey+"='"+key+"']").children(".eleTree-node-content"); + var floor=Number(node.attr("eletree-floor"))+1; + data[options.request.name] && node.children(".eleTree-node-content-label").text(data[options.request.name]); + data[options.request.disabled] && node.children(".eleTree-hideen").addClass("eleTree-disabled") + .siblings(".eleTree-checkbox").addClass("eleTree-checkbox-disabled"); + // 数据更新 + var getData=this.keySearchToOpera(key,function(d,obj) { + data[options.request.key]=d[obj.i][options.request.key]; + data[options.request.children]=d[obj.i][options.request.children]; + d[obj.i]=$.extend({},d[obj.i],data); + console.log(options.data); + }); + }, + remove: function(key) { + var options=this.config; + var node=options.elem.find("[data-"+options.customKey+"='"+key+"']"); + var pElem=node.parent(".eleTree-node-group"); + // 数据删除 + this.keySearchToOpera(key,function(data,obj) { + data.splice(obj.i,1); + obj.i--; + obj.len--; + + node.length!==0 && options.elem.find("[data-"+options.customKey+"='"+key+"']").remove(); + if(pElem.children(".eleTree-node").length===0){ + pElem.siblings(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon").css("color", "transparent"); + } + }); + this.unCheckNodes(true); + this.defaultChecked(); + this.checkboxInit(); + }, + append: function(key,data) { + var options=this.config; + // 如果不传key,则直接添加到根节点 + if(typeof key==="object" && key!==null){ + data=key; + key=null; + } + if(key===null || key===""){ + options.data.push(data); + laytpl(TPL_ELEM(options,0,"0")).render([data], function(string){ + $(options.elem).append(string); + $(options.elem).children(".eleTree-node:last").show(); + }); + this.checkboxRender(); + return; + } + // 传key则添加到子节点 + var node=options.elem.find("[data-"+options.customKey+"='"+key+"']"); + var floor=Number(node.attr("eletree-floor"))+1; + // 数据更新 + this.keySearchToOpera(key,function(d,obj) { + if(d[obj.i][options.request.children]){ + d[obj.i][options.request.children].push(data); + }else{ + d[obj.i][options.request.children]=[data]; + } + var arr=d[obj.i][options.request.children]; + var icon=node.children(".eleTree-node-content").find(".eleTree-node-content-icon .layui-icon"); + // 添加之后长度为1,则原来没有三角,添加三角 + if(arr.length===1){ + icon.removeAttr("style"); + } + // 判断原来是否没有展开 + if(!icon.hasClass("icon-rotate")){ + var expandOnClickNode=options.expandOnClickNode?node.children(".eleTree-node-content"):node.children(".eleTree-node-content").children(".eleTree-node-content-icon"); + expandOnClickNode.trigger("click"); + } + // 判断节点是否已存在 + var isExist=false; + node.children(".eleTree-node-group").children(".eleTree-node").each(function(index,item){ + if(data[options.request.key]==$(item).data(options.request.key)){ + isExist=true; + } + }) + if(!isExist){ + var len=arr.length; + var eletreeStatus=node.children(".eleTree-node-content").children("input.eleTree-hideen").attr("eletree-status"); + eletreeStatus=eletreeStatus==="2" ? "0" : eletreeStatus; + node.length!==0 && laytpl(TPL_ELEM(options,floor,eletreeStatus)).render([arr[len-1]], function(string){ + node.children(".eleTree-node-group").append(string).show(); + }); + } + + }); + this.checkboxRender(); + }, + insertBefore: function(key,data) { + var options=this.config; + var node=options.elem.find("[data-"+options.customKey+"='"+key+"']"); + var floor=Number(node.attr("eletree-floor")); + // 数据更新 + this.keySearchToOpera(key,function(d,obj) { + d.splice(obj.i,0,data); + obj.i++; + obj.len++; + var eletreeStatus=node.parent(".eleTree-node-group").length===0 ? "0" : node.parent(".eleTree-node-group").parent(".eleTree-node") + .children(".eleTree-node-content").children("input.eleTree-hideen").attr("eletree-status"); + eletreeStatus=eletreeStatus==="2" ? "0" : eletreeStatus; + node.length!==0 && laytpl(TPL_ELEM(options,floor,eletreeStatus)).render([data], function(string){ + node.before(string).prev(".eleTree-node"); + }); + }); + this.checkboxRender(); + }, + insertAfter: function(key,data) { + var options=this.config; + var node=options.elem.find("[data-"+options.customKey+"='"+key+"']"); + var floor=Number(node.attr("eletree-floor")); + // 数据更新 + this.keySearchToOpera(key,function(d,obj) { + d.splice(obj.i+1,0,data); + obj.i++; + obj.len++; + var eletreeStatus=node.parent(".eleTree-node-group").length===0 ? "0" : node.parent(".eleTree-node-group").parent(".eleTree-node") + .children(".eleTree-node-content").children("input.eleTree-hideen").attr("eletree-status"); + eletreeStatus=eletreeStatus==="2" ? "0" : eletreeStatus; + node.length!==0 && laytpl(TPL_ELEM(options,floor,eletreeStatus)).render([data], function(string){ + $(node).after(string).next(".eleTree-node"); + }); + }); + this.checkboxRender(); + // if(!options.lazy){ + // if(!options.renderAfterExpand || options.defaultExpandAll || options.defaultExpandedKeys.length>0){ + // this.initialExpandAll(options.data,[],1); + // } + // } + }, + getChecked: function(leafOnly, includeHalfChecked) { + var options=this.config + ,el + ,arr=[]; + leafOnly=leafOnly || false; + includeHalfChecked=includeHalfChecked || false; + if(leafOnly){ + el=options.elem.find(".layui-icon.leaf-icon").parent(".eleTree-node-content-icon") + .siblings("input.eleTree-hideen[eletree-status='1']"); + }else if(includeHalfChecked){ + el=options.elem.find("input.eleTree-hideen[eletree-status='1'],input.eleTree-hideen[eletree-status='2']"); + }else{ + el=options.elem.find("input.eleTree-hideen[eletree-status='1']"); + } + el.each(function(index,item) { + var obj={}; + var id=$(item).parent(".eleTree-node-content").parent(".eleTree-node").data(options.request.key); + var label=$(item).siblings(".eleTree-node-content-label").text(); + obj[options.request.key]=id; + obj[options.request.name]=label; + obj.elem=item; + obj.othis=$(item).siblings(".eleTree-checkbox").get(0) + arr.push(obj); + }) + return arr; + }, + setChecked: function(arr,isReset) { + var options=this.config; + isReset=isReset || false; + if(isReset){ + this.unCheckNodes(); + options.defaultCheckedKeys=$.extend([],arr); + }else{ + this.unCheckNodes(true); + arr.forEach(function(val) { + if($.inArray(val,options.defaultCheckedKeys)===-1){ + options.defaultCheckedKeys.push(val); + } + }) + } + this.defaultChecked(); + }, + unCheckNodes: function(_internal) { + _internal=_internal || false; // _internal: 是否内部调用 + var options=this.config; + options.elem.find("input.eleTree-hideen[eletree-status='1'],input.eleTree-hideen[eletree-status='2']").each(function(index,item) { + $(item).attr("eletree-status","0").prop("checked",false); + // 如果外部的取消选中,则所有的记录全部取消 + if(!_internal){ + $(item).removeAttr("data-checked"); + } + }); + this.checkboxRender(); + }, + unCheckArrNodes: function(arr) { + var options=this.config; + var dataChecked=[]; + options.elem.find(".eleTree-hideen[eletree-status='1']").each(function(index,item) { + var id=$(item).parent(".eleTree-node-content").parent(".eleTree-node").data(options.request.key); + // 获取所有被选中项,并去除arr中包含的数据 + if(arr.some(function(val) { + return val==id; + })){ + // 如果id在arr数组中,则清除dom上面的checked数据 + $(item).removeAttr("data-checked"); + return; + } + dataChecked.push(id); + }) + + // 更新defaultCheckedKeys数据 + for(var j=0;j.layui-icon").addClass("icon-rotate") + .parent(".eleTree-node-content-icon").parent(".eleTree-node-content") + .siblings(".eleTree-node-group").show(); + } + options.elem.children(".eleTree-node").children(".eleTree-node-group").empty(); + this.initialExpandAll(options.data,[],1,true); + this.unCheckNodes(true); + this.defaultChecked(); + this.checkboxInit(); + }, + // 展开某节点的所有子节点 + expandNode: function(key) { + var options=this.config; + var parentsEl=options.elem.find("[data-"+options.customKey+"='"+key+"']"); + var isExpand=parentsEl.children(".eleTree-node-content").find(".eleTree-node-content-icon>.layui-icon.layui-icon-triangle-r").hasClass("icon-rotate"); + var parentGroup=parentsEl.find(".eleTree-node-group"); + // 判断是否已经展开 + if(isExpand) return false; + // 判断子节点是否已经渲染(目前只判断所有子节点是否已经全部渲染,而不是当前子节点是否全部渲染) + if(this.isRenderAllDom){ + parentGroup.show("fast"); + parentsEl.find(".layui-icon.layui-icon-triangle-r").addClass("icon-rotate"); + return false; + } + if(options.lazy) return hint.error("展开所有子节点方法暂不支持懒加载"); + + var data=this.reInitData(parentsEl); + var d=data.currentData; + var floor=Number(parentsEl.attr("eletree-floor"))+1; + var fn=function(data,arr,floor) { + data.forEach(function(val,index) { + arr.push(index); + if(val[options.request.children] && val[options.request.children].length>0){ + var el=parentsEl.children(".eleTree-node-group"); + for(var i=1;i.layui-icon.layui-icon-triangle-r").hasClass("icon-rotate"); + // 判断是否已经合并 + if(!isExpand) return false; + parentsEl.find(".eleTree-node-group").hide("fast"); + parentsEl.find(".layui-icon.layui-icon-triangle-r").removeClass("icon-rotate"); + }, + // 切换某节点的所有子节点的展开合并状态 + toggleExpandNode: function(key) { + var options=this.config; + var parentsEl=options.elem.find("[data-"+options.customKey+"='"+key+"']"); + var isExpand=parentsEl.children(".eleTree-node-content").find(".eleTree-node-content-icon>.layui-icon.layui-icon-triangle-r").hasClass("icon-rotate"); + if(isExpand){ + this.unExpandNode(key); + }else{ + this.expandNode(key); + } + }, + // 节点事件 + nodeEvent: function() { + var _self=this; + var options=this.config; + // 节点被点击的回调事件 + options.elem.on("click",".eleTree-node-content",function(e) { + var eleNode=$(this).parent(".eleTree-node"); + var eleTreeNodeContent=eleNode.children(".eleTree-node-content"); + // 添加active背景 + if(_self.prevClickEle) _self.prevClickEle.removeClass("eleTree-node-content-active"); + if(options.highlightCurrent) eleTreeNodeContent.addClass("eleTree-node-content-active"); + _self.prevClickEle=eleTreeNodeContent; + + $("#tree-menu").hide().remove(); + layui.event.call(eleNode, MOD_NAME, 'nodeClick('+ _self.filter +')', { + node: eleNode, + data: _self.reInitData(eleNode), + event: e + }); + }) + // 节点右键的回调事件 + options.elem.on("contextmenu",".eleTree-node-content",function(e) { + var eleNode=$(this).parent(".eleTree-node"); + layui.event.call(eleNode, MOD_NAME, 'nodeContextmenu('+ _self.filter +')', { + node: eleNode, + data: _self.reInitData(eleNode), + event: e + }); + }) + // 节点被拖拽的回调事件 + options.draggable && options.elem.on("mousedown",".eleTree-node-content",function(e) { + var time=0; + var eleNode=$(this).parent(".eleTree-node"); + var eleFloor=Number(eleNode.attr("eletree-floor")); + var groupNode=eleNode.parent(".eleTree-node-group"); + + e.stopPropagation(); + options.elem.css("user-select","none"); + var cloneNode=eleNode.clone(true); + var temNode=eleNode.clone(true); + + var x=e.clientX-options.elem.offset().left; + var y=e.clientY-options.elem.offset().top; + options.elem.append(cloneNode); + cloneNode.css({ + "display": "none", + "opacity": 0.7, + "position": "absolute", + "background-color": "#f5f5f5", + "width": "100%" + }) + + var currentData=_self.reInitData(eleNode); + + var isStop=false; + + $(document).on("mousemove",function(e) { + // t为了区别click事件 + time++; + if(time>2){ + var xx=e.clientX-options.elem.offset().left+10; + var yy=e.clientY-options.elem.offset().top+$(document).scrollTop()-5; // 加上浏览器滚动高度 + + cloneNode.css({ + display: "block", + left: xx+"px", + top: yy+"px" + }) + } + }).on("mouseup",function(e) { + $(document).off("mousemove").off("mouseup"); + var target=$(e.target).parents(".eleTree-node").eq(0); + cloneNode.remove(); + options.elem.css("user-select","auto"); + + + // 当前点击的是否时最外层 + var isCurrentOuterMost=eleNode.parent().get(0).isEqualNode(options.elem.get(0)) + // 目标是否时最外层 + var isTargetOuterMost=$(e.target).get(0).isEqualNode(options.elem.get(0)) + if(isTargetOuterMost){ + target=options.elem; + } + // 判断是否超出边界 + if(target.parents(options.elem).length===0 && !isTargetOuterMost){ + return; + } + // 判断初始与结束是否是同一个节点 + if(target.get(0).isEqualNode(eleNode.get(0))){ + return; + } + // 判断是否是父节点放到子节点 + var tFloor=target.attr("eletree-floor"); + var isInChild=false; + eleNode.find("[eletree-floor='"+tFloor+"']").each(function() { + if(this.isEqualNode(target.get(0))){ + isInChild=true; + } + }) + if(isInChild){ + return; + } + + var targetData=_self.reInitData(target); + layui.event.call(target, MOD_NAME, 'nodeDrag('+ _self.filter +')', { + current: { + node: eleNode, + data: currentData + }, + target: { + node: target, + data: targetData + }, + stop: function() { + isStop=true; + } + }); + // 拖拽是否取消 + if(isStop){ + return false; + } + + // 数据更改 + var currList=currentData.parentData.data[options.request.children] + var currIndex=currentData.parentData.childIndex + var currData=currentData.currentData; + var tarData=targetData.currentData; + // 当前是否是最外层 + isCurrentOuterMost ? options.data.splice(currIndex,1) : currList.splice(currIndex,1) + // 目标是否是最外层 + isTargetOuterMost ? options.data.push(currData) : (function() { + !tarData[options.request.children] ? tarData[options.request.children]=[] : ""; + tarData[options.request.children].push(currData); + })() + + // dom互换 + eleNode.remove(); + var floor=null; + // 最外层判断 + if(isTargetOuterMost){ + target.append(temNode); + floor=0; + }else{ + target.children(".eleTree-node-group").append(temNode); + floor=Number(target.attr("eletree-floor"))+1; + } + // 加floor和padding + temNode.attr("eletree-floor",String(floor)); + temNode.children(".eleTree-node-content").css("padding-left",floor*options.indent+"px"); + // 计算线条的left + if(options.showLine){ + // 判断目标是否是最外层,是的话隐藏线条 + if(floor===0){ + temNode.children(".eleTree-node-verticalline,.eleTree-node-horizontalline").hide(); + }else{ + temNode.children(".eleTree-node-verticalline,.eleTree-node-horizontalline").css("left",options.indent*(floor-1)+9+"px").show(); + } + } + // 通过floor差值计算子元素的floor + var countFloor=eleFloor-floor; + temNode.find(".eleTree-node").each(function(index,item) { + var f=Number($(item).attr("eletree-floor"))-countFloor; + $(item).attr("eletree-floor",String(f)); + $(item).children(".eleTree-node-content").css("padding-left",f*options.indent+"px"); + options.showLine && $(item).children(".eleTree-node-verticalline,.eleTree-node-horizontalline").css("left",options.indent*(f-1)+9+"px").show(); + }) + // 原dom去三角 + var leaf=groupNode.children(".eleTree-node").length===0; + leaf && groupNode.siblings(".eleTree-node-content") + .children(".eleTree-node-content-icon").children(".layui-icon") + .removeClass("icon-rotate").css("color","transparent"); + // 当前的增加三角 + var cLeaf=target.children(".eleTree-node-group").children(".eleTree-node").length===1; + cLeaf && target.children(".eleTree-node-content") + .children(".eleTree-node-content-icon").children(".layui-icon") + .addClass("icon-rotate").removeAttr("style"); + // 判断当前是否需要显示 + var isShowNode=target.children(".eleTree-node-content").find(".layui-icon").hasClass("icon-rotate"); + (isTargetOuterMost || isShowNode) && target.children(".eleTree-node-group").show(); + + _self.unCheckNodes(true); + _self.defaultChecked(); + _self.checkboxInit(); + }) + }) + }, + rightClickMenu: function() { + var _self=this; + var options=this.config; + if(options.contextmenuList.length<=0){ + return; + } + $(document).on("click",function() { + $("#tree-menu").hide().remove(); + }); + + var customizeMenu=[]; // 用户自定义的 + var internalMenu=["copy","add","add.async","insertBefore","insertAfter","append","edit","edit.async","remove","remove.async"]; // 系统自带的 + var customizeStr=''; + options.contextmenuList.forEach(function(val) { + if($.inArray(val,internalMenu)===-1){ + customizeMenu.push(val); + customizeStr+='
  • '+(val.text || val)+'
  • '; + } + }) + var menuStr=['
      ' + ,$.inArray("copy",options.contextmenuList)!==-1?'
    • 复制
    • ':'' + ,($.inArray("add",options.contextmenuList)!==-1 || $.inArray("add.async",options.contextmenuList)!==-1)?'
    • 新增
    • '+ + '
    • 插入节点前
    • '+ + '
    • 插入节点后
    • '+ + '
    • 插入子节点
    • ' : "" + ,($.inArray("edit",options.contextmenuList)!==-1 || $.inArray("edit.async",options.contextmenuList)!==-1)?'
    • 修改
    • ':'' + ,($.inArray("remove",options.contextmenuList)!==-1 || $.inArray("remove.async",options.contextmenuList)!==-1)?'
    • 删除
    • ':'' + ,customizeStr + ,'
    '].join(""); + this.treeMenu=$(menuStr); + options.elem.off("contextmenu").on("contextmenu",".eleTree-node-content",function(e) { + var that=this; + e.stopPropagation(); + e.preventDefault(); + // 添加active背景 + if(_self.prevClickEle) _self.prevClickEle.removeClass("eleTree-node-content-active"); + $(this).addClass("eleTree-node-content-active"); + var eleNode=$(this).parent(".eleTree-node"); + var nodeData=_self.reInitData(eleNode); + + // 菜单位置 + $(document.body).after(_self.treeMenu); + $("#tree-menu").find("li.append,li.insertAfter,li.insertBefore").hide(); + $("#tree-menu").find(":not(li.append,li.insertAfter,li.insertBefore)").show(); + $("#tree-menu").css({ + left: e.clientX+$(document).scrollLeft(), + top: e.clientY+$(document).scrollTop() + }).show(); + // 复制 + $("#tree-menu li.copy").off().on("click",function() { + var el = $(that).children(".eleTree-node-content-label").get(0); + var selection = window.getSelection(); + var range = document.createRange(); + range.selectNodeContents(el); + selection.removeAllRanges(); + selection.addRange(range); + document.execCommand('Copy', 'false', null); + selection.removeAllRanges(); + }); + // 新增 + $("#tree-menu li.add").off().on("click",function(e) { + e.stopPropagation(); + $(this).hide().siblings("li:not(.append,.insertAfter,.insertBefore)").hide(); + $(this).siblings(".append,li.insertAfter,li.insertBefore").show(); + }) + // 添加的默认数据 + var obj={}; + obj[options.request.key]=Date.now(); + obj[options.request.name]="未命名"+_self.nameIndex; + if(options.lazy){ + obj[options.request.isLeaf]=true; + } + + var arr=["Append","InsertBefore","InsertAfter"]; + arr.forEach(function(val) { + var s=val[0].toLocaleLowerCase()+val.slice(1,val.length); + $("#tree-menu li."+s).off().on("click",function(e) { + var node=$(that).parent(".eleTree-node"); + var key=node.data(options.request.key); + var isStop=false; + var s=val[0].toLocaleLowerCase()+val.slice(1,val.length); + // 每次只能添加一条数据,不可以批量添加 + _self[s](key,obj); + var nodeArr=[]; + node.children(".eleTree-node-group").children(".eleTree-node").each(function(i,itemNode) { + nodeArr.push(itemNode); + }) + node.siblings(".eleTree-node").each(function(i,itemNode) { + nodeArr.push(itemNode); + }) + $.each(nodeArr, function(i,itemNode) { + if(obj[options.request.key]===$(itemNode).data(options.request.key)){ + var label=$(itemNode).children(".eleTree-node-content").children(".eleTree-node-content-label").hide(); + var text=label.text(); + var inp=""; + label.after(inp); + + label.siblings(".eleTree-node-content-input").focus().select().off().on("blur",function() { + var v=$(this).val(); + obj[options.request.name]=v; + var inpThis=this; + + layui.event.call(node, MOD_NAME, 'node'+val+'('+ _self.filter +')', { + node: node, + data: nodeData.currentData, + newData: obj, + // 重新设置数据 + setData: function(o) { + // obj[options.request.key]=Date.now(); + obj[options.request.name]=v; + if(options.lazy){ + obj[options.request.isLeaf]=true; + } + var newObj=$.extend({},obj,o); + this.newData=newObj; + // 修改数据 + var d=_self.reInitData($(itemNode)).currentData; + d[options.request.name]=newObj[options.request.name]; + d[options.request.key]=newObj[options.request.key]; + // 修改dom + $(inpThis).siblings(".eleTree-node-content-label").text(newObj[options.request.name]).show(); + $(itemNode).attr("data-"+options.customKey,newObj[options.request.key]); // 改变页面上面的显示的key,之后可以获取dom + $(itemNode).data(options.request.key,newObj[options.request.key]); // 改变data数据,之后可以通过data获取key + $(inpThis).remove(); + + _self.nameIndex++; + isStop=true; + }, + // 停止添加 + stop: function() { + isStop=true; + this.newData={}; + _self.remove(obj[options.request.key]); + } + }); + + // 不是异步添加 + if($.inArray("add.async",options.contextmenuList)===-1){ + if(isStop) return; + // 修改数据 + _self.reInitData($(itemNode)).currentData[options.request.name]=v; + // 修改dom + $(this).siblings(".eleTree-node-content-label").text(v).show(); + $(this).remove(); + + _self.nameIndex++; + } + }).on("mousedown",function(e) { + // 防止input拖拽 + e.stopPropagation(); + }).on("click",function(e) { + e.stopPropagation(); + }) + } + }) + }) + }) + + // 编辑 + $("#tree-menu li.edit").off().on("click",function(e) { + e.stopPropagation(); + $("#tree-menu").hide().remove(); + var node=$(that).parent(".eleTree-node"); + var key=node.data(options.request.key); + var label=$(that).children(".eleTree-node-content-label").hide(); + var text=label.text(); + var inp=""; + label.after(inp); + label.siblings(".eleTree-node-content-input").focus().select().off().on("blur",function() { + var val=$(this).val(); + var isStop=false; + var inpThis=this; + layui.event.call(node, MOD_NAME, 'nodeEdit('+ _self.filter +')', { + node: node, + value: val, + data: nodeData.currentData, + // 停止添加 + stop: function() { + isStop=true; + $(inpThis).siblings(".eleTree-node-content-label").show(); + $(inpThis).remove(); + }, + async: function() { + if(isStop) return; + // 修改数据 + _self.reInitData(eleNode).currentData[options.request.name]=val; + // 修改dom + $(inpThis).siblings(".eleTree-node-content-label").text(val).show(); + $(inpThis).remove(); + } + }); + // 不是异步 + if($.inArray("edit.async",options.contextmenuList)===-1){ + if(isStop) return; + // 修改数据 + _self.reInitData(eleNode).currentData[options.request.name]=val; + // 修改dom + $(this).siblings(".eleTree-node-content-label").text(val).show(); + $(this).remove(); + } + + }).on("mousedown",function(e) { + // 防止input拖拽 + e.stopPropagation(); + }) + }) + // 删除 + $("#tree-menu li.remove").off().on("click",function(e) { + var node=$(that).parent(".eleTree-node"); + var key=node.data(options.request.key); + var isStop=false; + layui.event.call(node, MOD_NAME, 'nodeRemove('+ _self.filter +')', { + node: node, + data: nodeData.currentData, + // 停止添加 + stop: function() { + isStop=true; + return this; + }, + async: function() { + if(isStop) return; + _self.remove(key); + return this; + } + }); + // 不是异步 + if($.inArray("remove.async",options.contextmenuList)===-1){ + if(isStop) return; + _self.remove(key); + } + + }) + + // 自定义菜单回调 + customizeMenu.forEach(function(val) { + var text=val.eventName || val; + $("#tree-menu li."+text).off().on("click",function() { + var node=$(that).parent(".eleTree-node"); + var isStop=false; + layui.event.call(node, MOD_NAME, 'node'+text.replace(text.charAt(0),text.charAt(0).toUpperCase())+'('+ _self.filter +')', { + node: node, + data: nodeData.currentData, + }); + }); + }) + + _self.prevClickEle=$(this); + }) + }, + search: function(value) { + var options=this.config; + if(!options.searchNodeMethod || typeof options.searchNodeMethod !== "function"){ + return; + } + var data=options.data; + // 数据递归 + var traverse=function(data) { + data.forEach(function(val,index) { + // 所有查找到的节点增加属性 + val.visible=options.searchNodeMethod(value,val); + if(val[options.request.children] && val[options.request.children].length>0){ + traverse(val[options.request.children]); + } + //如果当前节点属性为隐藏,判断其子节点是否有显示的,如果有,则当前节点改为显示 + if(!val.visible){ + var childSomeShow = false; + if(val[options.request.children] && val[options.request.children].length>0){ + childSomeShow=val[options.request.children].some(function(v,i) { + return v.visible; + }) + } + val.visible = childSomeShow; + } + // 通过节点的属性,显示隐藏各个节点,并添加删除搜索类 + var el=options.elem.find("[data-"+options.customKey+"='"+val[options.request.key]+"']"); + if(val.visible){ + el.removeClass("eleTree-search-hide"); + // 判断父节点是否展开,如果父节点没有展开,则子节点也不要显示 + var parentEl=el.parent(".eleTree-node-group").parent(".eleTree-node"); + var isParentOpen=parentEl.children(".eleTree-node-content").children(".eleTree-node-content-icon").children(".layui-icon.layui-icon-triangle-r").hasClass("icon-rotate") + if((parentEl.length>0 && isParentOpen) || parentEl.length===0){ + el.show(); + } + }else{ + el.hide().addClass("eleTree-search-hide"); + } + // 删除子层属性 + // if(val[options.request.children] && val[options.request.children].length>0){ + // val[options.request.children].forEach(function(v,i) { + // delete v.visible; + // }) + // } + }) + } + traverse(data); + // 删除最外层属性 + var arr=data.map(function (val) { + var v=val.visible; + // delete val.visible; + return v; + }); + var isNotext=options.elem.children(".eleTree-noText"); + // 如果第一层的所有的都隐藏,则显示文本 + if(arr.every(function(v) { + return v===false; + })){ + if(isNotext.length===0){ + laytpl(TPL_NoText()).render(options, function(string){ + options.elem.append(string); + }); + } + }else{ + isNotext.remove(); + } + }, + getAllNodeData: function() { + var options=this.config; + return options.data; + } + } + + exports(MOD_NAME,eleTree); +}) diff --git a/docs/plugins/index.js b/docs/plugins/index.js index 75f3757..66d4452 100644 --- a/docs/plugins/index.js +++ b/docs/plugins/index.js @@ -1,2 +1,2 @@ -import './eleTree/eleTree.js' +import './eleTree/eleTree.js' import './eleTree/eleTree.css' \ No newline at end of file diff --git a/docs/router.js b/docs/router.js index 90cc639..e33795a 100644 --- a/docs/router.js +++ b/docs/router.js @@ -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'), + }, + +]; diff --git a/package.json b/package.json index 3a870c7..89707c3 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/common/expand.js b/src/common/expand.js similarity index 100% rename from src/components/common/expand.js rename to src/common/expand.js diff --git a/src/common/util.js b/src/common/util.js new file mode 100644 index 0000000..9cebf37 --- /dev/null +++ b/src/common/util.js @@ -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; +} diff --git a/src/components/common/util.js b/src/components/common/util.js deleted file mode 100644 index b0494c3..0000000 --- a/src/components/common/util.js +++ /dev/null @@ -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; -} diff --git a/src/components/config/language/en.js b/src/components/config/language/en.js deleted file mode 100644 index 3b53c39..0000000 --- a/src/components/config/language/en.js +++ /dev/null @@ -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', - } -} \ No newline at end of file diff --git a/src/components/config/language/zn.js b/src/components/config/language/zn.js deleted file mode 100644 index 45b6498..0000000 --- a/src/components/config/language/zn.js +++ /dev/null @@ -1,11 +0,0 @@ -export default { - tips: '请选择', - empty: '暂无数据', - searchTips: '请选择', - toolbar: { - ALL: '全选', - CLEAR: '清空', - REVERSE: '反选', - SEARCH: '搜索', - } -} \ No newline at end of file diff --git a/src/components/core/index.js b/src/components/core/index.js deleted file mode 100644 index 382829e..0000000 --- a/src/components/core/index.js +++ /dev/null @@ -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(, 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; diff --git a/src/components/element/framework.js b/src/components/element/framework.js deleted file mode 100644 index 236039f..0000000 --- a/src/components/element/framework.js +++ /dev/null @@ -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 = ( - item[prop.value]).join(',') }> - ) - - 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 ( - - { select } - - - - ); - } -} - -export default Framework; diff --git a/src/components/element/model/custom.js b/src/components/element/model/custom.js deleted file mode 100644 index 4aeff35..0000000 --- a/src/components/element/model/custom.js +++ /dev/null @@ -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 ( -
    -
    -
    -
    -
    - ) - } -} - -export default Custom; diff --git a/src/components/element/model/general.js b/src/components/element/model/general.js deleted file mode 100644 index f8c9b5e..0000000 --- a/src/components/element/model/general.js +++ /dev/null @@ -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 = ( - - ); - - //如果是分组模式, 要分页先去除分组, 然后在计算分页, 最后再加上分组 - 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) => ( - // { i + 1 } - // )) - // } - - this.state.pageIndex !== pageIndex && this.changePageIndex(pageIndex); - - paging = ( -
    - 上一页 - { this.state.pageIndex } / { size } - this.pageNextClick.bind(this, e, size)() }>下一页 -
    - ) - }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 = ( -
    - { 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 (
    { - isFunction(info.method) && info.method(safetyArr) - } } onMouseEnter={ hoverChange } onMouseLeave={ hoverChange }> - { config.toolbar.showIcon && } - { info.name } -
    ) - }).filter(a => a) } -
    - ) - - 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 ( -
    - { showIcon && } -
    -
    - ) - } - - const renderGroup = item => { - const isGroup = item[optgroup]; - if(isGroup){//分组模式 - return ( -
    -
    { item[name] }
    -
    - ) - } - return renderItem(item); - } - - arr = arr.map(renderGroup); - - if(!arr.length){ - //查看无数据情况下是否显示分页 - !config.pageEmptyShow && (paging = ''); - arr.push(
    { empty }
    ) - } - - return ( -
    -
    - { config.toolbar.show && toolbar } - { filterable && search } -
    { arr }
    - { config.paging && paging } -
    - { this.state.loading &&
    - -
    } -
    - ) - } -} - -export default General; diff --git a/src/components/element/tips.js b/src/components/element/tips.js deleted file mode 100644 index 2dfe518..0000000 --- a/src/components/element/tips.js +++ /dev/null @@ -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 ( -
    { tips }
    - ) - } -} - -export default Tips; \ No newline at end of file diff --git a/src/components/framework/index.js b/src/components/framework/index.js new file mode 100644 index 0000000..ab3296e --- /dev/null +++ b/src/components/framework/index.js @@ -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 ? : tree.show ? : ; + + + return ( + + item[prop.value]).join(',') }> + + { sels.length === 0 &&
    { config.tips }
    } +
    + ); + } + + //组件完成挂载 + 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; diff --git a/src/components/element/label.js b/src/components/label/index.js similarity index 56% rename from src/components/element/label.js rename to src/components/label/index.js index 5989de2..a48fbf6 100644 --- a/src/components/element/label.js +++ b/src/components/label/index.js @@ -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 ( -
    - { sel[name] } - { conf.showIcon && } -
    - ) - }) - - //剩余没显示的数据 - if(arr.length){ - html.push( -
    - + { arr.length } -
    - ) - } - }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 ( -
    -
    this.labelRef = ref }> - { innerHTML ? -
    : -
    { html }
    - } -
    -
    - ) - } -} - -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 ( +
    + { sel[name] } + { conf.showIcon && } +
    + ) + }) + + //剩余没显示的数据 + if(arr.length){ + html.push( +
    + + { arr.length } +
    + ) + } + }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 ( +
    +
    this.labelRef = ref }> + { innerHTML ? +
    : +
    { html }
    + } +
    +
    + ) + } +} + +export default Label; diff --git a/src/components/plugin/custom.js b/src/components/plugin/custom.js new file mode 100644 index 0000000..bda1134 --- /dev/null +++ b/src/components/plugin/custom.js @@ -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 ( +
    +
    +
    +
    +
    + ) + } +} + +export default Custom; diff --git a/src/components/plugin/general.js b/src/components/plugin/general.js new file mode 100644 index 0000000..74554e4 --- /dev/null +++ b/src/components/plugin/general.js @@ -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 = ( + + ); + + //如果是分组模式, 要分页先去除分组, 然后在计算分页, 最后再加上分组 + 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) => ( + // { i + 1 } + // )) + // } + + this.state.pageIndex !== pageIndex && this.changePageIndex(pageIndex); + + paging = ( +
    + 上一页 + { this.state.pageIndex } / { size } + this.pageNextClick.bind(this, e, size)() }>下一页 +
    + ) + }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 = ( +
    + { 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 (
    { + isFunction(info.method) && info.method(safetyArr) + } } onMouseEnter={ hoverChange } onMouseLeave={ hoverChange }> + { config.toolbar.showIcon && } + { info.name } +
    ) + }).filter(a => a) } +
    + ) + + 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 ( +
    + { showIcon && } +
    +
    + ) + } + + const renderGroup = item => { + const isGroup = item[optgroup]; + if(isGroup){//分组模式 + return ( +
    +
    { item[name] }
    +
    + ) + } + return renderItem(item); + } + + arr = arr.map(renderGroup); + + if(!arr.length){ + //查看无数据情况下是否显示分页 + !config.pageEmptyShow && (paging = ''); + arr.push(
    { empty }
    ) + } + + return ( +
    +
    + { config.toolbar.show && toolbar } + { filterable && search } +
    { arr }
    + { config.paging && paging } +
    + { this.state.loading &&
    + +
    } +
    + ) + } +} + +export default General; diff --git a/src/components/plugin/tree.js b/src/components/plugin/tree.js new file mode 100644 index 0000000..cfd6de4 --- /dev/null +++ b/src/components/plugin/tree.js @@ -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 ( +
    + { tree.showFolderIcon && } + { tree.showFolderIcon && tree.showLine && } + { showIcon && } +
    +
    + ) + } + + 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 ( +
    + { tree.showFolderIcon && tree.showLine && } + { renderItem(item, indent, expand) } + { expand &&
    { child.map(c => renderGroup(c, indent)) }
    } +
    + ) + } + return renderItem(item, indent, 0); + } + + let arr = data.map(item => renderGroup(item, 10 - tree.indent)); + + if(!arr.length){ + //查看无数据情况下是否显示分页 + arr.push(
    { empty }
    ) + } + + return ( +
    +
    { arr }
    +
    + ) + } +} + +export default Tree; diff --git a/src/components/preact/index.js b/src/components/preact/index.js deleted file mode 100644 index 392716d..0000000 --- a/src/components/preact/index.js +++ /dev/null @@ -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 -}; diff --git a/src/components/xm-select/index.js b/src/components/xm-select/index.js new file mode 100644 index 0000000..8e017ae --- /dev/null +++ b/src/components/xm-select/index.js @@ -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(, 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; diff --git a/src/config/language/en.js b/src/config/language/en.js new file mode 100644 index 0000000..df6e632 --- /dev/null +++ b/src/config/language/en.js @@ -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', + } +} \ No newline at end of file diff --git a/src/config/language/zn.js b/src/config/language/zn.js new file mode 100644 index 0000000..1267d03 --- /dev/null +++ b/src/config/language/zn.js @@ -0,0 +1,11 @@ +export default { + tips: '请选择', + empty: '暂无数据', + searchTips: '请选择', + toolbar: { + ALL: '全选', + CLEAR: '清空', + REVERSE: '反选', + SEARCH: '搜索', + } +} \ No newline at end of file diff --git a/src/components/config/options.js b/src/config/options.js similarity index 64% rename from src/components/config/options.js rename to src/config/options.js index 0f02323..16d3a6b 100644 --- a/src/components/config/options.js +++ b/src/config/options.js @@ -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 }){ + + } + } +} diff --git a/src/index.js b/src/index.js index e3d04d5..2b6d155 100644 --- a/src/index.js +++ b/src/index.js @@ -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; diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..d94e09b --- /dev/null +++ b/src/main.js @@ -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; diff --git a/src/style/iconfont.less b/src/style/iconfont.less index 0ba6f4e..c8a8012 100644 --- a/src/style/iconfont.less +++ b/src/style/iconfont.less @@ -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,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') format('woff'), + url('data:application/x-font-woff2;charset=utf-8;base64,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') 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"; +} \ No newline at end of file diff --git a/src/style/index.less b/src/style/index.less index 2c7763e..83879df 100644 --- a/src/style/index.less +++ b/src/style/index.less @@ -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; + } }